Skip to content

Commit 721ac4e

Browse files
apelissegitster
authored andcommitted
dir.c: Make git-status --ignored more consistent
The current behavior of git-status is inconsistent and misleading. Especially when used with --untracked-files=all option: - files ignored in untracked directories will be missing from status output. - untracked files in committed yet ignored directories are also missing. - with --untracked-files=normal, untracked directories that contains only ignored files are dropped too. Make the behavior more consistent across all possible use cases: - "--ignored --untracked-files=normal" doesn't show each specific files but top directory. It instead shows untracked directories that only contains ignored files, and ignored tracked directories with untracked files. - "--ignored --untracked-files=all" shows all ignored files, either because it's in an ignored directory (tracked or untracked), or because the file is explicitly ignored. Signed-off-by: Antoine Pelisse <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7e20105 commit 721ac4e

File tree

2 files changed

+81
-21
lines changed

2 files changed

+81
-21
lines changed

dir.c

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,9 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
774774
* traversal routine.
775775
*
776776
* Case 1: If we *already* have entries in the index under that
777-
* directory name, we always recurse into the directory to see
778-
* all the files.
777+
* directory name, we recurse into the directory to see all the files,
778+
* unless the directory is excluded and we want to show ignored
779+
* directories
779780
*
780781
* Case 2: If we *already* have that directory name as a gitlink,
781782
* we always continue to see it as a gitlink, regardless of whether
@@ -789,6 +790,9 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
789790
* just a directory, unless "hide_empty_directories" is
790791
* also true and the directory is empty, in which case
791792
* we just ignore it entirely.
793+
* if we are looking for ignored directories, look if it
794+
* contains only ignored files to decide if it must be shown as
795+
* ignored or not.
792796
* (b) if it looks like a git directory, and we don't have
793797
* 'no_gitlinks' set we treat it as a gitlink, and show it
794798
* as a directory.
@@ -801,12 +805,15 @@ enum directory_treatment {
801805
};
802806

803807
static enum directory_treatment treat_directory(struct dir_struct *dir,
804-
const char *dirname, int len,
808+
const char *dirname, int len, int exclude,
805809
const struct path_simplify *simplify)
806810
{
807811
/* The "len-1" is to strip the final '/' */
808812
switch (directory_exists_in_index(dirname, len-1)) {
809813
case index_directory:
814+
if ((dir->flags & DIR_SHOW_OTHER_DIRECTORIES) && exclude)
815+
break;
816+
810817
return recurse_into_directory;
811818

812819
case index_gitdir:
@@ -826,13 +833,72 @@ static enum directory_treatment treat_directory(struct dir_struct *dir,
826833
}
827834

828835
/* This is the "show_other_directories" case */
829-
if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
836+
837+
/*
838+
* We are looking for ignored files and our directory is not ignored,
839+
* check if it contains only ignored files
840+
*/
841+
if ((dir->flags & DIR_SHOW_IGNORED) && !exclude) {
842+
int ignored;
843+
dir->flags &= ~DIR_SHOW_IGNORED;
844+
dir->flags |= DIR_HIDE_EMPTY_DIRECTORIES;
845+
ignored = read_directory_recursive(dir, dirname, len, 1, simplify);
846+
dir->flags &= ~DIR_HIDE_EMPTY_DIRECTORIES;
847+
dir->flags |= DIR_SHOW_IGNORED;
848+
849+
return ignored ? ignore_directory : show_directory;
850+
}
851+
if (!(dir->flags & DIR_SHOW_IGNORED) &&
852+
!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
830853
return show_directory;
831854
if (!read_directory_recursive(dir, dirname, len, 1, simplify))
832855
return ignore_directory;
833856
return show_directory;
834857
}
835858

859+
/*
860+
* Decide what to do when we find a file while traversing the
861+
* filesystem. Mostly two cases:
862+
*
863+
* 1. We are looking for ignored files
864+
* (a) File is ignored, include it
865+
* (b) File is in ignored path, include it
866+
* (c) File is not ignored, exclude it
867+
*
868+
* 2. Other scenarios, include the file if not excluded
869+
*
870+
* Return 1 for exclude, 0 for include.
871+
*/
872+
static int treat_file(struct dir_struct *dir, struct strbuf *path, int exclude, int *dtype)
873+
{
874+
struct path_exclude_check check;
875+
int exclude_file = 0;
876+
877+
if (exclude)
878+
exclude_file = !(dir->flags & DIR_SHOW_IGNORED);
879+
else if (dir->flags & DIR_SHOW_IGNORED) {
880+
/*
881+
* Optimization:
882+
* Don't spend time on indexed files, they won't be
883+
* added to the list anyway
884+
*/
885+
struct cache_entry *ce = index_name_exists(&the_index,
886+
path->buf, path->len, ignore_case);
887+
888+
if (ce)
889+
return 1;
890+
891+
path_exclude_check_init(&check, dir);
892+
893+
if (!path_excluded(&check, path->buf, path->len, dtype))
894+
exclude_file = 1;
895+
896+
path_exclude_check_clear(&check);
897+
}
898+
899+
return exclude_file;
900+
}
901+
836902
/*
837903
* This is an inexact early pruning of any recursive directory
838904
* reading - if the path cannot possibly be in the pathspec,
@@ -971,27 +1037,14 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
9711037
if (dtype == DT_UNKNOWN)
9721038
dtype = get_dtype(de, path->buf, path->len);
9731039

974-
/*
975-
* Do we want to see just the ignored files?
976-
* We still need to recurse into directories,
977-
* even if we don't ignore them, since the
978-
* directory may contain files that we do..
979-
*/
980-
if (!exclude && (dir->flags & DIR_SHOW_IGNORED)) {
981-
if (dtype != DT_DIR)
982-
return path_ignored;
983-
}
984-
9851040
switch (dtype) {
9861041
default:
9871042
return path_ignored;
9881043
case DT_DIR:
9891044
strbuf_addch(path, '/');
990-
switch (treat_directory(dir, path->buf, path->len, simplify)) {
1045+
1046+
switch (treat_directory(dir, path->buf, path->len, exclude, simplify)) {
9911047
case show_directory:
992-
if (exclude != !!(dir->flags
993-
& DIR_SHOW_IGNORED))
994-
return path_ignored;
9951048
break;
9961049
case recurse_into_directory:
9971050
return path_recurse;
@@ -1001,7 +1054,12 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
10011054
break;
10021055
case DT_REG:
10031056
case DT_LNK:
1004-
break;
1057+
switch (treat_file(dir, path, exclude, &dtype)) {
1058+
case 1:
1059+
return path_ignored;
1060+
default:
1061+
break;
1062+
}
10051063
}
10061064
return path_handled;
10071065
}

wt-status.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -516,7 +516,9 @@ static void wt_status_collect_untracked(struct wt_status *s)
516516

517517
if (s->show_ignored_files) {
518518
dir.nr = 0;
519-
dir.flags = DIR_SHOW_IGNORED | DIR_SHOW_OTHER_DIRECTORIES;
519+
dir.flags = DIR_SHOW_IGNORED;
520+
if (s->show_untracked_files != SHOW_ALL_UNTRACKED_FILES)
521+
dir.flags |= DIR_SHOW_OTHER_DIRECTORIES;
520522
fill_directory(&dir, s->pathspec);
521523
for (i = 0; i < dir.nr; i++) {
522524
struct dir_entry *ent = dir.entries[i];

0 commit comments

Comments
 (0)