14

在 Git 中,我可以使用交互式 rebase 来重写历史记录,这很棒,因为在我的功能分支中,当我探索不同的重构和完成它的方法时,我使用部分工作代码进行了大量提交。

在将分支重新定位或合并到 master 之前,我想将很多提交压缩在一起。

有些按从第一个(顶部)到底部(最后一个)的顺序组成提交

1. Initial commit on feature branch "Automatic coffee maker UI"
2. Add hot chocolate as product
3. Add tea as product. Products are now generic
4. Create in memory data store for adapter tests
5. Cry because I can't get entity framework to create a composite key. Integration tests broken.
6. Implemented composite key!!
7. All tests green and feature done!

假设我想保留提交 3、4 和 7。

使用 rebase 我想“压缩”提交

  • 1 和 2 进入 3。
  • 4 次住宿
  • 5和6进入7

理想情况下,我会在交互式变基中

1. squash
2. squash
3. pick (contains the work of 1 & 2)
4. pick 
5. squash
6. squash
7. pick (contains the work of 5 & 6)

但这是倒退的,因为 squash 将提交与之前的提交合并。我不知道如何使它向前挤压。

我是不是很难,我应该接受这行不通(我宁愿让它工作),还是有办法做到这一点?

我正在调用这个命令

git checkout My-feature-branch
git rebase master -i

然后我正在编辑出现的提交列表,并尝试通过保存文件并编辑编辑器来完成它,这通常对我有用。

4

4 回答 4

6

您要么还需要重新排序提交,因此如果可行的话,待保留的提交在待压缩的提交之前。

如果这不可行,因为你会遇到你不想解决的冲突,那就去做吧

1. pick
2. squash
3. squash
4. pick 
5. pick
6. squash
7. squash

压缩完成后,您可以编辑提交消息以包含您希望最终提交具有的消息。非常简单。:-)

你甚至可以做

1. pick
2. fixup
3. squash
4. pick 
5. pick
6. fixup
7. squash

然后我认为应该只启动一次提交消息编辑器,就像修复一样,只需在不启动编辑器的情况下获取先前的提交消息。

当提交消息编辑器触发时,在 squash 上,您还会同时获得两个提交消息,即来自 to-be-squashed-into 和 to-be-squashed 提交的消息,因此您可以简单地删除您不想要的提交消息保持。

于 2017-05-26T23:28:03.300 回答
4

在交互式 rebase 期间确实可以将提交压缩到一个提交中,并完全保留第二个提交的身份(包括作者、日期等)。

但是,该方法有些涉及,因此git rebase -i仍然会感谢本机支持。

我将仅用三个提交来演示aaaaaaa Abbbbbbb B并且ccccccc C,我们想要折叠AB保留B的身份:(该方法很容易推广到更多提交)

  • git rebase -i aaaaaaa^
  • 修改编辑脚本在提交后停止B并退出编辑器:
    pick aaaaaaa A
    edit bbbbbbb B
    pick ccccccc C
    
  • 当 rebase 之后停止时B,将最近的提交还原两次,然后继续:
    git revert HEAD
    git revert HEAD
    git rebase --continue
    
    因为还原还原会还原以前的状态,所以所有后续提交都将干净地应用。B和的顺序Revert "B"没有影响,但是这些提交中的第一个带有提交 B 的完整标识(实际上,在这个阶段它仍然commit B)。
    B并且Revert "B"可以压缩在一起形成一个无操作提交,该提交带有提交 B 的身份,并带有一个单独的rebase -i --keep-empty aaaaaaa^. 这非常有用,建议防止虚假合并冲突,尤其是在更复杂的情况下。但是,我们将在此处跳过该步骤,并将提交保持在一起。
    现在重要的提交Revert "Revert "B""将携带最初由B.
  • 现在rebase -i aaaaaaa^再次A越过两个Band Revert "B",同时B挤入两个Revert "B"and A
    pick   bbbbbbb B
    squash b111111 Revert "B"
    squash a222222 A
    squash b333333 Revert "Revert "B""
    pick   c444444 C
    
    因为Band的顺序Revert "B"没有影响,所以您可以将任何提交移过它,同时只创建可解决的合并冲突。
  • 当 rebase 因合并冲突而停止时,请使用git mergetool可以自动解决琐碎冲突的工具,并让这些工具来做这件事。
  • Rebase 将再次停止,让您编辑压缩提交的提交消息。根据您的口味编辑。
  • git rebase --continue你就完成了。
于 2021-01-30T00:02:42.320 回答
3

吸血鬼的回答是对的,但我想提供一个不同的视角。我认为这是您让自己变得不必要的地方:您从以下内容开始:

假设我想保留提交 3、4 和 7。

但然后添加:

  • 1 和 2 进入 3。
  • 4 次住宿
  • 5和6进入7

但这意味着您要保留所有1、2、3、4、5、6 和 7 的(内容)......而不是作为单独的提交。交互式变基squash并不意味着“丢弃”,甚至也不是“丢弃提交消息”,它只是意味着“组合”。如果动词是“组合”或“融合”或“混合”或类似的,可能会更好。所以顺序(pick、squash、squash)意味着:保留所有三个,同时按顺序应用它们,然后从它们中做出一个大提交。

如前所述,一旦 Git 从它们中做出一个大提交,Git 会给你另一个机会将三个组合的提交消息编辑成一个大提交消息。

当 rebase 完成后,您还没有保留任何原始提交。相反,您已经做出了新的提交。你的新的第一次提交是如何从各个部分组装的并不重要,重要的是最终的来源是什么,以及你在一个大的提交信息中放了什么。

于 2017-05-27T12:15:14.783 回答
-1

你想要的是:

1. pick
2. squash
3. fixup
4. pick
5. squash
6. squash
7. fixup

然后,当编辑器中出现新的组合提交时,删除所选提交的行并保留修复。生成的功能补丁应该有来自系列中最后一次提交的提交消息。

于 2019-10-09T17:35:01.810 回答