Skip to content

Commit 62c6489

Browse files
wincentgitster
authored andcommitted
"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>
1 parent 913b45f commit 62c6489

File tree

8 files changed

+171
-18
lines changed

8 files changed

+171
-18
lines changed

Documentation/diff-options.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ endif::git-format-patch[]
9393

9494
--check::
9595
Warn if changes introduce trailing whitespace
96-
or an indent that uses a space before a tab.
96+
or an indent that uses a space before a tab. Exits with
97+
non-zero status if problems are found. Not compatible with
98+
--exit-code.
9799

98100
--full-index::
99101
Instead of the first handful characters, show full

builtin-diff-files.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)
3333
result = run_diff_files_cmd(&rev, argc, argv);
3434
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
3535
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
36+
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
37+
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
3638
return result;
3739
}

builtin-diff-index.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ int cmd_diff_index(int argc, const char **argv, const char *prefix)
4646
result = run_diff_index(&rev, cached);
4747
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
4848
return DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
49+
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
50+
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
4951
return result;
5052
}

builtin-diff-tree.c

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -117,23 +117,23 @@ int cmd_diff_tree(int argc, const char **argv, const char *prefix)
117117
break;
118118
}
119119

120-
if (!read_stdin)
121-
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
122-
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
120+
if (read_stdin) {
121+
if (opt->diffopt.detect_rename)
122+
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
123+
DIFF_SETUP_USE_CACHE);
124+
while (fgets(line, sizeof(line), stdin)) {
125+
unsigned char sha1[20];
123126

124-
if (opt->diffopt.detect_rename)
125-
opt->diffopt.setup |= (DIFF_SETUP_USE_SIZE_CACHE |
126-
DIFF_SETUP_USE_CACHE);
127-
while (fgets(line, sizeof(line), stdin)) {
128-
unsigned char sha1[20];
129-
130-
if (get_sha1_hex(line, sha1)) {
131-
fputs(line, stdout);
132-
fflush(stdout);
127+
if (get_sha1_hex(line, sha1)) {
128+
fputs(line, stdout);
129+
fflush(stdout);
130+
}
131+
else
132+
diff_tree_stdin(line);
133133
}
134-
else
135-
diff_tree_stdin(line);
136134
}
135+
if (opt->diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
136+
return DIFF_OPT_TST(&opt->diffopt, CHECK_FAILED) != 0;
137137
return DIFF_OPT_TST(&opt->diffopt, EXIT_WITH_STATUS)
138138
&& DIFF_OPT_TST(&opt->diffopt, HAS_CHANGES);
139139
}

builtin-diff.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
247247
/* If the user asked for our exit code then don't start a
248248
* pager or we would end up reporting its exit code instead.
249249
*/
250-
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
250+
if (!DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS) &&
251+
(!(rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)))
251252
setup_pager();
252253

253254
/* 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)
353354
ent, ents);
354355
if (DIFF_OPT_TST(&rev.diffopt, EXIT_WITH_STATUS))
355356
result = DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0;
356-
357+
if (rev.diffopt.output_format & DIFF_FORMAT_CHECKDIFF)
358+
return DIFF_OPT_TST(&rev.diffopt, CHECK_FAILED) != 0;
357359
if (1 < rev.diffopt.skip_stat_unmatch)
358360
refresh_index_quietly();
359361
return result;

diff.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,6 +1031,7 @@ struct checkdiff_t {
10311031
const char *filename;
10321032
int lineno, color_diff;
10331033
unsigned ws_rule;
1034+
unsigned status;
10341035
};
10351036

10361037
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)
10641065
white_space_at_end = 1;
10651066

10661067
if (space_before_tab || white_space_at_end) {
1068+
data->status = 1;
10671069
printf("%s:%d: %s", data->filename, data->lineno, ws);
10681070
if (space_before_tab) {
10691071
printf("space before tab");
@@ -1491,6 +1493,8 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
14911493
free_and_return:
14921494
diff_free_filespec_data(one);
14931495
diff_free_filespec_data(two);
1496+
if (data.status)
1497+
DIFF_OPT_SET(o, CHECK_FAILED);
14941498
}
14951499

14961500
struct diff_filespec *alloc_filespec(const char *path)
@@ -2121,7 +2125,12 @@ int diff_setup_done(struct diff_options *options)
21212125
if (options->output_format & DIFF_FORMAT_NAME_STATUS)
21222126
count++;
21232127
if (options->output_format & DIFF_FORMAT_CHECKDIFF)
2128+
{
21242129
count++;
2130+
if (DIFF_OPT_TST(options, QUIET) ||
2131+
DIFF_OPT_TST(options, EXIT_WITH_STATUS))
2132+
die("--check may not be used with --quiet or --exit-code");
2133+
}
21252134
if (options->output_format & DIFF_FORMAT_NO_OUTPUT)
21262135
count++;
21272136
if (count > 1)

diff.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ typedef void (*diff_format_fn_t)(struct diff_queue_struct *q,
5959
#define DIFF_OPT_ALLOW_EXTERNAL (1 << 13)
6060
#define DIFF_OPT_EXIT_WITH_STATUS (1 << 14)
6161
#define DIFF_OPT_REVERSE_DIFF (1 << 15)
62+
#define DIFF_OPT_CHECK_FAILED (1 << 16)
6263
#define DIFF_OPT_TST(opts, flag) ((opts)->flags & DIFF_OPT_##flag)
6364
#define DIFF_OPT_SET(opts, flag) ((opts)->flags |= DIFF_OPT_##flag)
6465
#define DIFF_OPT_CLR(opts, flag) ((opts)->flags &= ~DIFF_OPT_##flag)

t/t4015-diff-whitespace.sh

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,6 @@ EOF
117117
git diff -b > out
118118
test_expect_success 'another test, with -b' 'git diff expect out'
119119

120-
121120
test_expect_success 'check mixed spaces and tabs in indent' '
122121
123122
# This is indented with SP HT SP.
@@ -126,4 +125,140 @@ test_expect_success 'check mixed spaces and tabs in indent' '
126125
127126
'
128127

128+
test_expect_success 'check with no whitespace errors' '
129+
130+
git commit -m "snapshot" &&
131+
echo "foo();" > x &&
132+
git diff --check
133+
134+
'
135+
136+
test_expect_failure 'check with trailing whitespace' '
137+
138+
echo "foo(); " > x &&
139+
git diff --check
140+
141+
'
142+
143+
test_expect_failure 'check with space before tab in indent' '
144+
145+
# indent has space followed by hard tab
146+
echo " foo();" > x &&
147+
git diff --check
148+
149+
'
150+
151+
test_expect_failure '--check and --exit-code are exclusive' '
152+
153+
git checkout x &&
154+
git diff --check --exit-code
155+
156+
'
157+
158+
test_expect_failure '--check and --quiet are exclusive' '
159+
160+
git diff --check --quiet
161+
162+
'
163+
164+
test_expect_success 'check staged with no whitespace errors' '
165+
166+
echo "foo();" > x &&
167+
git add x &&
168+
git diff --cached --check
169+
170+
'
171+
172+
test_expect_failure 'check staged with trailing whitespace' '
173+
174+
echo "foo(); " > x &&
175+
git add x &&
176+
git diff --cached --check
177+
178+
'
179+
180+
test_expect_failure 'check staged with space before tab in indent' '
181+
182+
# indent has space followed by hard tab
183+
echo " foo();" > x &&
184+
git add x &&
185+
git diff --cached --check
186+
187+
'
188+
189+
test_expect_success 'check with no whitespace errors (diff-index)' '
190+
191+
echo "foo();" > x &&
192+
git add x &&
193+
git diff-index --check HEAD
194+
195+
'
196+
197+
test_expect_failure 'check with trailing whitespace (diff-index)' '
198+
199+
echo "foo(); " > x &&
200+
git add x &&
201+
git diff-index --check HEAD
202+
203+
'
204+
205+
test_expect_failure 'check with space before tab in indent (diff-index)' '
206+
207+
# indent has space followed by hard tab
208+
echo " foo();" > x &&
209+
git add x &&
210+
git diff-index --check HEAD
211+
212+
'
213+
214+
test_expect_success 'check staged with no whitespace errors (diff-index)' '
215+
216+
echo "foo();" > x &&
217+
git add x &&
218+
git diff-index --cached --check HEAD
219+
220+
'
221+
222+
test_expect_failure 'check staged with trailing whitespace (diff-index)' '
223+
224+
echo "foo(); " > x &&
225+
git add x &&
226+
git diff-index --cached --check HEAD
227+
228+
'
229+
230+
test_expect_failure 'check staged with space before tab in indent (diff-index)' '
231+
232+
# indent has space followed by hard tab
233+
echo " foo();" > x &&
234+
git add x &&
235+
git diff-index --cached --check HEAD
236+
237+
'
238+
239+
test_expect_success 'check with no whitespace errors (diff-tree)' '
240+
241+
echo "foo();" > x &&
242+
git commit -m "new commit" x &&
243+
git diff-tree --check HEAD^ HEAD
244+
245+
'
246+
247+
test_expect_failure 'check with trailing whitespace (diff-tree)' '
248+
249+
echo "foo(); " > x &&
250+
git commit -m "another commit" x &&
251+
git diff-tree --check HEAD^ HEAD
252+
253+
'
254+
255+
test_expect_failure 'check with space before tab in indent (diff-tree)' '
256+
257+
# indent has space followed by hard tab
258+
echo " foo();" > x &&
259+
git commit -m "yet another" x &&
260+
git diff-tree --check HEAD^ HEAD
261+
262+
'
263+
129264
test_done

0 commit comments

Comments
 (0)