From 20f7ee46387a6ef142fdbb581a82f4bbe9c7aec2 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 5 Mar 2019 23:33:55 +0100 Subject: [PATCH] built-in add -i: allow filtering the modified files list In `update` command of `git add -i`, we are primarily interested in the list of modified files that have worktree (i.e. unstaged) changes. The Perl script version of `git add -i` has a parameter of the `list_modified()` function for that matter. In C, we can be a lot more precise, using an `enum`. The C implementation of the filter also has an easier time to avoid unnecessary work, simply by using an adaptive order of the `diff-index` and `diff-files` calls, and then not adding unnecessary entries in the first place. Signed-off-by: Johannes Schindelin --- add-interactive.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/add-interactive.c b/add-interactive.c index c431c72e3f..37d6783d2e 100644 --- a/add-interactive.c +++ b/add-interactive.c @@ -268,6 +268,7 @@ struct collection_status { const char *reference; + unsigned skip_unseen:1; struct file_list *list; struct hashmap file_map; }; @@ -296,6 +297,8 @@ static void collect_changes_cb(struct diff_queue_struct *q, entry = hashmap_get_from_hash(&s->file_map, hash, name); if (entry) file_index = entry->index; + else if (s->skip_unseen) + continue; else { FLEX_ALLOC_STR(entry, pathname, name); hashmap_entry_init(entry, hash); @@ -315,13 +318,22 @@ static void collect_changes_cb(struct diff_queue_struct *q, } } -static int get_modified_files(struct repository *r, struct file_list *list, +enum modified_files_filter { + NO_FILTER = 0, + WORKTREE_ONLY = 1, + INDEX_ONLY = 2, +}; + +static int get_modified_files(struct repository *r, + enum modified_files_filter filter, + struct file_list *list, const struct pathspec *ps) { struct object_id head_oid; int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL); struct collection_status s = { FROM_WORKTREE }; + int i; if (repo_read_index_preload(r, ps, 0) < 0) return error(_("could not read index")); @@ -329,10 +341,16 @@ static int get_modified_files(struct repository *r, struct file_list *list, s.list = list; hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0); - for (s.phase = FROM_WORKTREE; s.phase <= FROM_INDEX; s.phase++) { + for (i = 0; i < 2; i++) { struct rev_info rev; struct setup_revision_opt opt = { 0 }; + if (filter == INDEX_ONLY) + s.phase = i ? FROM_WORKTREE : FROM_INDEX; + else + s.phase = i ? FROM_INDEX : FROM_WORKTREE; + s.skip_unseen = filter && i; + opt.def = is_initial ? empty_tree_oid_hex() : oid_to_hex(&head_oid); @@ -418,7 +436,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps, { reset_file_list(files); - if (get_modified_files(s->r, files, ps) < 0) + if (get_modified_files(s->r, 0, files, ps) < 0) return -1; if (files->nr)