Skip to content

Commit 1844c4d

Browse files
committed
built-in add -i: allow filtering the modified files list
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 <[email protected]>
1 parent 2b5d5c1 commit 1844c4d

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

add-interactive.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ struct collection_status {
347347

348348
const char *reference;
349349

350+
unsigned skip_unseen:1;
350351
struct string_list *files;
351352
struct hashmap file_map;
352353
};
@@ -374,6 +375,9 @@ static void collect_changes_cb(struct diff_queue_struct *q,
374375
entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
375376
struct pathname_entry, ent);
376377
if (!entry) {
378+
if (s->skip_unseen)
379+
continue;
380+
377381
add_file_item(s->files, name);
378382

379383
entry = xcalloc(sizeof(*entry), 1);
@@ -395,13 +399,22 @@ static void collect_changes_cb(struct diff_queue_struct *q,
395399
free_diffstat_info(&stat);
396400
}
397401

398-
static int get_modified_files(struct repository *r, struct string_list *files,
402+
enum modified_files_filter {
403+
NO_FILTER = 0,
404+
WORKTREE_ONLY = 1,
405+
INDEX_ONLY = 2,
406+
};
407+
408+
static int get_modified_files(struct repository *r,
409+
enum modified_files_filter filter,
410+
struct string_list *files,
399411
const struct pathspec *ps)
400412
{
401413
struct object_id head_oid;
402414
int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
403415
&head_oid, NULL);
404416
struct collection_status s = { FROM_WORKTREE };
417+
int i;
405418

406419
if (discard_index(r->index) < 0 ||
407420
repo_read_index_preload(r, ps, 0) < 0)
@@ -411,10 +424,16 @@ static int get_modified_files(struct repository *r, struct string_list *files,
411424
s.files = files;
412425
hashmap_init(&s.file_map, pathname_entry_cmp, NULL, 0);
413426

414-
for (s.phase = FROM_WORKTREE; s.phase <= FROM_INDEX; s.phase++) {
427+
for (i = 0; i < 2; i++) {
415428
struct rev_info rev;
416429
struct setup_revision_opt opt = { 0 };
417430

431+
if (filter == INDEX_ONLY)
432+
s.phase = i ? FROM_WORKTREE : FROM_INDEX;
433+
else
434+
s.phase = i ? FROM_INDEX : FROM_WORKTREE;
435+
s.skip_unseen = filter && i;
436+
418437
opt.def = is_initial ?
419438
empty_tree_oid_hex() : oid_to_hex(&head_oid);
420439

@@ -498,7 +517,7 @@ static void print_file_item(int i, struct string_list_item *item,
498517
static int run_status(struct add_i_state *s, const struct pathspec *ps,
499518
struct string_list *files, struct list_options *opts)
500519
{
501-
if (get_modified_files(s->r, files, ps) < 0)
520+
if (get_modified_files(s->r, NO_FILTER, files, ps) < 0)
502521
return -1;
503522

504523
list(s, files, opts);

0 commit comments

Comments
 (0)