我有几个提交对文件进行无效更改,但其中一些与对另一个文件的相关更改相结合。所以我只想压缩对一个文件的更改。我该怎么做?
例: 以下内容应象征提交和文件内容的[......]
。
这是我所拥有的:
- 提交 5
file A: [.....] file B: [......]
- 提交 4
file A: [ ] file B: [.... ]
- 提交 3
file A: [.....] file B: [... ]
- 提交 2
file A: [ ] file B: [... ]
- 提交 1
file A: [.....] file B: [.. ]
差异将是:
- 提交 5
file A: [+++++] file B: [....++]
- 提交 4
file A: [-----] file B: [...+ ]
- 提交 3
file A: [+++++] file B: [... ]
- 提交 2
file A: [-----] file B: [..+ ]
- 提交 1
file A: [+++++] file B: [++ ]
在这种情况下,提交 5、3 和 1 时的文件 A 是相同的。
这就是我想要的: 所以我想把它压扁。
- 提交 5
file A: [.....] file B: [......]
- 提交 4
file A: [.....] file B: [.... ]
- 提交 2
file A: [.....] file B: [... ]
- 提交 1
file A: [.....] file B: [.. ]
差异将是:
- 提交 5
file A: [.....] file B: [....++]
- 提交 4
file A: [.....] file B: [...+ ]
- 提交 2
file A: [.....] file B: [..+ ]
- 提交 1
file A: [+++++] file B: [.. ]
有什么办法可以做到这一点。
编辑:也许我的问题不是很清楚。我知道如何进行交互式变基和壁球。更多的是关于这样一个事实,我只想"压缩"文件 A 的无效更改,而我保留文件 B 上的更改(这样做会导致提交 3 什么都不做,因此它被删除了。
我在"正常"变基时面临的问题是,如果我只是压缩 1-5 的所有提交,我最终会得到我想要的文件 A 的结果,但对文件 B 的所有中间更改都会丢失。
我添加了差异的表示形式,以更好地描述情况。
这是可以做到的。 这是一个历史记录重写,这意味着如果有遥控器,它将涉及强制推送分支,如果该遥控器与其他用户共享,那么您需要先与他们协调,否则您将面临他们试图从您强制推送后遇到的错误中恢复时撤消您的更改的风险。 您可以在"从上游变基恢复"下的git rebase
文档中找到有关强制推送到共享存储库的问题的更多信息。
因此,在像您的示例这样的小/简单情况下,您可以使用交互式 rebaes 来执行此操作。
git rebase -i HEAD~4
这将加载一个包含提交 2、3、4 和 5 的变基"TODO"列表。 (在您的示例中,您不会更改提交 1;如果需要更改它,您可以在有先前历史记录的情况下使用HEAD~5
,或者在没有历史记录的情况下使用--root
选项。
"TODO"列表中的每行代表一个提交,并以一个命令开头,该命令告诉变基如何处理该提交。 在提交 3 的行中,将命令从"pick"更改为"squash";这会将提交 2 和 3 中的更改合并到单个提交中。 在提交 4 的行中,将命令从"pick"更改为"edit"。 保存并从编辑器中退出。
当变基准备重写提交 4 时,它将暂停并让您在继续之前应用更改。 拉取文件 A 的正确版本
git checkout HEAD^ -- path/to/file_A
git add .
然后完成变基
git rebase --continue
您可以从变基文档页面获取有关所有交互式变基选项的信息。 (在简单情况下还有其他方法可以获得相同的效果;但在适合小型/简单用例的方法中,rebase -i
是最适合目的的IMO。
此过程在某种程度上是手动的,对于包含合并或可从多个分支(或标记或其他引用)访问的更复杂的历史记录,它会遇到问题。 在这些情况下,您可以使用git filter-repo
. 这是一个相当复杂的工具,所以有一些学习曲线。 但它确实有不错的文档。
将有多个交互式变基。综上所述,您应该在交互式变基时编辑commit 4
和commit 5
。让我解释一下:
您已经发现挤压commit 2
和commit 3
是第一步。当我们这样做时,提交历史记录的开始将类似于第一次交互式变基之后:
- 提交 2
file A: [.....] file B: [... ]
- 提交 1
file A: [.....] file B: [.. ]
好吧,让我们分析一下场景。您的file B
更改将被保留,与commit 4
和commit 5
相同。但是,我们需要摆脱file A
变化。在这里,我们将从交互式变基中的编辑选项中获得帮助。
在交互式变基时,选择commit 4
和commit 5
的编辑选项。编辑两个提交的状态时,将文件 A 更改与提交分开。因此,在第二次交互式变基后,示例历史记录将如下所示:
1--2--4A--4B--5A--5B
该4A
仅包括文件A
中的更改commit 4
.然后最终变基;将5A
提交移到4A
提交旁边,并将两个提交压缩到commit 2
中。而魔法,因为它们是相反的提交,所以它们将被消失。提交历史记录将在第三次交互式变基后如下所示:
- 提交 5B
file A: [.....] file B: [......]
- 提交 4B
file A: [.....] file B: [.... ]
- 提交 2
file A: [.....] file B: [... ]
- 提交 1
file A: [.....] file B: [.. ]
如你所愿。
-
重新开始:
git reset {commit 1 HASH}
并根据需要重做提交。
-
有新的提交来撤消你以前的提交
git revert {commit 1 HASH}
-
壁球提交
git rebase -i {commit 1 HASH}
如果你对 git-rebase 不是很满意,请不要担心。挤压 提交是一种非常简单的技术,可以通过交互式实现 git-rebase 交互式变基将打开编辑器。你可以 看看rebase -i
是如何完成最后三次提交的。并注意 它拥有的选项数量。让我们只关注南瓜。 如 前面提到过,让我们进行一次提交。您可以看到我们已经标记了最后两个 squash 提交。您可以使用squash或s来标记对 squash 的提交。
请继续按照此页面上的本教程来压制提交,它非常具有解释性
我建议选择选项1。 并重新开始,但这是您的选择。