blob: 3c652748d58c69dec4378d01de58212f65763328 [file] [log] [blame]
Nguyễn Thái Ngọc Duyf8adbec2019-01-24 15:29:12 +07001#define USE_THE_INDEX_COMPATIBILITY_MACROS
Adam Spiers368aa522013-01-06 16:58:13 +00002#include "builtin.h"
3#include "cache.h"
Brandon Williamsb2141fc2017-06-14 11:07:36 -07004#include "config.h"
Adam Spiers368aa522013-01-06 16:58:13 +00005#include "dir.h"
6#include "quote.h"
7#include "pathspec.h"
8#include "parse-options.h"
Brandon Williamsc08397e2017-05-11 15:04:24 -07009#include "submodule.h"
Adam Spiers368aa522013-01-06 16:58:13 +000010
Dave Williams8231fa62013-09-05 17:08:01 +010011static int quiet, verbose, stdin_paths, show_non_matching, no_index;
Adam Spiers368aa522013-01-06 16:58:13 +000012static const char * const check_ignore_usage[] = {
Alex Henrie9c9b4f22015-01-13 00:44:47 -070013"git check-ignore [<options>] <pathname>...",
Junio C Hamano33e8fc82015-10-16 11:27:42 -070014"git check-ignore [<options>] --stdin",
Adam Spiers368aa522013-01-06 16:58:13 +000015NULL
16};
17
Junio C Hamano800531a2013-07-11 23:05:48 -070018static int nul_term_line;
Adam Spiers368aa522013-01-06 16:58:13 +000019
20static const struct option check_ignore_options[] = {
21 OPT__QUIET(&quiet, N_("suppress progress reporting")),
22 OPT__VERBOSE(&verbose, N_("be verbose")),
23 OPT_GROUP(""),
Stefan Bellerd5d09d42013-08-03 13:51:19 +020024 OPT_BOOL(0, "stdin", &stdin_paths,
25 N_("read file names from stdin")),
Junio C Hamanoa86a8b92013-09-04 12:39:02 -070026 OPT_BOOL('z', NULL, &nul_term_line,
27 N_("terminate input and output records by a NUL character")),
Stefan Bellerd5d09d42013-08-03 13:51:19 +020028 OPT_BOOL('n', "non-matching", &show_non_matching,
29 N_("show non-matching input paths")),
Dave Williams8231fa62013-09-05 17:08:01 +010030 OPT_BOOL(0, "no-index", &no_index,
31 N_("ignore index when checking")),
Adam Spiers368aa522013-01-06 16:58:13 +000032 OPT_END()
33};
34
Derrick Stoleeab8db612019-09-03 11:04:55 -070035static void output_pattern(const char *path, struct path_pattern *pattern)
Adam Spiers368aa522013-01-06 16:58:13 +000036{
Derrick Stolee4ff89ee2019-09-03 11:04:56 -070037 char *bang = (pattern && pattern->flags & PATTERN_FLAG_NEGATIVE) ? "!" : "";
38 char *slash = (pattern && pattern->flags & PATTERN_FLAG_MUSTBEDIR) ? "/" : "";
Junio C Hamano800531a2013-07-11 23:05:48 -070039 if (!nul_term_line) {
Adam Spiers368aa522013-01-06 16:58:13 +000040 if (!verbose) {
41 write_name_quoted(path, stdout, '\n');
42 } else {
Derrick Stoleeab8db612019-09-03 11:04:55 -070043 if (pattern) {
Derrick Stoleecaa3d552019-09-03 11:04:56 -070044 quote_c_style(pattern->pl->src, NULL, stdout, 0);
Adam Spiersae3caf42013-04-11 13:05:10 +010045 printf(":%d:%s%s%s\t",
Derrick Stoleeab8db612019-09-03 11:04:55 -070046 pattern->srcpos,
47 bang, pattern->pattern, slash);
Adam Spiersae3caf42013-04-11 13:05:10 +010048 }
49 else {
50 printf("::\t");
51 }
Adam Spiers368aa522013-01-06 16:58:13 +000052 quote_c_style(path, NULL, stdout, 0);
53 fputc('\n', stdout);
54 }
55 } else {
56 if (!verbose) {
57 printf("%s%c", path, '\0');
58 } else {
Derrick Stoleeab8db612019-09-03 11:04:55 -070059 if (pattern)
Adam Spiersae3caf42013-04-11 13:05:10 +010060 printf("%s%c%d%c%s%s%s%c%s%c",
Derrick Stoleecaa3d552019-09-03 11:04:56 -070061 pattern->pl->src, '\0',
Derrick Stoleeab8db612019-09-03 11:04:55 -070062 pattern->srcpos, '\0',
63 bang, pattern->pattern, slash, '\0',
Adam Spiersae3caf42013-04-11 13:05:10 +010064 path, '\0');
65 else
66 printf("%c%c%c%s%c", '\0', '\0', '\0', path, '\0');
Adam Spiers368aa522013-01-06 16:58:13 +000067 }
68 }
69}
70
Junio C Hamanoc51afbb2013-05-29 14:23:39 -070071static int check_ignore(struct dir_struct *dir,
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070072 const char *prefix, int argc, const char **argv)
Adam Spiers368aa522013-01-06 16:58:13 +000073{
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070074 const char *full_path;
Adam Spiers368aa522013-01-06 16:58:13 +000075 char *seen;
René Scharfed60771e2018-02-10 13:38:29 +010076 int num_ignored = 0, i;
Derrick Stoleeab8db612019-09-03 11:04:55 -070077 struct path_pattern *pattern;
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070078 struct pathspec pathspec;
Adam Spiers368aa522013-01-06 16:58:13 +000079
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070080 if (!argc) {
Adam Spiers368aa522013-01-06 16:58:13 +000081 if (!quiet)
82 fprintf(stderr, "no pathspec given.\n");
83 return 0;
84 }
85
Adam Spiers368aa522013-01-06 16:58:13 +000086 /*
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070087 * check-ignore just needs paths. Magic beyond :/ is really
88 * irrelevant.
89 */
90 parse_pathspec(&pathspec,
91 PATHSPEC_ALL_MAGIC & ~PATHSPEC_FROMTOP,
92 PATHSPEC_SYMLINK_LEADING_PATH |
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070093 PATHSPEC_KEEP_ORDER,
94 prefix, argv);
95
Brandon Williamsc08397e2017-05-11 15:04:24 -070096 die_path_inside_submodule(&the_index, &pathspec);
97
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +070098 /*
Adam Spiers368aa522013-01-06 16:58:13 +000099 * look for pathspecs matching entries in the index, since these
100 * should not be ignored, in order to be consistent with
101 * 'git status', 'git add' etc.
102 */
Brandon Williams08de9152017-05-11 15:04:27 -0700103 seen = find_pathspecs_matching_against_index(&pathspec, &the_index);
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +0700104 for (i = 0; i < pathspec.nr; i++) {
Nguyễn Thái Ngọc Duy84b8b5d2013-07-14 15:36:00 +0700105 full_path = pathspec.items[i].match;
Derrick Stoleeab8db612019-09-03 11:04:55 -0700106 pattern = NULL;
Junio C Hamanoc19387e2013-02-19 11:56:44 -0800107 if (!seen[i]) {
René Scharfed60771e2018-02-10 13:38:29 +0100108 int dtype = DT_UNKNOWN;
Derrick Stolee65edd962019-09-03 11:04:57 -0700109 pattern = last_matching_pattern(dir, &the_index,
Brandon Williamsa0bba652017-05-05 12:53:30 -0700110 full_path, &dtype);
Elijah Newren7ec81252020-02-18 23:05:37 +0000111 if (!verbose && pattern &&
112 pattern->flags & PATTERN_FLAG_NEGATIVE)
113 pattern = NULL;
Adam Spiers368aa522013-01-06 16:58:13 +0000114 }
Derrick Stoleeab8db612019-09-03 11:04:55 -0700115 if (!quiet && (pattern || show_non_matching))
116 output_pattern(pathspec.items[i].original, pattern);
117 if (pattern)
Adam Spiersae3caf42013-04-11 13:05:10 +0100118 num_ignored++;
Adam Spiers368aa522013-01-06 16:58:13 +0000119 }
120 free(seen);
Adam Spiers368aa522013-01-06 16:58:13 +0000121
122 return num_ignored;
123}
124
Junio C Hamanoc51afbb2013-05-29 14:23:39 -0700125static int check_ignore_stdin_paths(struct dir_struct *dir, const char *prefix)
Adam Spiers368aa522013-01-06 16:58:13 +0000126{
Jeff King0d4cc1b2016-01-31 06:25:26 -0500127 struct strbuf buf = STRBUF_INIT;
128 struct strbuf unquoted = STRBUF_INIT;
Adam Spiers0c8e8c02013-04-11 13:05:12 +0100129 char *pathspec[2] = { NULL, NULL };
Junio C Hamanodca90032016-01-14 13:31:17 -0800130 strbuf_getline_fn getline_fn;
Adam Spiers0c8e8c02013-04-11 13:05:12 +0100131 int num_ignored = 0;
Adam Spiers368aa522013-01-06 16:58:13 +0000132
Junio C Hamanodca90032016-01-14 13:31:17 -0800133 getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf;
Junio C Hamanodca90032016-01-14 13:31:17 -0800134 while (getline_fn(&buf, stdin) != EOF) {
135 if (!nul_term_line && buf.buf[0] == '"') {
Jeff King0d4cc1b2016-01-31 06:25:26 -0500136 strbuf_reset(&unquoted);
137 if (unquote_c_style(&unquoted, buf.buf, NULL))
Adam Spiers368aa522013-01-06 16:58:13 +0000138 die("line is badly quoted");
Jeff King0d4cc1b2016-01-31 06:25:26 -0500139 strbuf_swap(&buf, &unquoted);
Adam Spiers368aa522013-01-06 16:58:13 +0000140 }
Adam Spiers0c8e8c02013-04-11 13:05:12 +0100141 pathspec[0] = buf.buf;
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +0700142 num_ignored += check_ignore(dir, prefix,
143 1, (const char **)pathspec);
Adam Spiers0c8e8c02013-04-11 13:05:12 +0100144 maybe_flush_or_die(stdout, "check-ignore to stdout");
Adam Spiers368aa522013-01-06 16:58:13 +0000145 }
Adam Spiers368aa522013-01-06 16:58:13 +0000146 strbuf_release(&buf);
Jeff King0d4cc1b2016-01-31 06:25:26 -0500147 strbuf_release(&unquoted);
Adam Spiers368aa522013-01-06 16:58:13 +0000148 return num_ignored;
149}
150
151int cmd_check_ignore(int argc, const char **argv, const char *prefix)
152{
153 int num_ignored;
Adam Spiers0006d852013-04-11 13:05:11 +0100154 struct dir_struct dir;
Adam Spiers368aa522013-01-06 16:58:13 +0000155
156 git_config(git_default_config, NULL);
157
158 argc = parse_options(argc, argv, prefix, check_ignore_options,
159 check_ignore_usage, 0);
160
161 if (stdin_paths) {
162 if (argc > 0)
163 die(_("cannot specify pathnames with --stdin"));
164 } else {
Junio C Hamano800531a2013-07-11 23:05:48 -0700165 if (nul_term_line)
Adam Spiers368aa522013-01-06 16:58:13 +0000166 die(_("-z only makes sense with --stdin"));
167 if (argc == 0)
168 die(_("no path specified"));
169 }
170 if (quiet) {
171 if (argc > 1)
172 die(_("--quiet is only valid with a single pathname"));
173 if (verbose)
174 die(_("cannot have both --quiet and --verbose"));
175 }
Adam Spiersae3caf42013-04-11 13:05:10 +0100176 if (show_non_matching && !verbose)
177 die(_("--non-matching is only valid with --verbose"));
Adam Spiers368aa522013-01-06 16:58:13 +0000178
Adam Spiers0006d852013-04-11 13:05:11 +0100179 /* read_cache() is only necessary so we can watch out for submodules. */
Dave Williams8231fa62013-09-05 17:08:01 +0100180 if (!no_index && read_cache() < 0)
Adam Spiers0006d852013-04-11 13:05:11 +0100181 die(_("index file corrupt"));
182
Elijah Newreneceba532020-08-18 22:58:26 +0000183 dir_init(&dir);
Adam Spiers0006d852013-04-11 13:05:11 +0100184 setup_standard_excludes(&dir);
Adam Spiers368aa522013-01-06 16:58:13 +0000185
186 if (stdin_paths) {
Junio C Hamanoc51afbb2013-05-29 14:23:39 -0700187 num_ignored = check_ignore_stdin_paths(&dir, prefix);
Adam Spiers368aa522013-01-06 16:58:13 +0000188 } else {
Nguyễn Thái Ngọc Duy931eab62013-07-14 15:35:45 +0700189 num_ignored = check_ignore(&dir, prefix, argc, argv);
Adam Spiers368aa522013-01-06 16:58:13 +0000190 maybe_flush_or_die(stdout, "ignore to stdout");
191 }
192
Elijah Newreneceba532020-08-18 22:58:26 +0000193 dir_clear(&dir);
Adam Spiers0006d852013-04-11 13:05:11 +0100194
Adam Spiers368aa522013-01-06 16:58:13 +0000195 return !num_ignored;
196}