在工作中进行分支合并的时候出现了这样的一个问题,正好在stackoverflow上已经有人提出了这样的疑问,正好简单做个小结。
原汁原味问答: https://stackoverflow.com/questions/8939977/git-push-rejected-after-feature-branch-rebase
问题点
在C点开出了feature分支,但是因为某些原因发了一个小版本,将这部分代码合到了master,也就是F,G,这时候需要做一次feature的rebase,当前的分支情况如下
A--B--C------F--G (master)
\
D--E (feature)
这时候我们希望合并之后长这样:
A--B--C------F--G (master)
\
D'--E' (feature)
但是我们在本地合并之后无法推送到远程分支,被拒绝了,但是可以走git push --force
强推解决问题,那么为什么不能推到远程分支呢?
解答
我们需要解答几个问题:
- git push的合并方式是什么样的?
- fast-forward是什么?
- 为什么git push会有fast-forward?
第一个问题:git push使用fast-forward进行合并,对于local(本地分支)和origin(远程分支)分支来说,区别应该只是local多了一些新的commit,所以push的结果是在远程的基础上往前移动指针,覆盖新的commit。
第二个问题:
在合并的时候,你应该注意到了“快进(fast-forward)”这个词。 由于你想要合并的分支
hotfix
所指向的提交C4
是你所在的提交C2
的直接后继, 因此 Git 会直接将指针向前移动。换句话说,当你试图合并两个分支时, 如果顺着一个分支走下去能够到达另一个分支,那么 Git 在合并两者的时候, 只会简单的将指针向前推进(指针右移),因为这种情况下的合并操作没有需要解决的分歧——这就叫做 “快进(fast-forward)”。
第三个问题:Git 为了保护远程分支不被覆盖,所以无法在不丢失提交的情况下对远程仓库进行更改,发生此情况时,推送会被拒绝。更多知识
所以最终我们知道:git push使用的是快速合并(fast-forward merge),所以无法解决本地与远程基不一致的合并,出现冲突则不允许提交,这时候的解决办法就是强推 git push -f
。
但是这显然也要考虑到是不是会有多人协作的问题,比如有人在你正好要强推之前提交了代码,你就会把他的代码覆盖掉,这时候别人的提交就会有问题!因此在下面有一个回答提到了一个安全的强制提交命令git push --force-with-lease
,使用此参数推送,如果远端有其他人推送了新的提交,那么推送将被拒绝。