git 压缩一个文件的更改

git squash changes for one file

我有几个提交对一个文件做了无效的更改,但其中一些与对另一个文件的相关更改结合在一起。所以我只想压缩对一个文件的更改。我该怎么做?

示例: 以下应表示提交和 [......] 文件的内容。

这是我的:

差异为:

在这种情况下,提交 5、3 和 1 处的文件 A 是相同的。

这就是我想要的: 所以我想把它压扁。

差异为:

有什么办法吗

编辑: 可能我的问题不是很清楚。我知道如何进行交互式变基和压缩。更重要的是,我只想“压缩”文件 A 的无效更改,同时保留文件 B 上的更改。(这样做会导致提交 3 什么都不做,因此它被删除了。)

我面临的“正常”变基问题是,如果我只是压缩 1-5 的所有提交,我最终会得到我想要的文件 A 的结果,但文件 B 的所有中间更改迷路了。

我添加了 diff 的表示,以便更好地描述情况。

  1. 重新开始:

    git reset {commit 1 HASH}
    

    并根据需要重做提交。

  2. 有新的提交可以撤消之前的提交

    git revert {commit 1 HASH}
    
  3. 压缩提交

    git rebase -i {commit 1 HASH}
    

如果您对 git-rebase 不是很满意,请不要担心。挤压 提交是一种非常简单的技术,可以通过交互实现 git-rebase 交互式 rebase 将打开编辑器。你可以 查看 rebase -i 如何进行最后三个提交。并注意 它拥有的选项数量。让我们只关注壁球。 作为 前面提到过,让我们进行一次提交。您可以看到我们已经将最后两次提交标记为 squash。您可以使用 squashs 将提交标记为 squash。

Please continue following this tutorial on this page for squashing commits, it is very explanatory

我建议选择选项 1。重新开始,但这是您的选择。

可以做到。这是一个历史重写,这意味着如果有一个远程,它将涉及强制推送分支,如果该远程与其他用户共享,那么你需要先与他们协调,否则你 运行 他们的风险当他们尝试从您强制推送后遇到的错误中恢复时,他们将撤消您的更改。您可以在“从上游 rebase 恢复”下的 git rebase 文档中找到有关强制推送到共享存储库的问题的更多信息。


所以在 small/simple 像你的例子这样的情况下,你可以使用交互式 rebaes 来做到这一点。

git rebase -i HEAD~4

这将加载包含提交 2、3、4 和 5 的变基“TODO”列表。(在您的示例中,您没有更改提交 1;如果您需要更改它,您可以使用 HEAD~5 在有先前历史的情况下,或 --root 选项在没有的情况下。)

“TODO”列表中的每一行都代表一个提交,并以一个命令开始,该命令告诉 rebase 如何处理该提交。在提交 3 的行上,将命令从“pick”更改为“squash”;这会将提交 2 和 3 的更改合并到一个提交中。在提交 4 的行上,将命令从“pick”更改为“edit”。保存并退出编辑器。

当 rebase 准备重写提交 4 时,它将暂停并让您在继续之前应用更改。拉取正确版本的文件 A

git checkout HEAD^ -- path/to/file_A
git add .

然后完成变基

git rebase --continue

您可以从 rebase 文档页面获取有关所有交互式 rebase 选项的信息。 (还有其他方法可以在简单情况下获得相同的效果;但是在适用于 small/simple 用例的方法中,rebase -i 是最适合目的的 IMO。)

此过程有点手动,它将 运行 解决包含合并或可从多个分支(或标签或其他参考)访问的更复杂历史的问题。在这些情况下,您可以使用 git filter-repo。这是一个相当复杂的工具,因此有一些学习曲线。但它确实有不错的文档。

会有多个交互式变基。总而言之,您应该在交互式变基时 edit commit 4commit 5。让我解释一下:

您已经发现压缩 commit 2commit 3 是第一步。当我们这样做时,提交历史的开始就像在第一次交互式 rebase 之后:

  • 提交 2 file A: [.....] file B: [... ]
  • 提交 1 file A: [.....] file B: [.. ]

好吧,我们来分析一下场景。您的 file B 更改将被保留,与 commit 4commit 5 相同。但是,我们需要摆脱 file A 变化。这是我们将从交互式变基中的 edit 选项获得帮助的地方。

在交互式变基时,select 编辑 commit 4commit 5 选项。在编辑两个提交的状态时,单独的文件 A 从提交中更改。因此,在第二次交互式 rebase 之后,示例历史将如下所示:

1--2--4A--4B--5A--5B

4A 仅包含文件 Acommit 4 的更改。然后最终变基;将 5A 提交移动到 4A 提交旁边,并将两个提交压缩到 commit 2 中。而魔法,因为它们是相反的承诺,所以它们会消失。在第三次交互式 rebase 之后提交历史看起来像:

  • 提交 5B file A: [.....] file B: [......]
  • 提交 4B file A: [.....] file B: [.... ]
  • 提交 2 file A: [.....] file B: [... ]
  • 提交 1 file A: [.....] file B: [.. ]

如你所愿。