git rebase¶
git rebase命令的作用是以另外一个分支为基础, 重建当前分支的父节点(将另一个分支的修改合并到当前分支).
基本语法:
# 以另外一个分支为基础, 重建当前分支的父节点 git rebase <another_branch>
假设当前版本库的状况如下:
假设我们在mywork这个分支做了一些修改, 然后生成两个commit; 与此同时, 其他人在origin分支上做了一些修改并做了提交. 这意味着origin和mywork这两个分支各自前进了.
现在的状况如下:
可以使用git pull命令把origin分支上的修改拉取下来并且和当前分支合并,生成一个新的合并提交(merge commit).
git checkout mywork
git merge origin
但是, 如果想让mywork分支的历史看起来像没有经过任何合并一样, 可以使用rebase.
git checkout mywork
git rebase origin
rebase的过程¶
rebase并不是简单的剪下/贴上commits的过程, 在rebase过程中会生成commits, 并重新计算commits的Id.
以上面的例子来说, rebase的过程大致如下:
- 先将
c68537这个commit接到053fb2这个commit上, 因为c68537原本的上一层commit是e12d8e, 现在要接到053fb2上, 所以要重新计算这个commit的SHA-1值, 重新生成一个新的commit对象35bc96;- 再将
b174a5这个commit接到刚才那个新生成的commit对象35bc96上, 同理, 因为b174a5这个commit要接到新的commit的原因, 所以它也会重新计算SHA-1值, 得到一个新的commit对象28a76d;- 最后, 原本的分支指针
cat是指向b174a5这个commit, 现在要改为指向那个新的commit对象28a76d;HEAD还是指向cat分支.
谁rebase谁有差吗?¶
以最后的档案来说没什么差别, 但以历史记录来说有差别, 谁rebase谁, 会造成历史记录上的先后顺序的不同.
rebase时出现冲突¶
在rebase 的过程中, 也许会出现冲突(conflict).
在这种情况下, Git会停止rebase并提示解决冲突; 在解决完冲突后, 使用git add命令更新这些内容到暂存区,
然后执行git rebase --continue, 这样Git会继续应用余下的补丁.
或者, 当rebase出现冲突时, 可以使用git rebase --abort命令来终止rebase的操作, 并使分支回到rebase之前的状态.
取消rebase¶
使用git merge进行的合并, 通常使用git reset --hard HEAD^就可以回退到合并之前的状态.
对于git rebase, git reset --hard HEAD^只会回退到前一个commit, 并不会回到rebase之前的状态.
使用
git reflog使用
git reflog查看rebase之前的commit id, 然后使用git reset --hard commit_id退回到rebase之前的状态.使用
ORIG_HEAD在Git中有一个特别的记录点叫
ORIG_HEAD, 会记录危险操作之前HEAD的位置. 例如分支合并或是reset之类的都算是所谓的危险操作.透过这个记录点来取消
git rebase相对的简单:git reset --hard ORIG_HEAD.
何时使用git rebase¶
使用git rebase来合并的好处是它不像git merge那样生成一个额外的合并提交, 而且历史顺序可以按照谁rebase谁而决定;
但缺点就是它相对的比一般的合并来得没那么直觉, 而且不小心可能会弄坏掉而且不知道怎么reset回来, 或是发生冲突的时候就会停在一半, 对不熟悉git rebase的人来说是个困扰.
通常还没有推送(push)出去但感觉有点乱的commit,可以使用git rebase整理再推送出去.
但git rebase等于是修改历史, 修改已经推送出去给别人的历史可能会对他人造成困扰, 所以对于已经推送出去的内容, 非必要的话应该尽量避免使用git rebase.
参考文章: