Git Rebase操作

概括

rebase翻译过来为“变基”,可以理解为改变基础,它可以用于分支合并和修改提交记录。

合并分支的区别

我们知道merge操作也可以用于分支合并,但是其和rebase操作有着明显的不同。假定有一个分支foo在B提交处检出了分支bar,接着两个分支各自前进出现了分叉,现在要将bar分支合并回foo分支。

A--B--C----E  foo
    \
     ----D  bar

首先使用merge操作,在foo分支下执行git merge bar命令,git就会在当前分支(即foo分支)下生成一个新的commit节点,从而实现分支的合并。

A--B--C----E---F foo
    \         /
     ----D----
        bar

而reabse操作合并分支的过程与之明显不同,我们在foo分支下执行git rebase bar命令。

现在来看看rebase操作的合并过程,它先是会暂存当前分支上从分叉开始之后commit节点,然后回退到分叉开始的节点。

stage: C, E

A--B  foo
    \
     ----D  bar

接着bar分支上的所有commit被移动到foo分支上,最后再合并之前暂存的节点。

A--B--D--C'--E' foo
    \
     ----D  bar

可以看到rebase操作合并之后的提交记录是一条线,而不像merge操作一样变成棱形,因此rebase操作合并分支会让提交记录看起来更加简洁。

工作流程

接下来基于rebase操作设计一个简单的分支协同开发流程,流程分为检出分支前和分支上提交后两个部分。

检出之前先在dev分支上pull以获取分支上最新提交,这样可以减少后续提交时的冲突,当然该步骤不是必须的。

接着便可以检出分支来进行开发,下面是该流程的命令示例。

[origin/dev => dev => ${new_branch}]

(dev)$ git pull
(dev)$ git checkout -b ${new_branch}

开发完成并在本地分支上提交后,就可以进行分支的合并了,首先还是先pull拉取dev分支上的最新提交。

接着分为两种情况,一种是没有其他人提交显示“Already up to date.”,这时候就直接切换到dev分支,然后执行rebase操作合并分支,最后提交到远程。

还有一种当然是有人提交过了,这时候就要先执行rebase操作将dev分支合并到当前开发的分支,接着可能就会出现冲突,需要手动修改冲突后执行git add ${conflict_file}git rebase --continue完成冲突修改。

冲突修改之后的操作和前面是一样的这里不再叙述,详细请参考下面的命令示例。

[${new_branch} => dev => origin/dev]

(${new_branch})$ git pull origin dev:dev
=========IF NOT UP TO DATE=========
(${new_branch})$ git rebase dev
(${new_branch})$ <fix the conflict>
===================================
($(new_branch))$ git checkout dev
(dev)$ git rebase ${new_branch}
(dev)$ git push

修改提交记录

rebase操作除了合并分支,还可以用于提交记录的修改。

当然一般不推荐在多人协同开发的分支上修改提交记录,一来是修改记录时的误操作可能会导致提交数据丢失。

二来是使用rebase修改提交记录后,需要使用--force选项强制推送到远程,假设刚好有其他人提交了代码而你没有及时更新,就会导致其他人的代码被你覆盖掉。

rebase操作修改提交记录其实也很简单,先是执行命令git rebase -i <START> [END],选项-i指的是使用交互式操作方式,后面两个参数是操作的范围。

这里<START>指的是开始的提交记录,而[END]则是结束的提交记录,如果结束的提交记录省略则默认为HEAD。注意这里范围是前面为开区间后面为闭区间,用区间表示为(START, END]。提交记录既可以用哈希值表示,也可以用头指针的偏移值表示,例如HEAD~1表示头指针指向的上一个提交。

上面命令执行完之后,就会出现如下格式的文本,同commit一样都是使用编辑器打开,修改完成后保存即可。

pick acaa54 Add `demo.md`
pick baed03 Add one line

每一行代表一个提交记录,第一个字段是对提交记录的操作命令,第二个字段是提交记录的哈希值,最后则是提交记录的注释。

下面是完整的操作命令和其作用,默认为pick命令即表示使用该提交记录且不做更改。

# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.

总结

虽然rebase操作功能强大,但掌握其正确使用才是重中之重。还有使用rebase还是merge合并分支仍有争议,两种方式各有利弊,这需要团队内部进行权衡选择。

猜你喜欢

转载自www.cnblogs.com/linzhehuang/p/13377381.html