572

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

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

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

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

4

2 回答 2

824

你想要skip-worktree

assume-unchanged专为检查一组文件是否已被修改的情况而设计;当您设置该位时,git(当然)假定与索引的该部分对应的文件在工作副本中没有被修改。所以它避免了混乱的stat电话。每当索引中的文件条目发生更改时(因此,当文件在上游更改时),该位都会丢失。

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

此处对这种差异的影响和典型用例进行了很好的总结:http: //fallengamer.livejournal.com/93321.html

从那篇文章:

  • --assume-unchanged假定开发人员不应该更改文件。此标志旨在提高SDK 等不更改文件夹的性能。
  • --skip-worktree当您指示 git 永远不要触摸特定文件时很有用,因为开发人员应该更改它。例如,如果上游的主存储库托管了一些生产就绪的配置文件,并且您不想意外提交对这些文件的更改,这--skip-worktree正是您想要的。
于 2012-11-29T17:39:42.173 回答
135

注意:fallgamer在 2011 年进行了一些测试(因此它们可能已经过时),以下是他的发现

运营

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

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

  • 没有本地更改,上游文件已更改 这两个标志都不会阻止您获取上游更改。Git 检测到你违背了承诺,并选择通过重置标志来反映现实。
    git pull
    assume-unchanged
    • 带有assume-unchanged标志的文件:内容已更新,标志丢失。
      '<code>git ls-files -v' 将显示该标志已修改为H(from h)。
    • 带有skip-worktree标志的文件:更新内容,保留标志。
      '<code>git ls-files -v' 将显示Spull.

  • 随着本地文件的更改 ,Git 不会触及文件并反映文件的现实(承诺不变的文件实际上已更改)。
    git reset --hard
    skip-worktreeassume-unchanged
    • 带有assume-unchanged标志的文件:文件内容被还原。标志重置为H(从h)。
    • skip-worktree标志的文件:文件内容完好无损。标志保持不变。

他补充了以下分析:

  • 看起来skip-worktree正在努力保存您的本地数据。但是,如果它是安全的,它不会阻止您获取上游更改。另外 git 不会在pull.
    但是忽略 '<code>reset --hard' 命令对开发人员来说可能是一个令人讨厌的惊喜。

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

看:

他总结道:

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

  • assume-unchanged假定开发人员不应该更改文件。如果一个文件被改变了——那么这个改变并不重要。此标志旨在提高 SDK 等不更改文件夹的性能。
    但是如果承诺被破坏并且文件实际上被更改,git 会恢复标志以反映现实。可能在通常不打算更改的文件夹中有一些不一致的标志是可以的。

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


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

请参阅提交 7a2dc95提交 1b13e90(2020 年 1 月 22 日),作者是brian m。卡尔森 ( bk2204) .
(由Junio C Hamano 合并gitster——提交 53a8329中,2020 年 1 月 30 日)
Git 邮件列表

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

签字人:Jeff King
签字人:brian m. 卡尔森

用户想要忽略 Git 跟踪的文件的更改是很常见的。

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

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

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

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

由于这不是受支持的配置,并且用户很容易将现有功能误用于非预期目的,从而导致普遍的悲伤和困惑,让我们在文档中记录现有行为和陷阱,git update-index以便用户知道他们应该探索替代解决方案。

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

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

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

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

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

于 2014-05-22T12:36:12.897 回答