Merge branch 'nd/diff-quiet-stat-dirty'

"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
This commit is contained in:
Junio C Hamano 2014-02-27 14:01:21 -08:00
commit 1e745453fe
3 changed files with 51 additions and 24 deletions

39
diff.c
View File

@ -4697,16 +4697,13 @@ static int diff_filespec_is_identical(struct diff_filespec *one,
return !memcmp(one->data, two->data, one->size); return !memcmp(one->data, two->data, one->size);
} }
static void diffcore_skip_stat_unmatch(struct diff_options *diffopt) static int diff_filespec_check_stat_unmatch(struct diff_filepair *p)
{ {
int i; if (p->done_skip_stat_unmatch)
struct diff_queue_struct *q = &diff_queued_diff; return p->skip_stat_unmatch_result;
struct diff_queue_struct outq;
DIFF_QUEUE_CLEAR(&outq);
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
p->done_skip_stat_unmatch = 1;
p->skip_stat_unmatch_result = 0;
/* /*
* 1. Entries that come from stat info dirtiness * 1. Entries that come from stat info dirtiness
* always have both sides (iow, not create/delete), * always have both sides (iow, not create/delete),
@ -4728,6 +4725,21 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
diff_populate_filespec(p->two, 1) || diff_populate_filespec(p->two, 1) ||
(p->one->size != p->two->size) || (p->one->size != p->two->size) ||
!diff_filespec_is_identical(p->one, p->two)) /* (2) */ !diff_filespec_is_identical(p->one, p->two)) /* (2) */
p->skip_stat_unmatch_result = 1;
return p->skip_stat_unmatch_result;
}
static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
DIFF_QUEUE_CLEAR(&outq);
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
if (diff_filespec_check_stat_unmatch(p))
diff_q(&outq, p); diff_q(&outq, p);
else { else {
/* /*
@ -4890,6 +4902,7 @@ void diff_change(struct diff_options *options,
unsigned old_dirty_submodule, unsigned new_dirty_submodule) unsigned old_dirty_submodule, unsigned new_dirty_submodule)
{ {
struct diff_filespec *one, *two; struct diff_filespec *one, *two;
struct diff_filepair *p;
if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) && if (S_ISGITLINK(old_mode) && S_ISGITLINK(new_mode) &&
is_submodule_ignored(concatpath, options)) is_submodule_ignored(concatpath, options))
@ -4916,9 +4929,15 @@ void diff_change(struct diff_options *options,
fill_filespec(two, new_sha1, new_sha1_valid, new_mode); fill_filespec(two, new_sha1, new_sha1_valid, new_mode);
one->dirty_submodule = old_dirty_submodule; one->dirty_submodule = old_dirty_submodule;
two->dirty_submodule = new_dirty_submodule; two->dirty_submodule = new_dirty_submodule;
p = diff_queue(&diff_queued_diff, one, two);
if (DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
return;
if (DIFF_OPT_TST(options, QUICK) && options->skip_stat_unmatch &&
!diff_filespec_check_stat_unmatch(p))
return;
diff_queue(&diff_queued_diff, one, two);
if (!DIFF_OPT_TST(options, DIFF_FROM_CONTENTS))
DIFF_OPT_SET(options, HAS_CHANGES); DIFF_OPT_SET(options, HAS_CHANGES);
} }

View File

@ -68,6 +68,8 @@ struct diff_filepair {
unsigned broken_pair : 1; unsigned broken_pair : 1;
unsigned renamed_pair : 1; unsigned renamed_pair : 1;
unsigned is_unmerged : 1; unsigned is_unmerged : 1;
unsigned done_skip_stat_unmatch : 1;
unsigned skip_stat_unmatch_result : 1;
}; };
#define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged) #define DIFF_PAIR_UNMERGED(p) ((p)->is_unmerged)

View File

@ -148,4 +148,10 @@ test_expect_success 'git diff --ignore-all-space, both files outside repo' '
) )
' '
test_expect_success 'git diff --quiet ignores stat-change only entries' '
test-chmtime +10 a &&
echo modified >>b &&
test_expect_code 1 git diff --quiet
'
test_done test_done