从2011年开始,这是在Git v1.8.3-rc0(2013年4月)中首次修复的。
它修复了在代码遍历工作树以查找未跟踪和/或被忽略的文件时遇到的一些问题,并且在总体上清理和优化了代码路径。
查看提交0aaf62b, 提交defd7c7, 提交8aaf8d7, 提交b07bc8c, 提交95c6f27, 提交6cd5c58, 提交46aa2f9, 提交5bd8e2d, 提交be8a84c, 提交c94ab01, 提交184d2a8, 提交0104c9e, 提交289ff55, 提交560bb7a (2013年4月15日) 由Karsten Blees (kblees
)提交。
(由Junio C Hamano -- gitster
--合并于提交7093d2c, 2013年4月23日)
dir.c
:使“git-status --ignored”在前导目录中工作
签名作者:Karsten Blees
如果“path”的某个组件被分类为未跟踪,则“{{link2:git status --ignored path/
}}”不会列出“path”中被忽略的文件和目录。
在遍历前导目录时禁用DIR_SHOW_OTHER_DIRECTORIES
标志。这可以防止带有DIR_SHOW_IGNORED
标志的treat_leading_path()
在顶级未跟踪目录处中止。
作为副作用,这也消除了每个前导目录级别的递归目录扫描,因为当从treat_leading_path()
调用treat_directory()
时,treat_directory()
不能再调用read_directory_recursive()
。
但是,6年后(2019年末),随着Git 2.25(2020年第一季度)的推出,对目录遍历API进行了各种修复...撤销了上述的修复,并重新实现了它。
请查看 2019年12月20日由Junio C Hamano (gitster
)提交的提交6836d2f。
请查看 2019年12月19日提交的提交c847dfa, 2019年12月19日提交的提交777b420, 2019年12月19日提交的提交b9670c1,以及 2019年12月10日由Elijah Newren (newren
)提交的提交c5c4edd, 2019年12月10日提交的提交072a231, 2019年12月10日提交的提交2f5d384, 2019年12月10日提交的提交a2b1336, 2019年12月10日提交的提交452efd1。
(由Junio C Hamano -- gitster
--在2019年12月25日提交的提交d2189a7中合并)
Revert "dir.c
: make 'git-status --ignored
' work within leading directories"
Signed-off-by: Elijah Newren
Commit be8a84c52669 ("[
dir.c](https
://github.com/git/git/blob/a2b13367fe55bdeb10862f41aff3e2446b63e171/dir.c): make 'git-status --ignored
' work within leading directories", 2013-04-15, Git v1.8.3-rc0 -- merge) noted that
git status --ignored <SOMEPATH>
would not list ignored files and directories within <SOMEPATH>
if <SOMEPATH>
was untracked, and modified the behavior to make it show them.
However, it did so via a hack that broke consistency; it would show paths under <SOMEPATH>
differently than a simple
git status --ignored | grep <SOMEPATH>
would show them.
A correct fix is slightly more involved, and complicated slightly by this hack, so we revert this commit (but keep corrected versions of the testcases) and will later fix the original bug with a subsequent patch.
Some history may be helpful:
A very, very similar case to the commit we are reverting was raised in commit 48ffef966c76 ("ls-files
: fix overeager pathspec optimization", 2010-01-08, Git v1.7.0-rc0 -- merge); but it actually went in somewhat the opposite direction.
In that commit, it mentioned how
git ls-files -o --exclude-standard t/
used to show untracked files under t/
even when t/
was ignored, and then changed the behavior to stop showing untracked files under an ignored directory.
More importantly, this commit considered keeping this behavior but noted that it would be inconsistent with the behavior when multiple pathspecs were specified and thus rejected it.
The reason for this whole inconsistency when one pathspec is specified versus zero or two is because common prefixes of pathspecs are sent through a different set of checks (in treat_leading_path()
) than normal file/directory traversal (those go through read_directory_recursive()
and treat_path()
).
As such, for consistency, one needs to check that both codepaths produce the same result.
Revert commit be8a84c526691667fc04a8241d93a3de1de298ab, except instead of removing the testcase it added, modify it to check for correct and consistent behavior.
和:
dir
: 修复对公共前缀目录的检查
签名:Elijah Newren
许多年前,目录遍历逻辑有一个优化,它总是会递归到所有路径规范的公共前缀目录,而不需要遍历前导目录以进入所需的目录。
因此,
git ls-files -o .git/ # 情况 A
会注意到.git/
是所有路径规范的公共前缀(因为它是唯一列出的路径规范),然后遍历它并开始显示该目录下的未知文件。
不幸的是,.git/
不是我们应该遍历的目录,这使得这个优化变得有问题。
这也影响了像:
git ls-files -o --exclude-standard t/ # 情况 B
其中t/
在.gitignore
文件中,因此不重要,不应递归进入。
它还影响了像:
git ls-files -o --directory untracked_dir/
其中untracked_dir/
确实未被跟踪,因此很有趣,但--directory
标志意味着我们只想显示目录本身,而不是递归进入并开始列出其下的未跟踪文件。
情况B类错误在提交16e2cfa90993 ("read_directory()
: further split treat_path()
", 2010-01-08)和48ffef966c76 ("ls-files
: fix overeager pathspec optimization", 2010-01-08, Git v1.7.0-rc0 -- merge)中得到了注意和修复,其思想是我们首先要检查公共前缀是否有趣。
前一个补丁指出,在检查公共前缀时不能使用treat_path()
,因为treat_path()
需要一个dir_entry()
,而我们在检查公共前缀时还没有读取任何目录。
因此,该补丁从treat_path()
中分离出treat_one_path()
。
后一个补丁创建了一个新的treat_leading_path()
,手动复制了treat_path()
的一些位,这些位无法分解,然后对其余部分调用treat_one_path()
。
这种方法有三个问题:
treat_leading_path()
中的重复逻辑意外地错过了特殊路径的检查(例如is_dot_or_dotdot
和匹配".git
"),导致A类错误继续存在。
treat_leading_path()
逻辑假定我们应该遍历任何路径处理不是path_none的内容,即它使C类错误持续存在。
- 它意味着我们需要保持同步的分裂逻辑,这样就有可能出现新的不一致性(例如在commit be8a84c52669中,我们在本系列中撤消了它,或者在commit df5bcdf83ae中,我们将在随后的提交中修复
git status -u
,这个文件会显示出来吗? - Peter Coulton