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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13630849/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 15:00:05  来源:igfitidea点击:

Git - Difference Between 'assume-unchanged' and 'skip-worktree'

gitgit-index

提问by ckb

I have local changes to a file that I don't want to commit to my repository. It is a configuration file for building the application on a server, but I want to build locally with different settings. Naturally, the file always shows up when i do 'git status' as something to be staged. I would like to hide this particular change and not commit it. I won't make any other changes to the file.

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

After some digging around, I see 2 options: 'assume-unchanged' and 'skip-worktree'. A previous question heretalks about them but doesn't really explain their differences. My question is this: how are the two commands different? Why would someone use one or the other?

经过一番挖掘,我看到了 2 个选项:“假设不变”和“跳过工作树”。此处的前一个问题讨论了它们,但并没有真正解释它们的差异。我的问题是:这两个命令有何不同?为什么有人会使用其中一种?

回答by Borealid

You want skip-worktree.

你要skip-worktree

assume-unchangedis designed for cases where it is expensive to check whether a group of files have been modified; when you set the bit, git(of course) assumes the files corresponding to that portion of the index have not been modified in the working copy. So it avoids a mess of statcalls. This bit is lost whenever the file's entry in the index changes (so, when the file is changed upstream).

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

skip-worktreeis more than that: even where gitknowsthat the file has been modified (or needs to be modified by a reset --hardor the like), it will pretend it has not been, using the version from the index instead. This persists until the index is discarded.

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

There is a good summary of the ramifications of this difference and the typical use cases here: http://fallengamer.livejournal.com/93321.html.

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

From that article:

从那篇文章:

  • --assume-unchangedassumes that a developer shouldn'tchange a file. This flag is meant for improving performancefor not-changing folders like SDKs.
  • --skip-worktreeis useful when you instruct git not to touch a specific file ever because developers shouldchange it. For example, if the main repository upstream hosts some production-ready configuration filesand you don't want to accidentally commit changes to those files, --skip-worktreeis exactly what you want.
  • --assume-unchanged假定开发人员不应更改文件。此标志旨在提高不更改文件夹(如 SDK)的性能。
  • --skip-worktree当您指示 git 不要触摸特定文件时很有用,因为开发人员应该更改它。例如,如果主存储库上游托管一些生产就绪的配置文件,并且您不想意外地提交对这些文件的更改,这--skip-worktree正是您想要的。

回答by VonC

Note: fallengamerdid some tests in 2011 (so they may be outdated), and here are his findings:

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

Operations

操作

  • File is changed both in local repository and upstream
    git pull:
    Git preserves local changes anyway.
    Thus you wouldn't accidentally lose any data that you marked with any of the flags.
    • File with assume-unchangedflag: Git wouldn't overwrite local file. Instead it would output conflicts and advices how to resolve them
    • File with skip-worktreeflag: Git wouldn't overwrite local file. Instead it would output conflicts and advices how to resolve them
  • 文件在本地存储库和上游都 发生了更改
    git pull
    Git 无论如何都会保留本地更改。
    因此,您不会意外丢失用任何标志标记的任何数据。
    • assume-unchanged标志的文件:Git 不会覆盖本地文件。相反,它会输出冲突并建议如何解决它们
    • skip-worktree标志的文件:Git 不会覆盖本地文件。相反,它会输出冲突并建议如何解决它们

  • File is changed both in local repository and upstream, trying to pull anyway
    git stash
    git pull
    Using skip-worktreeresults in some extra manual work but at least you wouldn't lose any data if you had any local changes.
    • File with assume-unchangedflag: Discards all local changes without any possibility to restore them. The effect is like ‘git reset --hard'. ‘git pull' call will succeed
    • File with skip-worktreeflag: Stash wouldn't work on skip-worktreefiles. ‘git pull' will fail with the same error as above. Developer is forced to manually reset skip-worktreeflag to be able to stash and complete the failing pull.
  • 文件在本地存储库和上游都被更改,无论如何都试图拉取 使用结果在一些额外的手动工作中,但至少如果您有任何本地更改,您不会丢失任何数据。
    git stash
    git pull
    skip-worktree
    • assume-unchanged标志的文件:丢弃所有本地更改而无法恢复它们。效果就像' git reset --hard'。' git pull' 调用会成功
    • 带有skip-worktree标志的文件:Stash 不适用于skip-worktree文件。' git pull' 将失败并出现与上述相同的错误。开发人员被迫手动重置skip-worktree标志以能够隐藏并完成失败的pull.

  • No local changes, upstream file changed
    git pull
    Both flags wouldn't prevent you from getting upstream changes. Git detects that you broke assume-unchangedpromise and choses to reflect the reality by resetting the flag.
    • File with assume-unchangedflag: Content is updated, flag is lost.
      git ls-files -v' would show that flag is modified to H(from h).
    • File with skip-worktreeflag: Content is updated, flag is preserved.
      git ls-files -v' would show the same Sflag as before the pull.
  • 没有本地更改,上游文件已更改 这两个标志都不会阻止您获得上游更改。Git 检测到你违背了承诺,并选择通过重置标志来反映现实。
    git pull
    assume-unchanged
    • assume-unchanged标志的文件:内容已更新,标志丢失。
      ' git ls-files -v' 将显示标志被修改为H(from h)。
    • skip-worktree标志的文件:更新内容,保留标志。
      ' git ls-files -v' 将显示与S之前相同的标志pull

  • With local file changed
    git reset --hard
    Git doesn't touch skip-worktreefile and reflects reality (the file promised to be unchanged actually was changed) for assume-unchangedfile.
    • File with assume-unchangedflag: File content is reverted. Flag is reset to H(from h).
    • File with skip-worktreeflag: File content is intact. Flag remains the same.
  • 更改本地文件后, Git 不会触及文件并反映文件的现实(承诺保持不变的文件实际上已更改)。
    git reset --hard
    skip-worktreeassume-unchanged
    • assume-unchanged标志的文件:文件内容被还原。标志重置为H(从h)。
    • skip-worktree标志的文件:文件内容完好无损。旗帜保持不变。

He adds the following analysis:

他补充了以下分析:

  • It looks like skip-worktreeis trying very hard to preserve your local data. But it doesn't prevent you to get upstream changes if it is safe. Plus git doesn't reset the flag on pull.
    But ignoring the ‘reset --hard' command could become a nasty surprisefor a developer.

  • Assume-unchangedflag could be lost on the pulloperation and the local changes inside such files doesn't seem to be important to git.

  • 看起来skip-worktree很努力维护您的本地数据。但是,如果安全,它不会阻止您获得上游更改。另外 git 不会重置pull.
    但是忽略“ reset --hard”命令可能会给开发人员带来令人讨厌的惊喜

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

See:

看:

He concludes:

他总结道:

Actually neither of the flags is intuitive enough.

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

  • assume-unchangedassumes that a developer shouldn't change a file. If a file was changed – then that change is not important. This flag is meant for improving performance for not-changing folders like SDKs.
    But if the promise is broken and a file is actually changed, git reverts the flag to reflect the reality. Probably it's ok to have some inconsistent flags in generally not-meant-to-be-changed folders.

  • On the other hand skip-worktreeis useful when you instruct git not to touch a specific file ever. That is useful for an already tracked config file.
    Upstream main repository hosts some production-ready config but you would like to change some settings in the config to be able to do some local testing. And you don't want to accidentally check the changes in such file to affect the production config. In that case skip-worktreemakes perfect scene.

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

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



With Git 2.25.1 (Feb. 2020), the "Actually neither of the flags is intuitive enough" mentioned above is further clarified:

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

See commit 7a2dc95, commit 1b13e90(22 Jan 2020) by brian m. carlson (bk2204).
(Merged by Junio C Hamano -- gitster--in commit 53a8329, 30 Jan 2020)
(Git Mailing list)

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

doc: dissuade users from trying to ignore tracked files

Signed-off-by: Jeff King
Signed-off-by: brian m. carlson

It is quite common for users to want to ignore the changes to a file that Git tracks.

Common scenarios for this case are IDE settings and configuration files, which should generally not be tracked and possibly generated from tracked files using a templating mechanism.

However, users learn about the assume-unchanged and skip-worktree bits and try to use them to do this anyway.

This is problematic, because when these bits are set, many operations behave as the user expects, but they usually do not help when git checkoutneeds to replace a file.

There is no sensible behavior in this case, because sometimes the data is precious, such as certain configuration files, and sometimes it is irrelevant data that the user would be happy to discard.

Since this is not a supported configuration and users are prone to misuse the existing features for unintended purposes, causing general sadness and confusion, let's document the existing behavior and the pitfalls in the documentation for git update-indexso that users know they should explore alternate solutions.

In addition, let's provide a recommended solution to dealing with the common case of configuration files, since there are well-known approaches used successfully in many environments.

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

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

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

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

但是,用户了解了假定未更改和跳过工作树位,并尝试使用它们来执行此操作。

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

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

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

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

The git update-indexman pagenow includes:

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

Users often try to use the assume-unchangedand skip-worktreebits to tell Git to ignore changes to files that are tracked. This does not work as expected, since Git may still check working tree files against the index when performing certain operations. In general, Git does not provide a way to ignore changes to tracked files, so alternate solutions are recommended.

For example, if the file you want to change is some sort of config file, the repository can include a sample config file that can then be copied into the ignored name and modified. The repository can even include a script to treat the sample file as a template, modifying and copying it automatically.

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

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

That last part is what I describe a typical content filter driver based on smudge/clean scripts.

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