git rebase在合并之间如何工作?

时间:2018-08-29 18:08:40

标签: git

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

*   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不提供南瓜“ f2”?
  • 我能否只压缩“ f3”而不对整个分支结构进行进一步更改?

1 个答案:

答案 0 :(得分:2)

  

为什么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

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

如果您改为重新排列提交,以便可以将f3压入2 ...

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]

f2f4没有实际价值;它们是master的更新,不包含任何有趣的内容。他们只是使历史混乱。仅f1f3包含实际内容。最好消除与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]

当您准备将feature合并到master时,这是您要进行合并提交的时间。使用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都是为单个功能开发的。