diff-lib: allow ita entries treated as "not yet exist in index"

When comparing the index and the working tree to show which paths are new, and comparing the tree recorded in the HEAD and the index to see if committing the contents recorded in the index would result in an empty commit, we would want the former comparison to say "these are new paths" and the latter to say "there is no change" for paths that are marked as intent-to-add. We made a similar attempt at d95d728a ("diff-lib.c: adjust position of i-t-a entries in diff", 2015-03-16), which redefined the semantics of these two comparison modes globally, which was a disaster and had to be reverted at 78cc1a54 ("Revert "diff-lib.c: adjust position of i-t-a entries in diff"", 2015-06-23). To make sure we do not repeat the same mistake, introduce a new internal diffopt option so that this different semantics can be asked for only by callers that ask it, while making sure other unaudited callers will get the same comparison result. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Oct 24, 2016 at 17:42 UTC 425a28e0a4edfc39585cec6b0b6368c0ad9dbf7e
5 files changed +38 -4
diff-lib.c
+14
@@ -214,6 +214,12 @@ int run_diff_files(struct rev_info *revs, unsigned int option)
214 !is_null_oid(&ce->oid),
215 ce->name, 0);
216 continue;
217 + } else if (revs->diffopt.ita_invisible_in_index &&
218 + ce_intent_to_add(ce)) {
219 + diff_addremove(&revs->diffopt, '+', ce->ce_mode,
220 + EMPTY_BLOB_SHA1_BIN, 0,
221 + ce->name, 0);
222 + continue;
223 }
224
225 changed = match_stat_with_submodule(&revs->diffopt, ce, &st,
@@ -379,6 +385,14 @@ static void do_oneway_diff(struct unpack_trees_options *o,
385 struct rev_info *revs = o->unpack_data;
386 int match_missing, cached;
387
388 + /* i-t-a entries do not actually exist in the index */
389 + if (revs->diffopt.ita_invisible_in_index &&
390 + idx && ce_intent_to_add(idx)) {
391 + idx = NULL;
392 + if (!tree)
393 + return; /* nothing to diff.. */
394 + }
395 +
396 /* if the entry is not checked out, don't examine work tree */
397 cached = o->index_only ||
398 (idx && ((idx->ce_flags & CE_VALID) || ce_skip_worktree(idx)));
diff.h
+1
@@ -146,6 +146,7 @@ struct diff_options {
146 int dirstat_permille;
147 int setup;
148 int abbrev;
149 + int ita_invisible_in_index;
150 /* white-space error highlighting */
151 #define WSEH_NEW 1
152 #define WSEH_CONTEXT 2
t/t2203-add-intent.sh
+15 -1
@@ -5,10 +5,24 @@ test_description='Intent to add'
5 . ./test-lib.sh
6
7 test_expect_success 'intent to add' '
8 + test_commit 1 &&
9 + git rm 1.t &&
10 + echo hello >1.t &&
11 echo hello >file &&
12 echo hello >elif &&
13 git add -N file &&
11 - git add elif
14 + git add elif &&
15 + git add -N 1.t
16 +'
17 +
18 +test_expect_success 'git status' '
19 + git status --porcelain | grep -v actual >actual &&
20 + cat >expect <<-\EOF &&
21 + DA 1.t
22 + A elif
23 + A file
24 + EOF
25 + test_cmp expect actual
26 '
27
28 test_expect_success 'check result of "add -N"' '
t/t7064-wtstatus-pv2.sh
+2 -2
@@ -246,8 +246,8 @@ test_expect_success 'verify --intent-to-add output' '
246 git add --intent-to-add intent1.add intent2.add &&
247
248 cat >expect <<-EOF &&
249 - 1 AM N... 000000 100644 100644 $_z40 $EMPTY_BLOB intent1.add
250 - 1 AM N... 000000 100644 100644 $_z40 $EMPTY_BLOB intent2.add
249 + 1 .A N... 000000 000000 100644 $_z40 $_z40 intent1.add
250 + 1 .A N... 000000 000000 100644 $_z40 $_z40 intent2.add
251 EOF
252
253 git status --porcelain=v2 >actual &&
wt-status.c
+6 -1
@@ -437,7 +437,7 @@ static void wt_status_collect_changed_cb(struct diff_queue_struct *q,
437
438 switch (p->status) {
439 case DIFF_STATUS_ADDED:
440 - die("BUG: worktree status add???");
440 + d->mode_worktree = p->two->mode;
441 break;
442
443 case DIFF_STATUS_DELETED:
@@ -547,6 +547,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
547 setup_revisions(0, NULL, &rev, NULL);
548 rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
549 DIFF_OPT_SET(&rev.diffopt, DIRTY_SUBMODULES);
550 + rev.diffopt.ita_invisible_in_index = 1;
551 if (!s->show_untracked_files)
552 DIFF_OPT_SET(&rev.diffopt, IGNORE_UNTRACKED_IN_SUBMODULES);
553 if (s->ignore_submodule_arg) {
@@ -570,6 +571,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)
571 setup_revisions(0, NULL, &rev, &opt);
572
573 DIFF_OPT_SET(&rev.diffopt, OVERRIDE_SUBMODULE_CONFIG);
574 + rev.diffopt.ita_invisible_in_index = 1;
575 if (s->ignore_submodule_arg) {
576 handle_ignore_submodules_arg(&rev.diffopt, s->ignore_submodule_arg);
577 } else {
@@ -605,6 +607,8 @@ static void wt_status_collect_changes_initial(struct wt_status *s)
607
608 if (!ce_path_match(ce, &s->pathspec, NULL))
609 continue;
610 + if (ce_intent_to_add(ce))
611 + continue;
612 it = string_list_insert(&s->change, ce->name);
613 d = it->util;
614 if (!d) {
@@ -911,6 +915,7 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
915
916 init_revisions(&rev, NULL);
917 DIFF_OPT_SET(&rev.diffopt, ALLOW_TEXTCONV);
918 + rev.diffopt.ita_invisible_in_index = 1;
919
920 memset(&opt, 0, sizeof(opt));
921 opt.def = s->is_initial ? EMPTY_TREE_SHA1_HEX : s->reference;