Git - Difference Between '和& # 39;skip-worktree& # 39;

我对一个文件进行了本地更改,但不想提交到存储库中。这是一个用于在服务器上构建应用程序的配置文件,但我想在本地使用不同的设置构建应用程序。当然,文件总是显示当我做'git状态'作为要上演的东西。我希望隐藏这个特定的更改,而不提交它。我不会对该文件做任何其他更改。

澄清一下,使用.gitignore并不是我想要的,因为它只会阻止添加新文件。我希望忽略对存储库中已经存在的文件的更改。

经过一番挖掘,我看到了2个选项:assume-unchangedskip-worktree。之前的一个问题在这里谈到了它们,但并没有真正解释它们的区别。

这两个命令有什么不同?为什么会有人用其中一种呢?

115462 次浏览

你想要skip-worktree

assume-unchanged是为检查一组文件是否被修改的代价昂贵的情况而设计的;当您设置位时,git(当然)假设索引的那一部分对应的文件在工作副本中没有被修改。因此它避免了stat调用的混乱。当索引中的文件条目发生变化时(因此,当文件在上游发生变化时),这个位就会丢失。

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

这里很好地总结了这种差异的后果和典型用例:http://fallengamer.livejournal.com/93321.html

从那篇文章中:

  • --assume-unchanged假设开发人员不应该更改了一个文件。这个标志是针对提高性能的不可更改文件夹,比如sdk。
  • --skip-worktree是很有用的,当你指示git不要碰一个特定的文件,因为开发人员应该改变了它。例如,如果主存储库上游托管了一些可用于生产的配置文件,并且您不希望意外地向这些文件提交更改,那么--skip-worktree正是您想要的。

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

操作

  • 文件在本地存储库和上游
    中都被更改 # EYZ1: < br > Git无论如何都会保留本地更改 因此,您不会意外地丢失使用任何标志标记的任何数据。
    • 带有assume-unchanged标志的文件:Git不会覆盖本地文件。相反,它将输出冲突和如何解决冲突的建议
    • 带有skip-worktree标志的文件:Git不会覆盖本地文件。相反,它将输出冲突和如何解决冲突的建议
    • 李< / ul > < / >

    • 文件在本地存储库和上游都被改变了,无论如何都试图拉
      # EYZ1 < br > # EYZ1 < br > 使用skip-worktree会导致一些额外的手工工作,但如果您有任何本地更改,至少不会丢失任何数据。
      • 带有assume-unchanged标志的文件:丢弃所有本地更改,不可能恢复它们。效果就像“git reset --hard”。' git pull '调用将成功
      • 带有skip-worktree标志的文件:Stash将无法在skip-worktree文件上工作。' git pull '将失败,并出现与上面相同的错误。开发人员被迫手动重置skip-worktree标志,以便能够隐藏和完成失败的pull
      • 李< / ul > < / >

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

        • 与本地文件更改
          # EYZ1 < br > Git不会触及skip-worktree文件,而是反映了assume-unchanged文件的实际情况(承诺不会改变的文件实际上已经改变了)。
          • assume-unchanged标志的文件:恢复文件内容。标志被重置为H(从h)。
          • 带有skip-worktree标志的文件:文件内容完好无损。旗帜保持不变。
          • 李< / ul > < / >

          他补充了以下分析:

            看起来skip-worktree非常努力地保存本地数据。但如果安全的话,它不会阻止您进行上游更改。另外,git不会重置pull上的标志 但是忽略' reset --hard'命令可能会成为一个令人讨厌的惊喜
          • Assume-unchanged标志可能会在pull操作中丢失,而这些文件中的本地更改对git来说似乎并不重要。

          看到的:

          他的结论是:

          # EYZ0。

          • assume-unchanged假设开发人员不应该更改文件。如果一个文件被改变了,那么这个改变并不重要。该标志用于提高不可更改文件夹(如sdk)的性能 但如果承诺被打破,文件实际上被更改了,git将恢复标志以反映实际情况。在通常不打算更改的文件夹中有一些不一致的标志可能是可以的。李< / p > < / > 另一方面,当你指示git永远不要碰某个特定文件时,skip-worktree是有用的。这对于已经跟踪的配置文件很有用 上游主存储库拥有一些可用于生产的配置,但您希望更改配置中的一些设置,以便能够进行一些本地测试。您不希望意外地检查该文件中的更改以影响生产配置。在这种情况下,skip-worktree是完美的场景。李< / p > < / >


          在Git 2.25.1(2020年2月)中,上面提到的“实际上两个标志都不够直观”得到了进一步的澄清:

          参见提交7 a2dc95提交1 b13e90 (22 Jan 2020) by 布莱恩·m·卡尔森(bk2204) # EYZ1 < br > (# EYZ0) < / p >

          doc:劝阻用户不要试图忽略被跟踪的文件

          < p > # EYZ0 < br > 署名:brian m. carlson

          对于用户来说,忽略Git跟踪的文件更改是很常见的。

          这种情况的常见场景是IDE设置和配置文件,它们通常不应该被跟踪,并且可能使用模板机制从被跟踪的文件生成。

          然而,用户了解了假设不变和跳过工作树的部分,并尝试使用它们来完成这一点。

          这是有问题的,因为当这些位被设置后,许多操作会像用户期望的那样进行,但是当git checkout需要替换一个文件时,它们通常不起作用。

          在这种情况下,没有合理的行为,因为有时数据是宝贵的,例如某些配置文件,而有时是用户乐于丢弃的不相关数据。

          由于这不是一个受支持的配置,用户很容易出于意想不到的目的滥用现有功能,导致普遍的悲伤和困惑,让我们在git update-index的文档中记录现有的行为和缺陷,以便用户知道他们应该探索替代解决方案。

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

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

          用户通常尝试使用assume-unchangedskip-worktree位来告诉Git忽略被跟踪的文件的更改。 这并不像预期的那样工作,因为Git在执行某些操作时仍然会根据索引检查工作树文件。 一般来说,Git没有提供一种方法来忽略对跟踪文件的更改,因此建议使用替代解决方案 例如,如果您想要更改的文件是某种类型的配置文件,存储库可以包含一个示例配置文件,然后可以将其复制到忽略的名称中并进行修改。 存储库甚至可以包含一个脚本,将示例文件视为模板,自动修改和复制它

          最后一部分就是我所描述的典型的基于涂抹/清除脚本的内容过滤器驱动程序

使用跳跃式工作树如下:

git update-index --skip-worktree changedfile.txt

确认文件状态:

 git ls-files -v
S changedfile.txt

第一个字母S表示文件被标记为skip-worktree选项

原因:

"git-update-index——assume-unchanged绝不意味着忽略变化 到被跟踪的文件(只是为了节省一些统计数据)。所以不要把它说成

看到:# EYZ0

——skip-worktree解释道:

该选项忽略对已被跟踪的文件的更改。Git总是使用索引中的文件内容和属性,而不管对工作目录中的文件做了什么修改。 这允许您对不想推送到上游的文件进行更改。 使用此选项,如上所示

要取消设置这个选项,使用--no-skip-worktree,如下所示:

git update-index --no-skip-worktree changedfile.txt

——assume-unchanged解释道:

这个选项是专门为检查某些文件是否被修改是资源密集型的用例而设计的。 例如,为了优化慢速文件系统上的资源使用,git不会检查文件是否有问题,它假设工作目录中的文件没有被修改。 当索引中的文件条目发生变化时,该标志将丢失。例如,当文件被上游修改时

它的用法如下:

git update-index --assume-unchanged changedfile.txt

确认文件状态:

git ls-files -v
h changedfile.txt

第一个字母h表示文件被标记为假设不变选项 要取消设置该选项,使用–no-assume-unchanged,如:

git update-index --no-assume-unchanged changedfile.txt