Skip to content

Commit eec0f7f

Browse files
jamillgitster
authored andcommitted
status: add option to show ignored files differently
Teach the status command more flexibility in how ignored files are reported. Currently, the reporting of ignored files and untracked files are linked. You cannot control how ignored files are reported independently of how untracked files are reported (i.e. `all` vs `normal`). This makes it impossible to show untracked files with the `all` option, but show ignored files with the `normal` option. This work 1) adds the ability to control the reporting of ignored files independently of untracked files and 2) introduces the concept of status reporting ignored paths that explicitly match an ignored pattern. There are 2 benefits to these changes: 1) if a consumer needs all untracked files but not all ignored files, there is a performance benefit to not scanning all contents of an ignored directory and 2) returning ignored files that explicitly match a path allow a consumer to make more informed decisions about when a status result might be stale. This commit implements --ignored=matching with --untracked-files=all. The following commit will implement --ignored=matching with --untracked=files=normal. As an example of where this flexibility could be useful is that our application (Visual Studio) runs the status command and presents the output. It shows all untracked files individually (e.g. using the '--untracked-files==all' option), and would like to know about which paths are ignored. It uses information about ignored paths to make decisions about when the status result might have changed. Additionally, many projects place build output into directories inside a repository's working directory (e.g. in "bin/" and "obj/" directories). Normal usage is to explicitly ignore these 2 directory names in the .gitignore file (rather than or in addition to the *.obj pattern).If an application could know that these directories are explicitly ignored, it could infer that all contents are ignored as well and make better informed decisions about files in these directories. It could infer that any changes under these paths would not affect the output of status. Additionally, there can be a significant performance benefit by avoiding scanning through ignored directories. When status is set to report matching ignored files, it has the following behavior. Ignored files and directories that explicitly match an exclude pattern are reported. If an ignored directory matches an exclude pattern, then the path of the directory is returned. If a directory does not match an exclude pattern, but all of its contents are ignored, then the contained files are reported instead of the directory. Signed-off-by: Jameson Miller <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4843cde commit eec0f7f

File tree

5 files changed

+66
-11
lines changed

5 files changed

+66
-11
lines changed

builtin/commit.c

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ static int edit_flag = -1; /* unspecified */
118118
static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
119119
static int config_commit_verbose = -1; /* unspecified */
120120
static int no_post_rewrite, allow_empty_message;
121-
static char *untracked_files_arg, *force_date, *ignore_submodule_arg;
121+
static char *untracked_files_arg, *force_date, *ignore_submodule_arg, *ignored_arg;
122122
static char *sign_commit;
123123

124124
/*
@@ -139,7 +139,7 @@ static const char *cleanup_arg;
139139
static enum commit_whence whence;
140140
static int sequencer_in_use;
141141
static int use_editor = 1, include_status = 1;
142-
static int show_ignored_in_status, have_option_m;
142+
static int have_option_m;
143143
static struct strbuf message = STRBUF_INIT;
144144

145145
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
@@ -1075,6 +1075,19 @@ static const char *find_author_by_nickname(const char *name)
10751075
die(_("--author '%s' is not 'Name <email>' and matches no existing author"), name);
10761076
}
10771077

1078+
static void handle_ignored_arg(struct wt_status *s)
1079+
{
1080+
if (!ignored_arg)
1081+
; /* default already initialized */
1082+
else if (!strcmp(ignored_arg, "traditional"))
1083+
s->show_ignored_mode = SHOW_TRADITIONAL_IGNORED;
1084+
else if (!strcmp(ignored_arg, "no"))
1085+
s->show_ignored_mode = SHOW_NO_IGNORED;
1086+
else if (!strcmp(ignored_arg, "matching"))
1087+
s->show_ignored_mode = SHOW_MATCHING_IGNORED;
1088+
else
1089+
die(_("Invalid ignored mode '%s'"), ignored_arg);
1090+
}
10781091

10791092
static void handle_untracked_files_arg(struct wt_status *s)
10801093
{
@@ -1363,8 +1376,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13631376
N_("mode"),
13641377
N_("show untracked files, optional modes: all, normal, no. (Default: all)"),
13651378
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
1366-
OPT_BOOL(0, "ignored", &show_ignored_in_status,
1367-
N_("show ignored files")),
1379+
{ OPTION_STRING, 0, "ignored", &ignored_arg,
1380+
N_("mode"),
1381+
N_("show ignored files, optional modes: traditional, matching, no. (Default: traditional)"),
1382+
PARSE_OPT_OPTARG, NULL, (intptr_t)"traditional" },
13681383
{ OPTION_STRING, 0, "ignore-submodules", &ignore_submodule_arg, N_("when"),
13691384
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
13701385
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
@@ -1383,8 +1398,12 @@ int cmd_status(int argc, const char **argv, const char *prefix)
13831398
finalize_deferred_config(&s);
13841399

13851400
handle_untracked_files_arg(&s);
1386-
if (show_ignored_in_status)
1387-
s.show_ignored_files = 1;
1401+
handle_ignored_arg(&s);
1402+
1403+
if (s.show_ignored_mode == SHOW_MATCHING_IGNORED &&
1404+
s.show_untracked_files == SHOW_NO_UNTRACKED_FILES)
1405+
die(_("Unsupported combination of ignored and untracked-files arguments"));
1406+
13881407
parse_pathspec(&s.pathspec, 0,
13891408
PATHSPEC_PREFER_FULL,
13901409
prefix, argv);

dir.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,30 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
13891389
case index_nonexistent:
13901390
if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
13911391
break;
1392+
if (exclude &&
1393+
(dir->flags & DIR_SHOW_IGNORED_TOO) &&
1394+
(dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) {
1395+
1396+
/*
1397+
* This is an excluded directory and we are
1398+
* showing ignored paths that match an exclude
1399+
* pattern. (e.g. show directory as ignored
1400+
* only if it matches an exclude pattern).
1401+
* This path will either be 'path_excluded`
1402+
* (if we are showing empty directories or if
1403+
* the directory is not empty), or will be
1404+
* 'path_none' (empty directory, and we are
1405+
* not showing empty directories).
1406+
*/
1407+
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
1408+
return path_excluded;
1409+
1410+
if (read_directory_recursive(dir, istate, dirname, len,
1411+
untracked, 1, 1, pathspec) == path_excluded)
1412+
return path_excluded;
1413+
1414+
return path_none;
1415+
}
13921416
if (!(dir->flags & DIR_NO_GITLINKS)) {
13931417
unsigned char sha1[20];
13941418
if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)

dir.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,8 @@ struct dir_struct {
152152
DIR_COLLECT_IGNORED = 1<<4,
153153
DIR_SHOW_IGNORED_TOO = 1<<5,
154154
DIR_COLLECT_KILLED_ONLY = 1<<6,
155-
DIR_KEEP_UNTRACKED_CONTENTS = 1<<7
155+
DIR_KEEP_UNTRACKED_CONTENTS = 1<<7,
156+
DIR_SHOW_IGNORED_TOO_MODE_MATCHING = 1<<8
156157
} flags;
157158
struct dir_entry **entries;
158159
struct dir_entry **ignored;

wt-status.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -658,10 +658,15 @@ static void wt_status_collect_untracked(struct wt_status *s)
658658
if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
659659
dir.flags |=
660660
DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES;
661-
if (s->show_ignored_files)
661+
if (s->show_ignored_mode) {
662662
dir.flags |= DIR_SHOW_IGNORED_TOO;
663-
else
663+
664+
if (s->show_ignored_mode == SHOW_MATCHING_IGNORED)
665+
dir.flags |= DIR_SHOW_IGNORED_TOO_MODE_MATCHING;
666+
} else {
664667
dir.untracked = the_index.untracked;
668+
}
669+
665670
setup_standard_excludes(&dir);
666671

667672
fill_directory(&dir, &the_index, &s->pathspec);
@@ -1619,7 +1624,7 @@ static void wt_longstatus_print(struct wt_status *s)
16191624
}
16201625
if (s->show_untracked_files) {
16211626
wt_longstatus_print_other(s, &s->untracked, _("Untracked files"), "add");
1622-
if (s->show_ignored_files)
1627+
if (s->show_ignored_mode)
16231628
wt_longstatus_print_other(s, &s->ignored, _("Ignored files"), "add -f");
16241629
if (advice_status_u_option && 2000 < s->untracked_in_ms) {
16251630
status_printf_ln(s, GIT_COLOR_NORMAL, "%s", "");

wt-status.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ enum untracked_status_type {
2727
SHOW_ALL_UNTRACKED_FILES
2828
};
2929

30+
enum show_ignored_type {
31+
SHOW_NO_IGNORED,
32+
SHOW_TRADITIONAL_IGNORED,
33+
SHOW_MATCHING_IGNORED,
34+
};
35+
3036
/* from where does this commit originate */
3137
enum commit_whence {
3238
FROM_COMMIT, /* normal */
@@ -70,7 +76,7 @@ struct wt_status {
7076
int display_comment_prefix;
7177
int relative_paths;
7278
int submodule_summary;
73-
int show_ignored_files;
79+
enum show_ignored_type show_ignored_mode;
7480
enum untracked_status_type show_untracked_files;
7581
const char *ignore_submodule_arg;
7682
char color_palette[WT_STATUS_MAXSLOT][COLOR_MAXLEN];

0 commit comments

Comments
 (0)