git随笔1(不理解git rebase本质)

95 阅读2分钟

对rebase -i理解不深,记录下问题和解决办法。。。

想法: 把自己的C10-C15这几个commit合并到一起( 这里应该用git rebase -i HEAD~6)?

但当时用了git rebase -i HEAD~10。

操作了C6-C9这几个已经被合并到master的commit。 主要是错误认为,如果对C6-C9选择pick,反正C6-C9已经是提交的了,不会有影响

实际上,rebase -i会导致被pick的commit产生一个副本...

image.png

如图,尽管C6'-C9' 改动内容完全一样,但是remote视为不同的提交。。。

在这种情况下,如果我们git push,然后提一个merge request,就会附带上C6'-C9'。

image.png

如图,我们假设C15'是 squash了C10-C15的提交,但由于错误的操作,导致C6-C9被创造了一个副本,C6'-C9',并且此时本地的master和远程的master已经处于不同分支了

当时想的是,反正C6-C9采取pick的话,不就等价于在C6-C9这个branch上修改吗,实际上rebase的含义是,找到要动的结点的祖先,在此基础上创建一个新的branch,原来branch 上的commit作为本地副本。

此时,尽管C6'-C9'(本地) 和远程的C6-C9一一对应,如果我们此时push,会显示不允许push,因为C6'-C9'对于远程origin/master而言,是全新的提交,此时如果强行push,会覆盖远程的C6-C9(这就是关键,尽管他们修改一样,但commitID不一样。。。),所以在本地会发生一次fetch&merge。

如果采取merge request,那么由于此时本地的master和origin/master的公共祖先是C5,此次push会把C6'-C9', C15'都带上去。。。体现在merge request上有一堆其他人已经commit的提交。

解决办法是,从reflog里找到这次git rebase的提交,git reset --hard到这个提交上。等价于我们找回了本地副本,也就等价于回到了本地的C10-C15。这样的话,我们可以git fetch,git rebase,让master和origin/master同步,再fork一个新的分支,把自己的commit 合到新的分支上。再push即可。此时对于remote,就不存在"内容相同但是commitID不同的本地副本提交了"

image.png

image.png

正确做法是上图,我们发现如果git rebase不操作origin/master上的提交,那么即便是新的branch,也是基于origin/master修改的,此时一个push就能把本地提交交上去。