首页 > 解决方案 > git rebase 如何在合并之间工作?

问题描述

我有一个功能和一个主分支,例如像这样(主已合并两次到功能中):

*   27e89b5 (HEAD -> feature) f4
|\  
| * 6849a63 (master) 3
* | 3b78807 f3
* |   e84e33f f2
|\ \  
| |/  
| * 90e6f74 2
* | 4e4025b f1
|/  
* e4e0759 (tag: initial) 1

您可以使用以下命令重建此 MWE:

git init
f() {   echo "$1" > README.md && git add README.md && git commit -m "$1"; }
f 1
git tag initial
git checkout -b feature
f f1
git checkout master
f 2
git checkout feature
git merge master
f f2
f f3
git checkout master
f 3
git checkout feature
git merge master
f f4

当我使用功能时,我想git rebase -i initial压缩一些功能分支提交。Git 显示了这一点:

pick 4e4025b f1
pick 90e6f74 2
pick 3b78807 f3
pick 6849a63 3

squash仅使用“f3”生成下图。

* be4387c (HEAD -> feature) 3
* a90d504 2
* 2afe0a4 f1
| * c447c7f (master) 3
| * efec11d 2
|/  
* 661d8fc (tag: initial) 1

问题:

标签: git

解决方案


为什么 git 不提供压缩“f2”?

因为f2是合并提交,您没有要求保留合并。默认情况下,git rebase线性化历史并消除合并。它只是将提交堆叠在基础之上,就好像它们是新的补丁一样。

您可以保留合并,-p然后您将获得所有提交。

$ git rebase -i initial
pick bde29dc f1
pick c9a9c74 2
pick e5565c5 f2
pick 7f18c18 f3
pick ffdd62c 3
pick 35d8ae9 f4

# Rebase aa61de7..35d8ae9 onto aa61de7 (6 commands)

我可以只压缩“f3”而不对整个分支结构进行进一步更改吗?

是的,但是在你压缩f3到之前2,如果你想保留你必须压缩f3到的结构,f2因为那是紧接在前的提交,在拓扑上。

pick bde29dc f1
pick c9a9c74 2
pick e5565c5 f2
squash 7f18c18 f3
pick ffdd62c 3
pick 35d8ae9 f4

你会结束的。

*  (HEAD -> feature) f4
|\  
| *  (master) 3
* |  f2
|\ \  
| |/  
| *  2
* |  f1
|/  
* (tag: initial) 1

尽管将提交压缩为合并提交没有多大意义。

如果您改为重新排序提交,以便您可以压缩f32...

pick bde29dc f1
pick c9a9c74 2
squash 7f18c18 f3
pick e5565c5 f2
pick ffdd62c 3
pick 35d8ae9 f4

......你会结束......一些奇怪的东西。

*   (HEAD -> feature) f4
|\  
| * 3
|/  
* f3
* 2
* (tag: initial) 1

尝试在分支之间移动提交git rebase -i -p会让人感到困惑,因为它会为git rebase -i您提供非线性历史的线性视图。假装非线性历史是线性的,这是 Git 令人困惑的地方。


但是您可能不应该担心保留所有这些。保持 Git 历史大部分是线性的,这会让一切变得更加简单。这是如何做到的。

您的历史记录可能是使用 更新的feature结果git merge master。这是一个更好的方式来看待它。

1 -- 2 ------- 3 [master]
 \    \         \
  f1 - f2 - f3 - f4 [feature]

f2并且f4没有实际价值;它们是来自更新,master不包含有趣的内容。他们只是让历史变得混乱。仅f1包含f3实际内容。您最好消除这些更新合并git rebase master并获得线性历史记录。

$ git rebase master

1 - 2 - 3 [master]
         \
         f1 - f3 [feature]

然后一切都清晰而简单。通过使用git rebase master而不是git merge master.

# After more updates with `git rebase master`
1 - 2 - 3 - 4 - 5 [master]
                 \
                  f1 - f3 - f5 - f6 [feature]

当您准备好合并featuremaster这里时,就是您想要合并提交的时候。用于git merge --no-ff feature强制合并提交,然后删除feature.

$ git merge --no-ff feature
$ git branch -d feature

1 - 2 - 3 - 4 - 5 ------------------ 6 [master]
                 \                 /
                  f1 - f3 - f5 - f6

这将使分支保留在历史记录中,而不必保留分支头。这让未来的代码考古学家清楚地知道,f1 - f3 - f5 - f6它们都是为单一功能而开发的。


推荐阅读