我可以“git commit”一个文件并忽略其内容更改吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3319479/
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 08:48:25  来源:igfitidea点击:

Can I 'git commit' a file and ignore its content changes?

gitgitignore

提问by Derick Bailey

Every developer on my team has their own local configuration. That configuration information is stored in a file called devtargets.rbwhich is used in our rake build tasks. I don't want developers to clobber each other's devtargets file, though.

我团队中的每个开发人员都有自己的本地配置。该配置信息存储在一个名为的文件中,该文件devtargets.rb用于我们的 rake 构建任务。不过,我不希望开发人员破坏彼此的 devtargets 文件。

My first thought was to put that file in the .gitignorelist so that it is not committed to git.

我的第一个想法是将该文件放在.gitignore列表中,这样它就不会提交给 git。

Then I started wondering: is it possible to commit the file, but ignore changes to the file? So, I would commit a default version of the file and then when a developer changes it on their local machine, git would ignore the changes and it wouldn't show up in the list of changed files when you do a git status or git commit.

然后我开始想:是否可以提交文件,但忽略对文件的更改?因此,我会提交文件的默认版本,然后当开发人员在他们的本地机器上更改它时,git 会忽略这些更改,并且当您执行 git status 或 git commit 时它不会显示在更改的文件列表中.

Is that possible? It would certainly be a nice feature...

那可能吗?这肯定是一个不错的功能......

回答by Rob Wilkerson

Sure, I do exactly this from time to time using

当然,我不时使用

git update-index --assume-unchanged [<file> ...]

To undo and start tracking again (if you forgot what files were untracked, see this question):

要撤消并再次开始跟踪(如果您忘记了未跟踪哪些文件,请参阅此问题):

git update-index --no-assume-unchanged [<file> ...]

Relevant documentation:

相关文件

--[no-]assume-unchanged
When this flag is specified, the object names recorded for the paths are not updated. Instead, this option sets/unsets the "assume unchanged" bit for the paths. When the "assume unchanged" bit is on, the user promises not to change the file and allows Git to assume that the working tree file matches what is recorded in the index. If you want to change the working tree file, you need to unset the bit to tell Git. This is sometimes helpful when working with a big project on a filesystem that has very slow lstat(2)system call (e.g. cifs).

Git will fail (gracefully) in case it needs to modify this file in the index e.g. when merging in a commit; thus, in case the assumed-untracked file is changed upstream, you will need to handle the situation manually.

--[no-]assume-unchanged
指定此标志时,不会更新为路径记录的对象名称。相反,此选项设置/取消设置路径的“假设未更改”位。当“假设未更改”位打开时,用户承诺不更改文件并允许 Git 假设工作树文件与索引中记录的内容相匹配。如果要更改工作树文件,则需要取消设置该位以告诉 Git。当在lstat(2)系统调用非常慢的文件系统(例如 cifs)上处理大型项目时,这有时会很有帮助。

如果 Git 需要在索引中修改此文件,例如在合并提交时,Git 将失败(优雅地);因此,如果假定未跟踪的文件在上游发生更改,您将需要手动处理这种情况。

Fail gracefully in this case means, if there are any changes upstream to that file (legitimate changes, etc.) when you do a pull, it will say:

在这种情况下,正常失败意味着,如果在执行拉取时该文件的上游有任何更改(合法更改等),它会说:

$ git pull
…
From https://github.com/x/y
   72a914a..106a261  master     -> origin/master
Updating 72a914a..106a261
error: Your local changes to the following files would be overwritten by merge:
                filename.ext

and will refuse to merge.

并将拒绝合并。

At that point, you can overcome this by either reverting your local changes, here's one way:

此时,您可以通过还原本地更改来克服此问题,这是一种方法:

 $ git checkout filename.ext

then pull again and re-modify your local file, or could set –no-assume-unchangedand you can do normal stash and merge, etc. at that point.

然后再次拉动并重新修改您的本地文件,或者可以设置–no-assume-unchanged并且您可以在此时进行正常的存储和合并等。

回答by 1615903

The preferred way to do this is to use git update-index --skip-worktree <file>, as explained in this answer:

执行此操作的首选方法是使用git update-index --skip-worktree <file>,如本答案中所述

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 stat calls. This bit is lost whenever the file's entry in the index changes (so, when the file is changed upstream).

skip-worktreeis more than that: even where git knows that 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.

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

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

To undo this, use git update-index --no-skip-worktree <file>

要撤消此操作,请使用 git update-index --no-skip-worktree <file>

Since git version 2.25.1, this is no longer the recommended way either, quoting:

从 git 版本 2.25.1 开始,这也不再是推荐的方式,引用:

Users often try to use the assume-unchanged and skip-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.

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

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

回答by erjiang

Common practice seems to be to create a devtargets.default.rband commit it, and then instruct each user to copy that file to devtargets.rb(which is on the .gitignore list). For example, CakePHP does the same for its database configuration file which naturally changes from machine to machine.

通常的做法似乎是创建一个devtargets.default.rb并提交它,然后指示每个用户将该文件复制到devtargets.rb(在 .gitignore 列表中)。例如,CakePHP 对它的数据库配置文件做同样的事情,它自然会随着机器的不同而变化。

回答by Eugene

For IntelliJ IDEA users: If you want to ignore changes for a file (or files) you can move it to different Change Set.

对于 IntelliJ IDEA 用户:如果您想忽略一个(或多个)文件的更改,您可以将其移动到不同的Change Set.

  • Head over to Local Changes(Cmd + 9)
  • Select file(s) you want to ignore
  • F6to move them to another Change Set
  • 前往Local Changes( Cmd + 9)
  • 选择要忽略的文件
  • F6将它们移动到另一个 Change Set