Skip to content

Commit

Permalink
built-in add -i: allow filtering the modified files list
Browse files Browse the repository at this point in the history
In the `update` command of `git add -i`, we are primarily interested in the
list of modified files that have worktree (i.e. unstaged) changes.

At the same time, we need to determine _also_ the staged changes, to be
able to produce the full added/deleted information.

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` phases, and then skipping files in the second phase
when they have not been seen in the first phase.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
dscho authored and gitster committed Nov 18, 2019
1 parent 8c15904 commit a5ced6d
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions add-interactive.c
Expand Up @@ -348,6 +348,7 @@ struct collection_status {

const char *reference;

unsigned skip_unseen:1;
struct string_list *files;
struct hashmap file_map;
};
Expand Down Expand Up @@ -375,6 +376,9 @@ static void collect_changes_cb(struct diff_queue_struct *q,
entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
struct pathname_entry, ent);
if (!entry) {
if (s->skip_unseen)
continue;

add_file_item(s->files, name);

entry = xcalloc(sizeof(*entry), 1);
Expand All @@ -396,13 +400,22 @@ static void collect_changes_cb(struct diff_queue_struct *q,
free_diffstat_info(&stat);
}

static int get_modified_files(struct repository *r, struct string_list *files,
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 string_list *files,
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 (discard_index(r->index) < 0 ||
repo_read_index_preload(r, ps, 0) < 0)
Expand All @@ -412,10 +425,16 @@ static int get_modified_files(struct repository *r, struct string_list *files,
s.files = files;
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);

Expand Down Expand Up @@ -499,7 +518,7 @@ static void print_file_item(int i, struct string_list_item *item,
static int run_status(struct add_i_state *s, const struct pathspec *ps,
struct string_list *files, struct list_options *opts)
{
if (get_modified_files(s->r, files, ps) < 0)
if (get_modified_files(s->r, NO_FILTER, files, ps) < 0)
return -1;

list(s, files, opts);
Expand Down

0 comments on commit a5ced6d

Please sign in to comment.