有什么方法可以看到为什么一些文件被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

我在手册页中找不到任何东西,但这里有一个快速和肮脏的脚本,它将检查每个父目录下的文件,看看它是否可以被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的排除处理的内部是相当神秘的。不管怎样,这里有一个几乎完成的提交系列,它适用于今天的上游主分支。测试套件已经完成了99%,但是我还没有完成——stdin选项的处理。希望这个周末我能做到,然后把我的补丁提交到git邮件列表中。

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

更新2:完成了!最新版本是在github如上所述,我已经提交补丁系列到git邮件列表进行同行评审。让我们看看他们是怎么想的……

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

更新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:中的commit 8231fa6

check-ignore currently shows how .gitignore rules would treat untracked paths. Tracked paths do not generate useful output. This prevents debugging of why a path became tracked unexpectedly unless that path is first removed from the index with git rm --cached <path>. The option --no-index tells the command to bypass the check for the path being in the index and hence allows tracked paths to be checked too. Whilst this behaviour deviates from the characteristics of git add and git status its use case is unlikely to cause any user confusion. Test scripts are augmented to check this option against the standard ignores to ensure correct behaviour.


--no-index::

检查时不要查索引。 可以使用: 调试为什么一个路径被跟踪,例如git add。并没有像用户所期望的那样被规则忽略 当开发包含否定的模式以匹配之前用git添加的路径时,添加-f。


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

* .sublime-project

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


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

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

参考:你也可以看一下这里的额外解释。


它可能不是。gitignore——3个可能被忽略的原因

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

.gitignore Git update-index——skip-worktree Git update-index——assume-unchanged

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

检查上述列举的情况:

对于.gitignore排除的两种情况,比较以下输出: Git check-ignore——verbose——non-matching——no-index file1 file2 file3 Git check-ignore——verbose——不匹配file1 file2 file3 | grep -E '^S' 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