check-ignore: Add option to ignore index contents

check-ignore currently shows how .gitignore rules would treat untracked paths. Tracked paths do not generate useful output. This prevents debugging of why a path became tracked unexpectedly unless that path is first removed from the index with `git rm --cached <path>`. The option --no-index tells the command to bypass the check for the path being in the index and hence allows tracked paths to be checked too. Whilst this behaviour deviates from the characteristics of `git add` and `git status` its use case is unlikely to cause any user confusion. Test scripts are augmented to check this option against the standard ignores to ensure correct behaviour. Signed-off-by: Dave Williams <dave@opensourcesolutions.co.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Dave Williams committed Sep 5, 2013 at 17:08 UTC 8231fa6ae1ef92be73bec5cf0a533a4d8b71d536
3 files changed +74 -11
Documentation/git-check-ignore.txt
+7
@@ -45,6 +45,13 @@ OPTIONS
45 not be possible to distinguish between paths which match a
46 pattern and those which don't.
47
48 +--no-index::
49 + Don't look in the index when undertaking the checks. This can
50 + be used to debug why a path became tracked by e.g. `git add .`
51 + and was not ignored by the rules as expected by the user or when
52 + developing patterns including negation to match a path previously
53 + added with `git add -f`.
54 +
55 OUTPUT
56 ------
57
builtin/check-ignore.c
+4 -2
@@ -5,7 +5,7 @@
5 #include "pathspec.h"
6 #include "parse-options.h"
7
8 -static int quiet, verbose, stdin_paths, show_non_matching;
8 +static int quiet, verbose, stdin_paths, show_non_matching, no_index;
9 static const char * const check_ignore_usage[] = {
10 "git check-ignore [options] pathname...",
11 "git check-ignore [options] --stdin < <list-of-paths>",
@@ -24,6 +24,8 @@ static const struct option check_ignore_options[] = {
24 N_("terminate input and output records by a NUL character")),
25 OPT_BOOL('n', "non-matching", &show_non_matching,
26 N_("show non-matching input paths")),
27 + OPT_BOOL(0, "no-index", &no_index,
28 + N_("ignore index when checking")),
29 OPT_END()
30 };
31
@@ -157,7 +159,7 @@ int cmd_check_ignore(int argc, const char **argv, const char *prefix)
159 die(_("--non-matching is only valid with --verbose"));
160
161 /* read_cache() is only necessary so we can watch out for submodules. */
160 - if (read_cache() < 0)
162 + if (!no_index && read_cache() < 0)
163 die(_("index file corrupt"));
164
165 memset(&dir, 0, sizeof(dir));
t/t0008-ignores.sh
+63 -9
@@ -66,11 +66,11 @@ test_check_ignore () {
66
67 init_vars &&
68 rm -f "$HOME/stdout" "$HOME/stderr" "$HOME/cmd" &&
69 - echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
69 + echo git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
70 >"$HOME/cmd" &&
71 echo "$expect_code" >"$HOME/expected-exit-code" &&
72 test_expect_code "$expect_code" \
73 - git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $args \
73 + git $global_args check-ignore $quiet_opt $verbose_opt $non_matching_opt $no_index_opt $args \
74 >"$HOME/stdout" 2>"$HOME/stderr" &&
75 test_cmp "$HOME/expected-stdout" "$HOME/stdout" &&
76 stderr_empty_on_success "$expect_code"
@@ -87,6 +87,9 @@ test_check_ignore () {
87 # check-ignore --verbose output is the same as normal output except
88 # for the extra first column.
89 #
90 +# A parameter is used to determine if the tests are run with the
91 +# normal case (using the index), or with the --no-index option.
92 +#
93 # Arguments:
94 # - (optional) prereqs for this test, e.g. 'SYMLINKS'
95 # - test name
@@ -94,19 +97,26 @@ test_check_ignore () {
97 # from the other verbosity modes is automatically inferred
98 # from this value)
99 # - code to run (should invoke test_check_ignore)
97 -test_expect_success_multi () {
100 +# - index option: --index or --no-index
101 +test_expect_success_multiple () {
102 prereq=
99 - if test $# -eq 4
103 + if test $# -eq 5
104 then
105 prereq=$1
106 shift
107 fi
108 + if test "$4" = "--index"
109 + then
110 + no_index_opt=
111 + else
112 + no_index_opt=$4
113 + fi
114 testname="$1" expect_all="$2" code="$3"
115
116 expect_verbose=$( echo "$expect_all" | grep -v '^:: ' )
117 expect=$( echo "$expect_verbose" | sed -e 's/.* //' )
118
109 - test_expect_success $prereq "$testname" '
119 + test_expect_success $prereq "$testname${no_index_opt:+ with $no_index_opt}" '
120 expect "$expect" &&
121 eval "$code"
122 '
@@ -116,7 +126,8 @@ test_expect_success_multi () {
126 then
127 for quiet_opt in '-q' '--quiet'
128 do
119 - test_expect_success $prereq "$testname${quiet_opt:+ with $quiet_opt}" "
129 + opts="${no_index_opt:+$no_index_opt }$quiet_opt"
130 + test_expect_success $prereq "$testname${opts:+ with $opts}" "
131 expect '' &&
132 $code
133 "
@@ -126,7 +137,7 @@ test_expect_success_multi () {
137
138 for verbose_opt in '-v' '--verbose'
139 do
129 - for non_matching_opt in '' ' -n' ' --non-matching'
140 + for non_matching_opt in '' '-n' '--non-matching'
141 do
142 if test -n "$non_matching_opt"
143 then
@@ -139,12 +150,21 @@ test_expect_success_multi () {
150 expect '$my_expect' &&
151 $code
152 "
142 - opts="$verbose_opt$non_matching_opt"
153 + opts="${no_index_opt:+$no_index_opt }$verbose_opt${non_matching_opt:+ $non_matching_opt}"
154 test_expect_success $prereq "$testname${opts:+ with $opts}" "$test_code"
155 done
156 done
157 verbose_opt=
158 non_matching_opt=
159 + no_index_opt=
160 +}
161 +
162 +test_expect_success_multi () {
163 + test_expect_success_multiple "$@" "--index"
164 +}
165 +
166 +test_expect_success_no_index_multi () {
167 + test_expect_success_multiple "$@" "--no-index"
168 }
169
170 test_expect_success 'setup' '
@@ -288,7 +308,7 @@ test_expect_success_multi 'needs work tree' '' '
308
309 # First make sure that the presence of a file in the working tree
310 # does not impact results, but that the presence of a file in the
291 -# index does.
311 +# index does unless the --no-index option is used.
312
313 for subdir in '' 'a/'
314 do
@@ -303,27 +323,61 @@ do
323 ":: ${subdir}non-existent" \
324 "test_check_ignore '${subdir}non-existent' 1"
325
326 + test_expect_success_no_index_multi "non-existent file $where not ignored" \
327 + ":: ${subdir}non-existent" \
328 + "test_check_ignore '${subdir}non-existent' 1"
329 +
330 test_expect_success_multi "non-existent file $where ignored" \
331 ".gitignore:1:one ${subdir}one" \
332 "test_check_ignore '${subdir}one'"
333
334 + test_expect_success_no_index_multi "non-existent file $where ignored" \
335 + ".gitignore:1:one ${subdir}one" \
336 + "test_check_ignore '${subdir}one'"
337 +
338 test_expect_success_multi "existing untracked file $where not ignored" \
339 ":: ${subdir}not-ignored" \
340 "test_check_ignore '${subdir}not-ignored' 1"
341
342 + test_expect_success_no_index_multi "existing untracked file $where not ignored" \
343 + ":: ${subdir}not-ignored" \
344 + "test_check_ignore '${subdir}not-ignored' 1"
345 +
346 test_expect_success_multi "existing tracked file $where not ignored" \
347 ":: ${subdir}ignored-but-in-index" \
348 "test_check_ignore '${subdir}ignored-but-in-index' 1"
349
350 + test_expect_success_no_index_multi "existing tracked file $where shown as ignored" \
351 + ".gitignore:2:ignored-* ${subdir}ignored-but-in-index" \
352 + "test_check_ignore '${subdir}ignored-but-in-index'"
353 +
354 test_expect_success_multi "existing untracked file $where ignored" \
355 ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
356 "test_check_ignore '${subdir}ignored-and-untracked'"
357
358 + test_expect_success_no_index_multi "existing untracked file $where ignored" \
359 + ".gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
360 + "test_check_ignore '${subdir}ignored-and-untracked'"
361 +
362 test_expect_success_multi "mix of file types $where" \
363 ":: ${subdir}non-existent
364 .gitignore:1:one ${subdir}one
365 :: ${subdir}not-ignored
366 :: ${subdir}ignored-but-in-index
367 +.gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
368 + "test_check_ignore '
369 + ${subdir}non-existent
370 + ${subdir}one
371 + ${subdir}not-ignored
372 + ${subdir}ignored-but-in-index
373 + ${subdir}ignored-and-untracked'
374 + "
375 +
376 + test_expect_success_no_index_multi "mix of file types $where" \
377 +":: ${subdir}non-existent
378 +.gitignore:1:one ${subdir}one
379 +:: ${subdir}not-ignored
380 +.gitignore:2:ignored-* ${subdir}ignored-but-in-index
381 .gitignore:2:ignored-* ${subdir}ignored-and-untracked" \
382 "test_check_ignore '
383 ${subdir}non-existent