Git 忽略、排除、假设-未改变

我已经多次阅读了这方面的文档,但仍然不能完全理解这些不同命令之间的区别。也许只有我这么觉得,但是文件应该更清楚一些:

Http://git-scm.com/docs/gitignore

Https://help.github.com/articles/ignoring-files

此外,许多关于这个主题的评论似乎使用了“索引”、“承诺”、“追踪”等词语,这使得这三者之间的区别不那么明显。

我目前(诚然有限)的理解是:

  • .gitignore中匹配的文件将来不会被跟踪。 (尽管它们可能以前被跟踪过)这意味着它们 将永远不会出现在未来的 git status列表修改。 但是,未来的更改仍将与远程回购协议 同步。换句话说,这些文件仍然被“索引”,但是它们没有被“跟踪”。 因为 .gitignore文件位于项目目录中,所以该文件 本身可以进行版本控制

  • .git/info/exclude中匹配的文件也不会被“跟踪” 此外,这些文件将永远不会被远程同步,因此将 这些文件应该是以任何形式提供的,而不应该被其他用户以任何形式看到 是特定于单个用户的编辑器或工作流的。因为它在 .git中 目录下,无法对 exclude文件本身进行版本控制。

  • 运行过 assume-unchanged的文件也不会出现在 git statusgit diff中。这似乎类似于 exclude,因为这些文件既没有“索引”也没有“跟踪”。但是,在 assume-unchanged之前提交的文件的最后版本将对回购中的所有用户保持可见。

我的问题是:

  1. 以上解释正确吗? 请指正。

  2. 如果一个文件已经在提交中,那么什么是函数 在 .exclude中匹配和运行之间的区别 为什么有人喜欢用一种方法 另一个

  3. 我的基本用例是,我希望避免对 已编译的文件,但我仍然希望这些已编译的文件同步 和源文件一起。gitignore文件还会被推送吗?如果没有,如何管理已编译文件的最终部署?

提前谢谢你的帮助。

35462 次浏览

Hopefully, not too many sources of information are using tracked, indexed and committed loosely, since they are all different and meaningful.

  • Indexed means that the file is in the git index. At some point in the past, someone has use git add or an equivalent command on the file. The file is tracked, and might also be committed.
  • Tracked means that git is watching the file for changes. Any committed file, or any file in the index is tracked.
  • Committed means that the file is in git's history. There is at least one checkpoint for this file; you can revert to any committed version of the file.

Now to the limit of my own knowledge. I'm not sure about this definition, but this is my understanding; happy to be corrected about this:

when an indexed file is committed, it is no longer in the index. The next time it is modified (or deleted), it is back in the index. The index is the sum of all tracked files that differ from what's committed.

The index is also called the cache, or the staging area.

On to your main question. .git/info/exclude is the same as .gitignore, just a lower precedence and not in the repository (so, not committed and shared). Neither affects already tracked files. Both affect files that are not currently tracked. Updating .gitignore after git add or git commit is too late; git already tracks the file, and .gitignore won't affect that.

Assume-unchanged affects only tracked files, and thus is completely separate to .gitignore. It can temporarily pretend that the file is untracked and ignored (but it doesn't have to and can also do nothing different from normal behaviour). As other answers mention, this is not used for ignoring changes to files, just for potentially avoiding file system operations on slow file systems.

Re: point 3: you should not add compiled files to git. Compile your files to a different directory that your source is in, and ignore that entire directory. Bundle your compiled files into a library and add it to an artifact repository, but don't put them in git.

I'm going to accept this emailed answer from Junio Hamano (the maintainer of Git) because I think it explains some things more lucidly than the official docs, and it can be taken as "official" advice:

The .gitignore and .git/info/exclude are the two UIs to invoke the same mechanism. In-tree .gitignore are to be shared among project members (i.e. everybody working on the project should consider the paths that match the ignore pattern in there as cruft). On the other hand, .git/info/exclude is meant for personal ignore patterns (i.e. you, while working on the project, consider them as cruft).

Assume-unchanged should not be abused for an ignore mechanism. It is, "I know my filesystem operations are slow. My intention is not to change these paths so I have Git mark them with the 'assume-unchanged' bit. So, Git will not check for changes in these paths every time I ask for 'git status' output". It does not mean anything other than that. Especially, Git does not promise to always consider that these paths are unmodified. If Git can determine any of these paths have changed without incurring extra lstat(2) cost, it reserves the right to mark them as modified. As a result, "git commit -a" will commit that change.

I think the difference of .gitignore and assume-unchanged are

  1. .gitignore can be shared with other people in the team but assume-unchanged has to be configured for each member individually.

  2. assume-unchanged are tracked files. It is very useful if a file has configuration information but can be modified by the team. If a file is set as assume-unchanged but changed by other people and pushed to the remote repository, git will remind when try to pull from the remote.

Adding to Junio Hamano's answer, Git 2.3.0 (February 2015) now removes from the gitignore documentation

To ignore uncommitted changes in a file that is already tracked, use 'git update-index --assume-unchanged'.

See commit 936d2c9 from Michael J Gruber (mjg):

gitignore.txt: do not suggest assume-unchanged

git-update-index --assume-unchanged was never meant to ignore changes to tracked files (only to spare some stats).
So do not suggest it as a means to achieve that.