From: Junio C Hamano Date: Mon, 13 Nov 2017 05:44:59 +0000 (+0900) Subject: Merge branch 'jm/status-ignored-files-list' X-Git-Tag: v2.16.0-rc0~140 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/d8df70f2739af78cab6d7f9b942e890da6fbd01d?hp=-c Merge branch 'jm/status-ignored-files-list' The set of paths output from "git status --ignored" was tied closely with its "--untracked=" option, but now it can be controlled more flexibly. Most notably, a directory that is ignored because it is listed to be ignored in the ignore/exclude mechanism can be handled differently from a directory that ends up to be ignored only because all files in it are ignored. * jm/status-ignored-files-list: status: test ignored modes status: document options to show matching ignored files status: report matching ignored and normal untracked status: add option to show ignored files differently --- d8df70f2739af78cab6d7f9b942e890da6fbd01d diff --combined builtin/commit.c index 605ea8c0e9,98d84d0277..cfb78fcf68 --- a/builtin/commit.c +++ b/builtin/commit.c @@@ -118,7 -118,7 +118,7 @@@ static int edit_flag = -1; /* unspecifi static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship; static int config_commit_verbose = -1; /* unspecified */ static int no_post_rewrite, allow_empty_message; - static char *untracked_files_arg, *force_date, *ignore_submodule_arg; + static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg; static char *sign_commit; /* @@@ -139,7 -139,7 +139,7 @@@ static const char *cleanup_arg static enum commit_whence whence; static int sequencer_in_use; static int use_editor = 1, include_status = 1; - static int show_ignored_in_status, have_option_m; + static int have_option_m; static struct strbuf message = STRBUF_INIT; static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED; @@@ -355,7 -355,7 +355,7 @@@ static const char *prepare_index(int ar refresh_cache_or_die(refresh_flags); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to create temporary index")); old_index_env = getenv(INDEX_ENVIRONMENT); @@@ -374,7 -374,7 +374,7 @@@ if (update_main_cache_tree(WRITE_TREE_SILENT) == 0) { if (reopen_lock_file(&index_lock) < 0) die(_("unable to write index file")); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to update temporary index")); } else warning(_("Failed to update main cache tree")); @@@ -401,7 -401,7 +401,7 @@@ add_files_to_cache(also ? prefix : NULL, &pathspec, 0); refresh_cache_or_die(refresh_flags); update_main_cache_tree(WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new_index file")); commit_style = COMMIT_NORMAL; ret = get_lock_file_path(&index_lock); @@@ -474,7 -474,7 +474,7 @@@ add_remove_files(&partial); refresh_cache(REFRESH_QUIET); update_main_cache_tree(WRITE_TREE_SILENT); - if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &index_lock, 0)) die(_("unable to write new_index file")); hold_lock_file_for_update(&false_lock, @@@ -486,7 -486,7 +486,7 @@@ add_remove_files(&partial); refresh_cache(REFRESH_QUIET); - if (write_locked_index(&the_index, &false_lock, CLOSE_LOCK)) + if (write_locked_index(&the_index, &false_lock, 0)) die(_("unable to write temporary index file")); discard_cache(); @@@ -912,12 -912,11 +912,12 @@@ static int prepare_to_commit(const cha * submodules which were manually staged, which would * be really confusing. */ - int diff_flags = DIFF_OPT_OVERRIDE_SUBMODULE_CONFIG; + struct diff_flags flags = DIFF_FLAGS_INIT; + flags.override_submodule_config = 1; if (ignore_submodule_arg && !strcmp(ignore_submodule_arg, "all")) - diff_flags |= DIFF_OPT_IGNORE_SUBMODULES; - commitable = index_differs_from(parent, diff_flags, 1); + flags.ignore_submodules = 1; + commitable = index_differs_from(parent, &flags, 1); } } strbuf_release(&committer_ident); @@@ -1076,6 -1075,19 +1076,19 @@@ static const char *find_author_by_nickn die(_("--author '%s' is not 'Name ' and matches no existing author"), name); } + static void handle_ignored_arg(struct wt_status *s) + { + if (!ignored_arg) + ; /* default already initialized */ + else if (!strcmp(ignored_arg, "traditional")) + s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED; + else if (!strcmp(ignored_arg, "no")) + s->show_ignored_mode = SHOW_NO_IGNORED; + else if (!strcmp(ignored_arg, "matching")) + s->show_ignored_mode = SHOW_MATCHING_IGNORED; + else + die(_("Invalid ignored mode '%s'"), ignored_arg); + } static void handle_untracked_files_arg(struct wt_status *s) { @@@ -1364,8 -1376,10 +1377,10 @@@ int cmd_status(int argc, const char **a N_("mode"), N_("show untracked files, optional modes: all, normal, no. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, - OPT_BOOL(0, "ignored", &show_ignored_in_status, - N_("show ignored files")), + { OPTION_STRING, 0, "ignored", &ignored_arg, + N_("mode"), + N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"), + PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" }, { OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"), N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"), PARSE_OPT_OPTARG, NULL, (intptr_t)"all" }, @@@ -1384,8 -1398,12 +1399,12 @@@ finalize_deferred_config(&s); handle_untracked_files_arg(&s); - if (show_ignored_in_status) - s.show_ignored_files = 1; + handle_ignored_arg(&s); + + if (s.show_ignored_mode == SHOW_MATCHING_IGNORED && + s.show_untracked_files == SHOW_NO_UNTRACKED_FILES) + die(_("Unsupported combination of ignored and untracked-files arguments")); + parse_pathspec(&s.pathspec, 0, PATHSPEC_PREFER_FULL, prefix, argv); @@@ -1493,8 -1511,6 +1512,8 @@@ static void print_summary(const char *p diff_setup_done(&rev.diffopt); head = resolve_ref_unsafe("HEAD", 0, NULL, NULL); + if (!head) + die_errno(_("unable to resolve HEAD after creating commit")); if (!strcmp(head, "HEAD")) head = _("detached HEAD"); else @@@ -1791,9 -1807,9 +1810,9 @@@ int cmd_commit(int argc, const char **a transaction = ref_transaction_begin(&err); if (!transaction || - ref_transaction_update(transaction, "HEAD", oid.hash, + ref_transaction_update(transaction, "HEAD", &oid, current_head - ? current_head->object.oid.hash : null_sha1, + ? ¤t_head->object.oid : &null_oid, 0, sb.buf, &err) || ref_transaction_commit(transaction, &err)) { rollback_index_files(); diff --combined dir.c index fc2bdc79fc,20457724c0..047a950f55 --- a/dir.c +++ b/dir.c @@@ -1389,10 -1389,34 +1389,34 @@@ static enum path_treatment treat_direct case index_nonexistent: if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES) break; + if (exclude && + (dir->flags & DIR_SHOW_IGNORED_TOO) && + (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) { + + /* + * This is an excluded directory and we are + * showing ignored paths that match an exclude + * pattern. (e.g. show directory as ignored + * only if it matches an exclude pattern). + * This path will either be 'path_excluded` + * (if we are showing empty directories or if + * the directory is not empty), or will be + * 'path_none' (empty directory, and we are + * not showing empty directories). + */ + if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES)) + return path_excluded; + + if (read_directory_recursive(dir, istate, dirname, len, + untracked, 1, 1, pathspec) == path_excluded) + return path_excluded; + + return path_none; + } if (!(dir->flags & DIR_NO_GITLINKS)) { - unsigned char sha1[20]; - if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0) - return path_untracked; + struct object_id oid; + if (resolve_gitlink_ref(dirname, "HEAD", &oid) == 0) + return exclude ? path_excluded : path_untracked; } return path_recurse; } @@@ -1561,6 -1585,7 +1585,7 @@@ static enum path_treatment treat_one_pa { int exclude; int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case); + enum path_treatment path_treatment; if (dtype == DT_UNKNOWN) dtype = get_dtype(de, istate, path->buf, path->len); @@@ -1607,8 -1632,23 +1632,23 @@@ return path_none; case DT_DIR: strbuf_addch(path, '/'); - return treat_directory(dir, istate, untracked, path->buf, path->len, - baselen, exclude, pathspec); + path_treatment = treat_directory(dir, istate, untracked, + path->buf, path->len, + baselen, exclude, pathspec); + /* + * If 1) we only want to return directories that + * match an exclude pattern and 2) this directory does + * not match an exclude pattern but all of its + * contents are excluded, then indicate that we should + * recurse into this directory (instead of marking the + * directory itself as an ignored path). + */ + if (!exclude && + path_treatment == path_excluded && + (dir->flags & DIR_SHOW_IGNORED_TOO) && + (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) + return path_recurse; + return path_treatment; case DT_REG: case DT_LNK: return exclude ? path_excluded : path_untracked; @@@ -2279,10 -2319,10 +2319,10 @@@ static int remove_dir_recurse(struct st int ret = 0, original_len = path->len, len, kept_down = 0; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL); - unsigned char submodule_head[20]; + struct object_id submodule_head; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && - !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) { + !resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) { /* Do not descend and nuke a nested git work tree. */ if (kept_up) *kept_up = 1; diff --combined wt-status.c index ed3271c3f3,6760df6176..937a87bbd5 --- a/wt-status.c +++ b/wt-status.c @@@ -559,12 -559,12 +559,12 @@@ static void wt_status_collect_changes_w init_revisions(&rev, NULL); setup_revisions(0, NULL, &rev, NULL); rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK; - DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES); + rev.diffopt.flags.dirty_submodules = 1; rev.diffopt.ita_invisible_in_index = 1; if (!s->show_untracked_files) - DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES); + rev.diffopt.flags.ignore_untracked_in_submodules = 1; if (s->ignore_submodule_arg) { - DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); + rev.diffopt.flags.override_submodule_config = 1; handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); } rev.diffopt.format_callback = wt_status_collect_changed_cb; @@@ -583,7 -583,7 +583,7 @@@ static void wt_status_collect_changes_i opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference; setup_revisions(0, NULL, &rev, &opt); - DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG); + rev.diffopt.flags.override_submodule_config = 1; rev.diffopt.ita_invisible_in_index = 1; if (s->ignore_submodule_arg) { handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg); @@@ -658,10 -658,15 +658,15 @@@ static void wt_status_collect_untracked if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES) dir.flags |= DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; - if (s->show_ignored_files) + if (s->show_ignored_mode) { dir.flags |= DIR_SHOW_IGNORED_TOO; - else + + if (s->show_ignored_mode == SHOW_MATCHING_IGNORED) + dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING; + } else { dir.untracked = the_index.untracked; + } + setup_standard_excludes(&dir); fill_directory(&dir, &the_index, &s->pathspec); @@@ -949,7 -954,7 +954,7 @@@ static void wt_longstatus_print_verbose const char *c = color(WT_STATUS_HEADER, s); init_revisions(&rev, NULL); - DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV); + rev.diffopt.flags.allow_textconv = 1; rev.diffopt.ita_invisible_in_index = 1; memset(&opt, 0, sizeof(opt)); @@@ -1449,7 -1454,7 +1454,7 @@@ static void wt_status_get_detached_from return; } - if (dwim_ref(cb.buf.buf, cb.buf.len, oid.hash, &ref) == 1 && + if (dwim_ref(cb.buf.buf, cb.buf.len, &oid, &ref) == 1 && /* sha1 is a commit? match without further lookup */ (!oidcmp(&cb.noid, &oid) || /* perhaps sha1 is a tag, try to dereference to a commit */ @@@ -1619,7 -1624,7 +1624,7 @@@ static void wt_longstatus_print(struct } if (s->show_untracked_files) { wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add"); - if (s->show_ignored_files) + if (s->show_ignored_mode) wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f"); if (advice_status_u_option && 2000 < s->untracked_in_ms) { status_printf_ln(s, GIT_COLOR_NORMAL, "%s", ""); @@@ -2263,8 -2268,8 +2268,8 @@@ int has_unstaged_changes(int ignore_sub init_revisions(&rev_info, NULL); if (ignore_submodules) - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); + rev_info.diffopt.flags.ignore_submodules = 1; + rev_info.diffopt.flags.quick = 1; diff_setup_done(&rev_info.diffopt); result = run_diff_files(&rev_info, 0); return diff_result_code(&rev_info.diffopt, result); @@@ -2283,8 -2288,8 +2288,8 @@@ int has_uncommitted_changes(int ignore_ init_revisions(&rev_info, NULL); if (ignore_submodules) - DIFF_OPT_SET(&rev_info.diffopt, IGNORE_SUBMODULES); - DIFF_OPT_SET(&rev_info.diffopt, QUICK); + rev_info.diffopt.flags.ignore_submodules = 1; + rev_info.diffopt.flags.quick = 1; add_head_to_pending(&rev_info); diff_setup_done(&rev_info.diffopt); result = run_diff_index(&rev_info, 1); @@@ -2297,14 -2302,14 +2302,14 @@@ */ int require_clean_work_tree(const char *action, const char *hint, int ignore_submodules, int gently) { - struct lock_file *lock_file = xcalloc(1, sizeof(*lock_file)); + struct lock_file lock_file = LOCK_INIT; int err = 0, fd; - fd = hold_locked_index(lock_file, 0); + fd = hold_locked_index(&lock_file, 0); refresh_cache(REFRESH_QUIET); if (0 <= fd) - update_index_if_able(&the_index, lock_file); - rollback_lock_file(lock_file); + update_index_if_able(&the_index, &lock_file); + rollback_lock_file(&lock_file); if (has_unstaged_changes(ignore_submodules)) { /* TRANSLATORS: the action is e.g. "pull with rebase" */