解释一下哪条gitignore规则忽略了我的文件

有什么方法可以看到为什么一些文件被git忽略(即.gitignore文件中的哪个规则导致文件被忽略)?

假设我有这样(或者一个更复杂的场景,有数百个文件夹和数十个.gitignore文件:

/
-.gitignore
-folder/
-.gitignore
-subfolder/
-.gitignore
-file.txt

如果我运行git add folder/subfolder/file.txt, git可能会抱怨它被忽略:

The following paths are ignored by one of your .gitignore files:
folder/subfolder/file.txt
Use -f if you really want to add them.

有没有办法知道所有可能的.gitignore中有一个规则来忽略这个文件,并显示该规则?如:

The following paths are ignored by your folder/.gitignore file (line 12: *.txt)
folder/subfolder/file.txt
Use -f if you really want to add them.

或者是:

$ git why-is-ignored folder/subfolder/file.txt
folder/.gitignore:12:*.txt
58431 次浏览

我在手册页中找不到任何东西,但这里有一个快速和肮脏的脚本,它将检查每个父目录下的文件,看看它是否可以被git-add'ed。在包含问题文件的目录中运行它:

test-add.sh STOP_DIR FILENAME

其中STOP_DIR是Git项目的顶级目录,FILENAME是问题文件名(没有路径)。它在层次结构的每一层都创建一个同名的空文件(如果它不存在),并尝试git add -n来查看是否可以添加它(它在自己之后清理)。它输出如下内容:

FAILED:    /dir/1/2/3
SUCCEEDED: /dir/1/2

脚本:

#!/usr/bin/env bash
TOP=$1
FILE=$2
DIR=`pwd`
while : ; do
TMPFILE=1
F=$DIR/$FILE
if [ ! -f $F ]; then
touch $F
TMPFILE=0
fi
git add -n $F >/dev/null 2>&1
if [ $? = 0 ]; then
echo "SUCCEEDED: $DIR"
else
echo "FAILED:    $DIR"
fi
if [ $TMPFILE = 0 ]; then
rm $F
fi
DIR=${DIR%/*}
if [ "$DIR" \< "$TOP" ]; then
break
fi
done
git check-ignore -v filename

更多细节参见手册页

原答案如下:

Git目前还没有提供类似的功能。但在看到你的问题后,我做了一些谷歌搜索,发现早在2009年这个特性是被要求的,并且部分实现了。在看完帖子后,我意识到要把它做好并不需要太多的工作,所以我已经开始了一个补丁的工作,希望能在接下来的一两天内完成。当这个答案准备好时,我会更新它。

哇,这比我想象的难多了。git的排除处理的内部是相当神秘的。不管怎样,这里是几乎完成了一系列提交,它适用于今天的上游master分支。测试套件已经完成了99%,但我还没有完成--stdin选项的处理。希望这个周末我能做到,然后把我的补丁提交到git邮件列表中。

与此同时,我非常欢迎任何能够这样做的人进行测试-只需从我的git克隆,检查check-ignore分支,并正常编译它。

结束了!最新版本是在github如上所述,我有将补丁系列提交到git邮件列表同行评审。让我们看看他们是怎么想的……

更新3:经过几个月的黑客/补丁审查/讨论/等待,我很高兴能够说这个特性现在已经到达git的master分支,并将在下一个版本中可用(1.8.2,预计2013年3月8日)。这里是check-ignore手册页。哇,工作量比我想象的要大得多!

更新4:如果你对这个答案如何演变以及该功能如何实现的完整故事感兴趣,请查看GitMinutes播客第32集

更新git 2.8(2016年3月):

GIT_TRACE_EXCLUDE=1 git status

参见“一种验证.gitignore文件的方法

这是对下面描述的git check-ignore -v的补充。


原答案:2013年9月(git 1.8.2,然后是1.8.5+):

< >强git check-ignore < / >强git 1.8.5/1.9(2013年第四季度)中再次改进:

"git check-ignore"遵循与"git add"和"git status"相同的规则,即忽略/排除机制不会对已经跟踪的路径生效 使用"--no-index"选项,它可以用来诊断哪些应该被忽略的路径被错误地添加到索引中。

参见https://github.com/flashydave中的提交8231年fa6:

check-ignore当前显示了.gitignore规则如何处理未跟踪的路径。被跟踪的路径不会产生有用的输出 这可以防止调试路径被意外跟踪的原因,除非该路径被意外跟踪 第一次从索引中删除git rm --cached <path>.

选项--no-index告诉命令绕过索引中路径的检查,因此也允许检查跟踪的路径。

虽然这种行为偏离了git addgit status的特征,但它的用例不太可能引起任何用户混淆。

测试脚本被增强来检查这个选项是否符合标准忽略,以确保正确的行为。


--no-index::

检查时不要查看索引

  • 调试为什么路径被例如git add .跟踪,而没有被用户期望的规则忽略
  • 当开发包含否定的模式以匹配先前用git add -f添加的路径时。

添加到使用git check-ignore -v filename的主要答案(谢谢BTW) 我发现我的.gitignore文件阻塞了一切,因为在通配符后面有一个换行符,所以我有:

< p > <代码> * .sublime-project < /代码> < / p >

举个例子。我只是移除了换行符,瞧!它是固定的。

上下文:我有一个非常相似的问题,我找不到什么规则忽略我的文件/文件夹。我尝试了
git check-ignore -v filename
,但它没有给我任何结果,或者结果是我的.gitignore文件中的空行号。所以问题是我的文件没有被我的本地。gitignore文件忽略,但由我的本地核心。Excludesfile(它没有包含在我的存储库中)。

解决方案:我用这个命令寻找文件的位置:
git config core.excludesfile
,然后我打开它并删除了有问题的行,就是这样。

参考:你也可以查看在这里以获得更多的解释。

它可能不是.gitignore - 3可能忽略的原因

文件可能会被忽略,原因如下:

  1. .gitignore
  2. git update-index --skip-worktree
  3. git update-index --assume-unchanged

此外,如果一个文件在.gitignore中并且已经在索引/缓存中暂存,则该文件可能被unignore。

检查上述列举的情况:

  1. 对于.gitignore排除的两种情况,比较输出:

    • git check-ignore --verbose --non-matching --no-index file1 file2 file3
    • git check-ignore --verbose --non-matching file1 file2 file3
  2. < p > git ls-files file1 file2 file3 | grep -E '^S'

  3. < p > git ls-files file1 file2 file3 | grep -E '^[[:lower:]]'

太难了,给我个别名!

以下别名将涵盖上述所有情况:

ignore = !"bash -c 'diff --unified=999999999 --color=always <(echo a; git check-ignore --verbose --non-matching --no-index . \"$@\") <(echo b; git check-ignore --verbose --non-matching . \"$@\")' - \"$@\" | tail -n+7; git hidden \"$@\" # Show ignore status of arguments. Files included by index are tagged with prepended '+'."
hidden = !"git ls-files -v -- \"$@\"| grep -E '^(S|[[:lower:]])' # S means update-index --skip-worktree, and lower first letter means --assume-unchanged."

注释和结尾"是要复制到你的.gitconfig的行中的一部分。

用法:

git ignore file1 file2 file3