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

Posted

技术标签:

【中文标题】我可以“git commit”一个文件并忽略其内容更改吗?【英文标题】:Can I 'git commit' a file and ignore its content changes? 【发布时间】:2011-03-20 04:02:31 【问题描述】:

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

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

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

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

【问题讨论】:

参见***.com/questions/3318043/… 类似的主题。 Committing Machine Specific Configuration Files的可能重复 git ignore files only locally 【参考方案1】:

无法使用 Git 忽略对跟踪文件的更改。 Git FAQ explains this:

Git 没有提供执行此操作的方法。原因是如果 Git 需要覆盖这个文件,例如在结帐期间,它不知道对文件的更改是否宝贵并且应该保留,或者它们是否无关紧要并且可以安全地销毁。因此,它必须采取安全路线并始终保护它们。

尝试使用 git update-index 的某些功能是很有诱惑力的,即假设不变和跳过工作树位,但这些功能不能正常工作,因此不应该以这种方式使用。

如果您的目标是使用配置文件,那么最好的做法是添加示例或模板文件,然后让用户将其复制到位或让脚本创建适当的文件。然后,您应该忽略实际配置文件的位置,只签入示例或模板。

【讨论】:

【参考方案2】:

执行此操作的首选方法是使用git update-index --skip-worktree <file>,如in this answer 所述:

assume-unchanged 专为检查成本高昂的情况而设计 一组文件是否被修改;当你设置位时,git (当然)假设文件对应于 工作副本中的索引没有被修改。所以它避免了混乱 统计调用。每当索引中的文件条目时,该位都会丢失 更改(因此,当文件在上游更改时)。

skip-worktree 不止于此:即使 git 知道该文件 已被修改(或需要通过 reset --hard 或 像),它会假装它没有,使用来自 而是索引。这会一直持续到索引被丢弃为止。

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

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

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

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

【讨论】:

这是否适用于所有签出存储库的用户?除非明确说明,否则他们是否会错误地获取某些文件但不再能够添加更改? @momomo 该标志存储在索引中,所以不,它仅适用于单个用户。请参阅 erjiang's answer 了解适用于所有用户的内容。 Git documentation 明确表示不要将git update-index --skip-worktree 用于此目的。 @Emir 这个方法和以前一样好用,git 刚刚更新了文档以说明他们不推荐它。其他答案涵盖其他选项 - 这主要适用于您无法控制遥控器并需要某种解决方法的情况。 谢谢,很高兴知道。我想这是我的错。我误解了不推荐为无法正常工作。感谢您的跟进。其实这个答案解决了我的问题。【参考方案3】:

当然,我不时会这样做

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

撤消并重新开始跟踪(如果您忘记了未跟踪的文件,see this question):

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

Relevant documentation:

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

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

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

$ 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
 

并且会拒绝合并。

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

 $ git checkout filename.ext

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

【讨论】:

此命令是否在 .git 文件夹中进行本地操作?我的意思是,如果我对 config.php 文件运行此命令,这会传播给正在使用 repo 的其他用户吗? @Magus:不。这只会为你工作。 稍后您将想知道如何确定文件是否假定未更改:***.com/questions/2363197/… 使用“git stash”时,以这种方式忽略的文件更改会丢失。有办法解决吗? 这不是git update-index --assume-unchanged 的用途。 public-inbox.org/git/…【参考方案4】:

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

前往Local Changes (Cmd + 9) 选择要忽略的文件 F6 将它们移动到另一个 Change Set

【讨论】:

【参考方案5】:

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

【讨论】:

您不能 .gitignore 正在跟踪的文件。 .gitignore 仅对不在索引中的文件有效。 我试图避免这样做,尽管我真的没有充分的理由。我们现在正在这样做,我认为记住我需要创建自己的版本而名称中没有“.default”是很痛苦的。 @DerickBailey 但公平地说,记住复制文件比记住对每个克隆存储库的人使用--assume-unchanged 选项更容易。 @DerickBailey 如果devtargets.rb 不存在,您还可以将您的 rake 构建设置为默认为 devtargets.default.rb @erjang devtargets.default.rb 文件中有什么?一个例子?

以上是关于我可以“git commit”一个文件并忽略其内容更改吗?的主要内容,如果未能解决你的问题,请参考以下文章

git commit时暂时忽略已提交的文件

git commit 前8位为啥不重复

你可能已经忽略的git commit规范

git commit进行代码检查

在git中,当使用git.commit命令时,这个Please tell me who yoy are 怎么解决

文件修改后git add+git commit提交一次,但是没有push到远程,接着继续修改文件,继续git add+git commit提交,并push到远程仓库。会发现本地仓库两次commit一次