Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 34120a5

Browse files
committed
Merge branch 'nd/diff-quiet-stat-dirty' into maint
"git diff --quiet -- pathspec1 pathspec2" sometimes did not return correct status value. * nd/diff-quiet-stat-dirty: diff: do not quit early on stat-dirty files diff.c: move diffcore_skip_stat_unmatch core logic out for reuse later
2 parents 1030d4c + f34b205 commit 34120a5

File tree

3 files changed

+51
-24
lines changed

3 files changed

+51
-24
lines changed

diff.c

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4697,6 +4697,38 @@ static int diff_filespec_is_identical(struct diff_filespec *one,
46974697
return !memcmp(one->data, two->data, one->size);
46984698
}
46994699

4700+
static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
4701+
{
4702+
if (p->done_skip_stat_unmatch)
4703+
return p->skip_stat_unmatch_result;
4704+
4705+
p->done_skip_stat_unmatch = 1;
4706+
p->skip_stat_unmatch_result = 0;
4707+
/*
4708+
* 1. Entries that come from stat info dirtiness
4709+
* always have both sides (iow, not create/delete),
4710+
* one side of the object name is unknown, with
4711+
* the same mode and size. Keep the ones that
4712+
* do not match these criteria. They have real
4713+
* differences.
4714+
*
4715+
* 2. At this point, the file is known to be modified,
4716+
* with the same mode and size, and the object
4717+
* name of one side is unknown. Need to inspect
4718+
* the identical contents.
4719+
*/
4720+
if (!DIFF_FILE_VALID(p->one) || /* (1) */
4721+
!DIFF_FILE_VALID(p->two) ||
4722+
(p->one->sha1_valid && p->two->sha1_valid) ||
4723+
(p->one->mode != p->two->mode) ||
4724+
diff_populate_filespec(p->one, 1) ||
4725+
diff_populate_filespec(p->two, 1) ||
4726+
(p->one->size != p->two->size) ||
4727+
!diff_filespec_is_identical(p->one, p->two)) /* (2) */
4728+
p->skip_stat_unmatch_result = 1;
4729+
return p->skip_stat_unmatch_result;
4730+
}
4731+
47004732
static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
47014733
{
47024734
int i;
@@ -4707,27 +4739,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
47074739
for (i = 0; i < q->nr; i++) {
47084740
struct diff_filepair *p = q->queue[i];
47094741

4710-
/*
4711-
* 1. Entries that come from stat info dirtiness
4712-
* always have both sides (iow, not create/delete),
4713-
* one side of the object name is unknown, with
4714-
* the same mode and size. Keep the ones that
4715-
* do not match these criteria. They have real
4716-
* differences.
4717-
*
4718-
* 2. At this point, the file is known to be modified,
4719-
* with the same mode and size, and the object
4720-
* name of one side is unknown. Need to inspect
4721-
* the identical contents.
4722-
*/
4723-
if (!DIFF_FILE_VALID(p->one) || /* (1) */
4724-
!DIFF_FILE_VALID(p->two) ||
4725-
(p->one->sha1_valid && p->two->sha1_valid) ||
4726-
(p->one->mode != p->two->mode) ||
4727-
diff_populate_filespec(p->one, 1) ||
4728-
diff_populate_filespec(p->two, 1) ||
4729-
(p->one->size != p->two->size) ||
4730-
!diff_filespec_is_identical(p->one, p->two)) /* (2) */
4742+
if (diff_filespec_check_stat_unmatch(p))
47314743
diff_q(&outq, p);
47324744
else {
47334745
/*
@@ -4890,6 +4902,7 @@ void diff_change(struct diff_options *options,
48904902
unsigned old_dirty_submodule, unsigned new_dirty_submodule)
48914903
{
48924904
struct diff_filespec *one, *two;
4905+
struct diff_filepair *p;
48934906

48944907
if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
48954908
is_submodule_ignored(concatpath, options))
@@ -4916,10 +4929,16 @@ void diff_change(struct diff_options *options,
49164929
fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
49174930
one->dirty_submodule = old_dirty_submodule;
49184931
two->dirty_submodule = new_dirty_submodule;
4932+
p = diff_queue(&diff_queued_diff, one, two);
49194933

4920-
diff_queue(&diff_queued_diff, one, two);
4921-
if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
4922-
DIFF_OPT_SET(options, HAS_CHANGES);
4934+
if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
4935+
return;
4936+
4937+
if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
4938+
!diff_filespec_check_stat_unmatch(p))
4939+
return;
4940+
4941+
DIFF_OPT_SET(options, HAS_CHANGES);
49234942
}
49244943

49254944
struct diff_filepair *diff_unmerge(struct diff_options *options, const char *path)

diffcore.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ struct diff_filepair {
6868
unsigned broken_pair : 1;
6969
unsigned renamed_pair : 1;
7070
unsigned is_unmerged : 1;
71+
unsigned done_skip_stat_unmatch : 1;
72+
unsigned skip_stat_unmatch_result : 1;
7173
};
7274
#define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)
7375

t/t4035-diff-quiet.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,4 +148,10 @@ test_expect_success 'git diff --ignore-all-space, both files outside repo' '
148148
)
149149
'
150150

151+
test_expect_success 'git diff --quiet ignores stat-change only entries' '
152+
test-chmtime +10 a &&
153+
echo modified >>b &&
154+
test_expect_code 1 git diff --quiet
155+
'
156+
151157
test_done

0 commit comments

Comments
 (0)