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
Git - Difference Between 'assume-unchanged' and 'skip-worktree'
提问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-unchanged
is 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 stat
calls. 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-worktree
is more than that: even where git
knowsthat the file has been modified (or needs to be modified by a reset --hard
or 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-unchanged
assumes that a developer shouldn'tchange a file. This flag is meant for improving performancefor not-changing folders like SDKs.--skip-worktree
is 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-worktree
is 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-unchanged
flag: Git wouldn't overwrite local file. Instead it would output conflicts and advices how to resolve them - File with
skip-worktree
flag: Git wouldn't overwrite local file. Instead it would output conflicts and advices how to resolve them
- File with
- 文件在本地存储库和上游都
发生了更改
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
Usingskip-worktree
results in some extra manual work but at least you wouldn't lose any data if you had any local changes.- File with
assume-unchanged
flag: 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-worktree
flag: Stash wouldn't work onskip-worktree
files. ‘git pull
' will fail with the same error as above. Developer is forced to manually resetskip-worktree
flag to be able to stash and complete the failingpull
.
- File with
- 文件在本地存储库和上游都被更改,无论如何都试图拉取
使用结果在一些额外的手动工作中,但至少如果您有任何本地更改,您不会丢失任何数据。
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 brokeassume-unchanged
promise and choses to reflect the reality by resetting the flag.- File with
assume-unchanged
flag: Content is updated, flag is lost.
‘git ls-files -v
' would show that flag is modified toH
(fromh
). - File with
skip-worktree
flag: Content is updated, flag is preserved.
‘git ls-files -v
' would show the sameS
flag as before thepull
.
- File with
- 没有本地更改,上游文件已更改
这两个标志都不会阻止您获得上游更改。Git 检测到你违背了承诺,并选择通过重置标志来反映现实。
git pull
assume-unchanged
- 带
assume-unchanged
标志的文件:内容已更新,标志丢失。
'git ls-files -v
' 将显示标志被修改为H
(fromh
)。 - 带
skip-worktree
标志的文件:更新内容,保留标志。
'git ls-files -v
' 将显示与S
之前相同的标志pull
。
- 带
- With local file changed
git reset --hard
Git doesn't touchskip-worktree
file and reflects reality (the file promised to be unchanged actually was changed) forassume-unchanged
file.- File with
assume-unchanged
flag: File content is reverted. Flag is reset toH
(fromh
). - File with
skip-worktree
flag: File content is intact. Flag remains the same.
- File with
- 更改本地文件后,
Git 不会触及文件并反映文件的现实(承诺保持不变的文件实际上已更改)。
git reset --hard
skip-worktree
assume-unchanged
- 带
assume-unchanged
标志的文件:文件内容被还原。标志重置为H
(从h
)。 - 带
skip-worktree
标志的文件:文件内容完好无损。旗帜保持不变。
- 带
He adds the following analysis:
他补充了以下分析:
It looks like
skip-worktree
is 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 onpull
.
But ignoring the ‘reset --hard
' command could become a nasty surprisefor a developer.Assume-unchanged
flag could be lost on thepull
operation 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:
看:
Junio's (current git maintainer) comment regarding intent of
assume-unchanged
,In particular, Junio points out that changes to
assume-unchanged
files could accidentally be committed: "if Git can determine a path that is marked asassume-unchanged
has changed without incurring extra lstat(2) cost, it reserves the right to report that the path has beenmodified (as a result,git commit -a
is free to commit that change)."
Junio(当前的 git 维护者)关于意图的评论
assume-unchanged
,Junio 特别指出,对
assume-unchanged
文件的更改可能会被意外提交:“如果 Git 可以确定标记为assume-unchanged
已更改的路径而不会产生额外的 lstat(2) 成本,则它保留报告该路径 已被修改的权利(因此,git commit -a
可以自由地提交该更改)。”添加patch后在 git 邮件列表中讨论的
assume-unchanged
和之间的区别skip-worktree
skip-worktree
。
He concludes:
他总结道:
Actually neither of the flags is intuitive enough.
实际上,这两个标志都不够直观。
assume-unchanged
assumes 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-worktree
is 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 caseskip-worktree
makes 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 7a2dc95和commit 1b13e90(2020 年 1 月 22 日)。卡尔森 ( bk2204
)。
(由Junio C gitster
Hamano合并-- --在提交 53a8329 中,2020 年 1 月 30 日)
(Git 邮件列表)
doc
: dissuade users from trying to ignore tracked filesSigned-off-by: Jeff King
Signed-off-by: brian m. carlsonIt 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 checkout
needs 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-index
so 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-index
man pagenow includes:
该git update-index
手册页现在包括:
Users often try to use the
assume-unchanged
andskip-worktree
bits 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-unchanged
和skip-worktree
位来告诉 Git 忽略对被跟踪文件的更改。这不会按预期工作,因为在执行某些操作时,Git 可能仍会根据索引检查工作树文件。通常,Git 不提供忽略跟踪文件更改的方法,因此建议使用替代解决方案。例如,如果您要更改的文件是某种配置文件,则存储库可以包含一个示例配置文件,然后可以将其复制到忽略的名称中并进行修改。存储库甚至可以包含一个脚本来将示例文件视为模板,自动修改和复制它。
That last part is what I describe a typical content filter driver based on smudge/clean scripts.