"diff --check" should affect exit status

"git diff" has a --check option that can be used to check for whitespace
problems but it only reported by printing warnings to the
console.

Now when the --check option is used we give a non-zero exit status,
making "git diff --check" nicer to use in scripts and hooks.

Signed-off-by: Wincent Colaiuta <win@wincent.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Wincent Colaiuta 2007-12-13 21:24:52 +01:00 committed by Junio C Hamano
parent 913b45f51b
commit 62c64895cf
8 changed files with 171 additions and 18 deletions

View File

@ -93,7 +93,9 @@ endif::git-format-patch[]
--check:: --check::
Warn if changes introduce trailing whitespace Warn if changes introduce trailing whitespace
or an indent that uses a space before a tab. or an indent that uses a space before a tab. Exits with
non-zero status if problems are found. Not compatible with
--exit-code.
--full-index:: --full-index::
Instead of the first handful characters, show full Instead of the first handful characters, show full

View File

@ -33,5 +33,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
result = run_diff_files_cmd(&rev, argc, argv); result = run_diff_files_cmd(&rev, argc, argv);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
return result; return result;
} }

View File

@ -46,5 +46,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
result = run_diff_index(&rev, cached); result = run_diff_index(&rev, cached);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
return result; return result;
} }

View File

@ -117,23 +117,23 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
break; break;
} }
if (!read_stdin) if (read_stdin) {
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) if (opt->diffopt.detect_rename)
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
DIFF_SETUP_USE_CACHE);
while (fgets(line, sizeof(line), stdin)) {
unsigned char sha1[20];
if (opt->diffopt.detect_rename) if (get_sha1_hex(line, sha1)) {
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE | fputs(line, stdout);
DIFF_SETUP_USE_CACHE); fflush(stdout);
while (fgets(line, sizeof(line), stdin)) { }
unsigned char sha1[20]; else
diff_tree_stdin(line);
if (get_sha1_hex(line, sha1)) {
fputs(line, stdout);
fflush(stdout);
} }
else
diff_tree_stdin(line);
} }
if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0;
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS) return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES); && DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
} }

View File

@ -247,7 +247,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
/* If the user asked for our exit code then don't start a /* If the user asked for our exit code then don't start a
* pager or we would end up reporting its exit code instead. * pager or we would end up reporting its exit code instead.
*/ */
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) &&
(!(rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)))
setup_pager(); setup_pager();
/* Do we have --cached and not have a pending object, then /* Do we have --cached and not have a pending object, then
@ -353,7 +354,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
ent, ents); ent, ents);
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS)) if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0; result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
if (1 < rev.diffopt.skip_stat_unmatch) if (1 < rev.diffopt.skip_stat_unmatch)
refresh_index_quietly(); refresh_index_quietly();
return result; return result;

9
diff.c
View File

@ -1031,6 +1031,7 @@ struct checkdiff_t {
const char *filename; const char *filename;
int lineno, color_diff; int lineno, color_diff;
unsigned ws_rule; unsigned ws_rule;
unsigned status;
}; };
static void checkdiff_consume(void *priv, char *line, unsigned long len) static void checkdiff_consume(void *priv, char *line, unsigned long len)
@ -1064,6 +1065,7 @@ static void checkdiff_consume(void *priv, char *line, unsigned long len)
white_space_at_end = 1; white_space_at_end = 1;
if (space_before_tab || white_space_at_end) { if (space_before_tab || white_space_at_end) {
data->status = 1;
printf("%s:%d: %s", data->filename, data->lineno, ws); printf("%s:%d: %s", data->filename, data->lineno, ws);
if (space_before_tab) { if (space_before_tab) {
printf("space before tab"); printf("space before tab");
@ -1491,6 +1493,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
free_and_return: free_and_return:
diff_free_filespec_data(one); diff_free_filespec_data(one);
diff_free_filespec_data(two); diff_free_filespec_data(two);
if (data.status)
DIFF_OPT_SET(o, CHECK_FAILED);
} }
struct diff_filespec *alloc_filespec(const char *path) struct diff_filespec *alloc_filespec(const char *path)
@ -2121,7 +2125,12 @@ int diff_setup_done(struct diff_options *options)
if (options->output_format & DIFF_FORMAT_NAME_STATUS) if (options->output_format & DIFF_FORMAT_NAME_STATUS)
count++; count++;
if (options->output_format & DIFF_FORMAT_CHECKDIFF) if (options->output_format & DIFF_FORMAT_CHECKDIFF)
{
count++; count++;
if (DIFF_OPT_TST(options, QUIET) ||
DIFF_OPT_TST(options, EXIT_WITH_STATUS))
die("--check may not be used with --quiet or --exit-code");
}
if (options->output_format & DIFF_FORMAT_NO_OUTPUT) if (options->output_format & DIFF_FORMAT_NO_OUTPUT)
count++; count++;
if (count > 1) if (count > 1)

1
diff.h
View File

@ -59,6 +59,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
#define DIFF_OPT_ALLOW_EXTERNAL (1 << 13) #define DIFF_OPT_ALLOW_EXTERNAL (1 << 13)
#define DIFF_OPT_EXIT_WITH_STATUS (1 << 14) #define DIFF_OPT_EXIT_WITH_STATUS (1 << 14)
#define DIFF_OPT_REVERSE_DIFF (1 << 15) #define DIFF_OPT_REVERSE_DIFF (1 << 15)
#define DIFF_OPT_CHECK_FAILED (1 << 16)
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag) #define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag) #define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag) #define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)

View File

@ -117,7 +117,6 @@ EOF
git diff -b > out git diff -b > out
test_expect_success 'another test, with -b' 'git diff expect out' test_expect_success 'another test, with -b' 'git diff expect out'
test_expect_success 'check mixed spaces and tabs in indent' ' test_expect_success 'check mixed spaces and tabs in indent' '
# This is indented with SP HT SP. # This is indented with SP HT SP.
@ -126,4 +125,140 @@ test_expect_success 'check mixed spaces and tabs in indent' '
' '
test_expect_success 'check with no whitespace errors' '
git commit -m "snapshot" &&
echo "foo();" > x &&
git diff --check
'
test_expect_failure 'check with trailing whitespace' '
echo "foo(); " > x &&
git diff --check
'
test_expect_failure 'check with space before tab in indent' '
# indent has space followed by hard tab
echo " foo();" > x &&
git diff --check
'
test_expect_failure '--check and --exit-code are exclusive' '
git checkout x &&
git diff --check --exit-code
'
test_expect_failure '--check and --quiet are exclusive' '
git diff --check --quiet
'
test_expect_success 'check staged with no whitespace errors' '
echo "foo();" > x &&
git add x &&
git diff --cached --check
'
test_expect_failure 'check staged with trailing whitespace' '
echo "foo(); " > x &&
git add x &&
git diff --cached --check
'
test_expect_failure 'check staged with space before tab in indent' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
git diff --cached --check
'
test_expect_success 'check with no whitespace errors (diff-index)' '
echo "foo();" > x &&
git add x &&
git diff-index --check HEAD
'
test_expect_failure 'check with trailing whitespace (diff-index)' '
echo "foo(); " > x &&
git add x &&
git diff-index --check HEAD
'
test_expect_failure 'check with space before tab in indent (diff-index)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
git diff-index --check HEAD
'
test_expect_success 'check staged with no whitespace errors (diff-index)' '
echo "foo();" > x &&
git add x &&
git diff-index --cached --check HEAD
'
test_expect_failure 'check staged with trailing whitespace (diff-index)' '
echo "foo(); " > x &&
git add x &&
git diff-index --cached --check HEAD
'
test_expect_failure 'check staged with space before tab in indent (diff-index)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git add x &&
git diff-index --cached --check HEAD
'
test_expect_success 'check with no whitespace errors (diff-tree)' '
echo "foo();" > x &&
git commit -m "new commit" x &&
git diff-tree --check HEAD^ HEAD
'
test_expect_failure 'check with trailing whitespace (diff-tree)' '
echo "foo(); " > x &&
git commit -m "another commit" x &&
git diff-tree --check HEAD^ HEAD
'
test_expect_failure 'check with space before tab in indent (diff-tree)' '
# indent has space followed by hard tab
echo " foo();" > x &&
git commit -m "yet another" x &&
git diff-tree --check HEAD^ HEAD
'
test_done test_done