Git-“假设不变”和“跳过工作树”之间的区别


450

我对不想提交到存储库的文件进行了本地更改。它是用于在服务器上构建应用程序的配置文件,但是我想在本地使用不同的设置进行构建。自然地,当我执行“ git status”作为要上演的内容时,文件总是显示出来。我想隐藏此特定更改而不提交。我不会对该文件进行任何其他更改。

经过一些挖掘之后,我看到两个选项:“假定不变”和“跳过工作树”。这里的上一个问题讨论了它们,但并没有真正解释它们之间的差异。我的问题是:这两个命令有何不同?为什么有人要使用另一个?


1
通常我.gitignore用于类似目的。该解决方案对您有用吗?
samuil 2012年

45
samuil,.gitignore忽略添加,而不更改。当文件已经在git中时,如果它在.gitignore中列出,它将被跟踪事件
Grigory

但是一个人不能删除所有内容并添加所有内容以便“刷新”,如此处所述吗?stackoverflow.com/questions/7075923/…@格里高里
丹尼尔·斯普林格

1
如果我正确理解了OP的意图,则不应忽略该文件。该文件必须位于存储库中,但是至少应该不提交他已经进行的这些非常具体的更改。
西蒙妮

Answers:


666

你要skip-worktree

assume-unchanged用于检查一组文件是否已被修改的开销很大的情况;当您设置该位时,git(当然)假定与索引的该部分相对应的文件尚未在工作副本中被修改。这样可以避免一团糟stat。只要索引中的文件条目发生更改(因此,当文件在上游更改时),该位就会丢失。

skip-worktree不仅如此:即使git 知道文件已被修改(或需要用a reset --hard或类似方法修改),它也会假装它没有被修改,而是使用索引中的版本。这一直持续到索引被丢弃为止。

这里有一个很好的总结,介绍了这种差异的后果以及典型的用例:http : //fallengamer.livejournal.com/93321.html

从那篇文章:

  • --assume-unchanged假定开发人员不应更改文件。该标志旨在提高未更改的文件夹(如SDK)的性能。
  • --skip-worktree当您指示git永远不要触摸特定文件时很有用,因为开发人员应该更改它。例如,如果上游主存储库托管了一些生产就绪的配置文件,而您又不想意外地将更改提交到这些文件,--skip-worktree则正是您想要的。

3
这就说得通了。跳过工作树确实确实是要走的路。谢谢!
ckb

99
小注释可节省几秒钟的搜索和阅读时间。要取消--skip-worktree效果并取消设置标志,可以使用--no-skip-worktree选项。工作原理完全相同。如果手滑了并且标记了错误的文件,或者情况发生了变化并且以前跳过的文件不应该再被忽略,则这很有用。
drdaeman 2015年

18
为了回答我上面的问题,使用--skip-worktree.git/info/exclude文件之间的区别在于,前者甚至可以用于当前跟踪的文件。.git/info/exclude就像一样.gitignore,只会防止意外地将未跟踪的文件添加到索引,而不会更改已经跟踪的文件。
LinusR 2015年

13
可以将其推送到远程并由所有克隆保留吗?
CMCDragonkai '16

4
刚刚使用,小姐git update-index --skip-worktree <file_name>
鲁芬

108

注意:fallengamer在2011年做了一些测试(所以它们可能已经过时了),这是他的发现

运作方式

  • 文件在本地存储库和上游都被更改
    git pull
    Git仍然保留本地更改。
    因此,您不会意外丢失用任何标志标记的任何数据。
    • 带有assume-unchanged标志的文件:Git不会覆盖本地文件。相反,它将输出冲突并提供解决方案的建议
    • 带有skip-worktree标志的文件:Git不会覆盖本地文件。相反,它将输出冲突并提供解决方案的建议

  • 在本地存储库和上游都更改了文件,尝试以任何方式进行拉动。 使用结果需要进行一些额外的手动工作,但是至少如果您进行了任何本地更改,您也不会丢失任何数据。
    git stash
    git pull
    skip-worktree
    • assume-unchanged标志的文件:丢弃所有本地更改,没有任何可能恢复它们。效果就像' git reset --hard'。“ git pull”调用会成功
    • 带有skip-worktree标志的文件:“隐藏”不适用于skip-worktree文件。“ git pull”将失败,并出现与上述相同的错误。开发人员必须手动重置skip-worktree标志才能存储和完成失败pull

  • 没有本地更改,上游文件已更改 两个标志都不会阻止您获取上游更改。Git检测到您违背了诺言,并选择通过重置标志来反映现实。
    git pull
    assume-unchanged
    • 带有assume-unchanged标志的文件:内容已更新,标志已丢失。
      git ls-files -v”表示标志已修改为H(从h)。
    • 带有skip-worktree标志的文件:内容已更新,标志已保留。
      ' git ls-files -v将显示与S之前相同的标志pull

  • 更改了本地文件后, Git不会触摸文件并反映文件的实际情况(实际上承诺更改为不变的文件已更改)。
    git reset --hard
    skip-worktreeassume-unchanged
    • 带有assume-unchanged标志的文件:文件内容已还原。标志重置为H(从h)。
    • 带有skip-worktree标志的文件:文件内容完整无缺。标志保持不变。

他添加了以下分析:

  • 看起来skip-worktree很努力维护您的本地数据。但这并不会阻止您在安全的情况下进行上游更改。再加上git不会将标志重置为pull
    但是,reset --hard对于开发人员而言,忽略' '命令可能会成为一个令人讨厌的惊喜

  • Assume-unchanged可能会丢失该标志,pull并且此类文件内的本地更改对git似乎并不重要。

看到:

他得出结论:

实际上,两个标志都不足够直观

  • assume-unchanged假设开发人员不应该更改文件。如果文件已更改–那么该更改并不重要。该标志旨在提高未更改的文件夹(如SDK)的性能。
    但是,如果没有兑现承诺,并且实际上已更改了文件,则git会将标志还原以反映实际情况。在通常不希望更改的文件夹中有一些不一致的标志可能是可以的。

  • 另一方面skip-worktree,当您指示git永远不要触摸特定文件时,它很有用。这对于已经跟踪的配置文件很有用。
    上游主存储库托管一些可用于生产的配置,但是您希望更改配置中的某些设置以能够进行一些本地测试。而且您不想意外检查此类文件中的更改以影响生产配置。在这种情况下,skip-worktree制作完美的场景。


在Git 2.25.1(2020年2月)中,上述“实际上两个标记都不足够直观”进一步阐明:

参见brian m的commit 7a2dc95commit 1b13e90(2020年1月22日)。卡尔森(bk2204
(由Junio C gitsterHamano合并--commit 53a8329中,2020年1月30日)
Git邮件列表

doc:阻止用户尝试忽略跟踪的文件

签字人:杰夫·金
签字人:brian m。卡尔森

用户通常会忽略对Git跟踪的文件所做的更改。

这种情况的常见情况是IDE设置和配置文件,通常不应使用模板机制对它们进行跟踪,而应该从跟踪的文件中生成它们。

但是,用户了解假设不变和跳过工作树位,并尝试使用它们来执行此操作。

这是有问题的,因为设置这些位后,许多操作会按照用户期望的方式运行,但是当git checkout需要替换文件时,它们通常无济于事。

在这种情况下,没有明智的行为,因为有时数据是宝贵的,例如某些配置文件,有时用户会乐意丢弃无关紧要的数据。

由于这不是受支持的配置,并且用户容易出于意料之外的目的滥用现有功能,从而引起普遍的悲伤和困惑,因此,让我们在文档中记录现有行为和陷阱,git update-index以便用户知道他们应该探索替代解决方案。

另外,由于在许多环境中成功使用了众所周知的方法,因此让我们提供一种推荐的解决方案来处理配置文件的常见情况。

git update-index手册页现在包括:

用户经常尝试使用assume-unchangedskip-worktree位来告诉Git忽略对跟踪文件的更改。这不能按预期方式工作,因为在执行某些操作时,Git可能仍会根据索引检查工作树文件。通常,Git不提供忽略跟踪文件更改的方法,因此建议使用替代解决方案。

例如,如果要更改的文件是某种配置文件,则存储库可以包含样本配置文件,然后可以将其复制到忽略的名称中并进行修改。该存储库甚至可以包含一个脚本,以将示例文件视为模板,并自动对其进行修改和复制。

最后一部分是我描述的基于污迹/干净脚本的典型内容过滤器驱动程序


7
如果文件上有skip-worktree并且上游发生更改,则即使git status不会将文件报告为已更改,当您尝试拉时也会出现“请提交或隐藏”的消息。您如何避免这种情况,以便在人们对原始设置进行嘲弄时可以保持本地更改?
GreenAsJade 2014年

3
是的,我可以确认您这样做。这意味着拥有一个本地文件,而您只想与原始文件保持不同,仍然非常困难。
GreenAsJade 2014年

1
@GreenAsJade比似乎古老。您是否有可能用2.2.x进行测试?
VonC 2014年

1
@VonC,“ Junio的评论”的链接不在修订历史记录中。是这个你指的是什么?
Michael-Clay Shirky在哪里,

1
@迈克尔好抓住,谢谢。我把那个链接放回了答案。
VonC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.