我经常发现自己处于这种情况:
- 我在分支Foo工作,它有整个被忽略文件的文件夹,这些文件在分支Bar中不存在
- 我结账去酒吧做其他工作
- 我在我的工作副本中看到了数千个新的/未跟踪的文件,这些文件在分支Foo中被git忽略,但在分支Bar中没有
- 如果在酒吧工作期间,我尝试使用stash,它会把所有这些文件都拉进去——这会让我隐藏的更改无法读取(而且速度真的很慢)
虽然我可以为这些文件夹添加git忽略,但这些文件夹甚至不存在于Foo之外,所以这看起来很尴尬。
git还有其他解决方案吗?理想情况下,这些文件只有在使用它们的分支被签出时才会出现,但我不想git添加它们,因为它们太多,而且修改太频繁;这会让git慢到爬行。这就像我希望他们在分支中表现得好像git被忽略了一样,而在不被忽略的时候,他们会被藏起来。
Git从.gitignore
:以外的文件读取忽略模式
.git/info/exclude
中的模式将在该存储库中检出的任何分支中被忽略~/.config/git/ignore
中的模式将在系统范围内被忽略
将.gitignore
从分支Foo
复制到其中一个位置将导致在签出Bar
时忽略这些文件。
您还可以考虑仅将分支Foo
的.gitignore
合并到分支Bar
中。
分支——或者更准确地说,分支名称——在这里基本上是不相关的。所有重要的是提交。一个分支名称用于查找一个特定的提交,但两个或多个分支名称可以标识同一个提交。
git还有其他解决方案吗?
这里可以使用多种方法。如果你的Git版本至少是2.5(最好是2.15),我建议你从git worktree
开始。但首先,让我们用一些特定于Git的术语来详细定义这个问题,这样解决方案本身就有意义了。
理想情况下,文件只有在使用它们的分支被签出时才会出现。。。
Git也不是关于文件的,当然你需要文件来完成工作。但是,在工作树或的工作树it中都不是,这一点非常重要。提交(在Git中是)包含文件,但格式特殊、只读、压缩和消除重复。只读文件不会让你完成工作,除非工作从不写入任何文件;但是由于提交的文件是只使用Git的格式,您可能也无法让软件读取它们。
因此,要使用Git,您需要Git将其文件以冻干、压缩和消除重复的格式复制到普通的日常读/写文件中。这些读/写文件在您的工作树中。签出特定提交的行为(通常通过分支名称)会选择该特定提交作为当前提交。Git将提交的文件复制到您的工作树中,以便您可以查看和使用它们。
因为你的工作树是你的,所以你可以创建许多在提交中不是的文件,通过将它们列在.gitignore
文件或类似文件中,你可以告诉Git两件事:
- 不要抱怨这些所谓的未跟踪文件;以及
- 不要将它们添加到Git的索引或暂存区
索引/暂存区——同一事物的两个术语——是Git如何进行新的提交:从复制到Git索引中的预冻干文件。git add
命令告诉Git:制作该工作树文件的冻干/去复制副本,并将其放入索引中1
当然,主.gitignore
文件本身通常是提交的,所以您的工作树中的那个文件来自当前提交。如果随后切换到具有不同提交的.gitignore
文件的不同提交,Git将用工作树副本替换其他提交的副本。当然,这会更改发生上述两个操作的文件集。
1注意,重复数据消除意味着索引实际上从未包含文件的副本。相反,它保存文件名和文件内容的blob散列ID。如果内容与任何现有的已提交文件匹配;复制";最初,当Git从您选择的提交中填充其索引时,这些文件都已经消除了重复,因此索引只列出了要进入下一次提交的文件。git commit
就是这样工作的:它只是在运行git commit
时打包索引中的列表。
还要注意,git add
实际上意味着使索引副本与工作树副本匹配。特别是,如果删除了工作树副本,git add
将删除索引副本。(或者,您可以使用git rm
同时删除两个副本,因此不需要git add
删除的文件就可以让Git看到删除。)
溶液1:git worktree add
Git存储库带有一个默认的工作树2但是,您可以使用git worktree add
添加更多工作树,至少从Git 2.5版本开始。每个工作树都有自己的索引。
在主/默认工作树之外有一个单独的工作树,意味着您可以签出多个分支。由于每个工作树是独立的,因此工作树W1中的任何未跟踪(忽略或不忽略)文件都不会以任何方式影响工作树W2中的任何已跟踪文件。因此,整个问题就消失了:使用主工作树W1处理主分支B1,使用添加的工作树W2处理分支B2。如果你需要在更多的树枝上工作,继续添加更多的工作树。
当你完成一个工作树时,只需删除它。你可以手动删除它并使用git worktree prune
,或者如果你的git worktree
有子命令,则使用git worktree remove
。请注意,Git 2.5中的git worktree
中有一个相当严重的错误,直到Git 2.15才修复,如果您让添加的工作树闲置超过两周,可能会导致数据丢失。我建议升级Git版本,但创建工作树,完成所有工作,然后在两周内将其删除就足够了,或者您可以使用git config
将最小对象修剪保护期限gc.pruneExpire
从默认的2周值提高,以延长保护时间。
2一个bare存储库省略了工作树。不过,我们不会在这里讨论这一点。
.git/info/exclude
除了工作树中的.gitattributes
文件外,Git还将读取并遵守.git/info/exclude
中的排除。此文件在任何提交中都不是--不能是;Git不会将.git
中的文件添加到提交中——因此,无论您签出了哪一个提交,您都可以在此处列出未经处理的文件,并忽略它们。
git clean
git clean
命令具有删除未跟踪文件(-x
或-X
)的选项。在切换到其他分支之前使用这些将删除构建产品等小心使用这些选项因为未跟踪的文件不在Git中——根据定义,未跟踪文件不在Git的索引中,因此不会在下一次提交中——因此无法使用Git恢复。
git stash -u
或git stash -a
git stash
命令可以被告知进行三提交存储,而不是通常的两提交存储,其中第三提交保存未跟踪但未被忽略的文件(-u
)或所有未跟踪的文件(即使被忽略)(-a
)。一旦git stash
进行了第三次提交,它将使用git clean
或等效方法删除在第三次交付中保存的文件。
我不喜欢这种方法,因为恢复一个三提交存储需要有问题的工作树是";"干净";,即不包含在该第三提交中的任何文件。使用git stash push -a
来保存构建产品,更改一些事情(包括制作需要大量时间和/或精力的构建产品和配置文件),尝试使用git stash apply
来恢复保存的产品,然后使用git clean
进行清理,使git stash apply
能够工作,这太容易了。。。结果发现您刚刚清理的一个文件是新,并且不在保存的存储库中,现在需要花费大量时间和/或精力来重新构建它。