Open FrankKai opened 5 years ago
merge 是Git中最简单也是最常用的集成change的方法,但是这并不是唯一的一种方式。 Rebase是另外一种可选的但是略微高级的集成方式。
通常情况下,一个由人类认真创建的commit,是一个有意义的单元:它仅仅包含相关的change并且每个commit都伴随着一个comment。 有一种merge commit可以让所有comments丢失:Git自动创建的commit,并且由Git填充所有的differ change。没有语义,没有主题。当然,这些独立commits的内容是保留的。但是history分成了注释的,分离的有意义的commit,由于这个原因,在一次merge commit中不会保留。 这就是为什么有些人不喜欢merge,喜欢rebase的原因。
与一笼统把commits塞到一个commit不同,一个rebase会保留原始的commits。
项目的历史是一条单的,直线。没有任何迹象表明它在某个时候拆分出一个分支来。
在一次rebase后,看起来就像development从来没有被拆分成不同的分支。
我们来一步一步拆分一个rebase操作。方案很简单:我们想用rebase集成branch-B到branch-A。
一个rebase之前的方案。
命令很简单:
git rebase branch-B
首先,线条开始分支后,Git将"undo"所有的branch-A上的commits(在共同的祖提交后)。当然,它不会丢弃它们,而是临时将它们存了起来。
其次,它会应用我们想集成的来自branch-B的commits。此使,两个分支是相同的。
最后,branch-A的新commits重新被应用,但是在一个新的位置,在branch-B的后面。(they are rebased)。
结果就是development在一条直线上开发。不是一个commit包含了所有的改变,而是让原始commit结构保持原样。
下面尝试开BranchA,BranchB两个分支,然后基于webstorm的Version Control,观察git rebase操作会不会有上述的变化。
BranchA
BranchB
Rebase BranchA onto branchB
其实就是将branchB的母分支branchA进行了integrate changes,也就是把branchB的2次commit,放在共同的起点与branchA的新commit之间,或者也可以理解成将branchA的新commit,移动到了branchB的2次commits之后。
rebase的是谁,就修改的是谁 onto的是谁,谁就是被rebase的分支的新commits
其实,rebase只做了一件事:更新base branch!(重点!重点!重点!)
而想将谁的更新内容作为新的base branch的提交,就将作为topicBranch。
非常重要的命令。
git checkout baseBranch
git rebase topicBranch
再说的通俗一点,其实就是:挑了一个branch,把它的特性拿过来,放在我的新特性之前。
看完上面这篇文章后,并没有搞清楚rebase做了什么操作,所以还是需要多读一些文章。
git checkout feature
git merge master
git merge master feature
会有一个'merge commit', 但是merge是非常安全的,不会像rebase有很多陷阱。
但是若master非常活跃,每次merge都会有要给'merge commit',会导致feature的commit history很脏。
git checkout feature
git rebase master
feature从master tip处开始合并master上的commits
重写project的history
rebase后,project的history更加干净了。没了多余的'merge commit',并且成了一条线。
rebase 需要遵循Golden Rule of Rebasing,否则会导致灾难性的合作workflow。
rebase 会丢失掉merge commit,导致看不到之后合并到feature的commit。
git checkout feature
git rebase -i master
pick 33d5b7a Message for commit #1
pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
pick 33d5b7a Message for commit #1
fixup 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
永远不要在public 分支上使用git rebase!
每次使用git rebase前,问自己"有没有人也正在基于这个branch写代码?"若是的话,就老老实实用merge,不要尝试rebase。
若有gitflow的经验,其实就是当你开了一个feature/foo时,若同事也开了一个feature/bar,而且你们是同时基于develop checkout出来的分支,那么当develop有hotfix merge进去时,若你想拉去最新的develop代码,就不能用git rebase,只能用merge,否则会导致同事的develop分支与我们的develop分支不同,而此时她想再与我们保持同步是很复杂的。
若想将rebased的master分支推到远程仓库,Git 将会阻止你,因为它与远程的master分支冲突了。但是,你可以force push。
# 这个命令一定要小心使用
git push --force
下面尝试开master,feture两个分支,然后基于webstorm的Version Control,观察git rebase操作会不会有上述的变化。
master
feature
git checkout feature
git rebase master
# resolve conflict1
git rebase --continue
# resolve confict2
git rebase --continue
Rebase feature onto master
可以理解成下图这样。
Current在WebStorm中指右下角的branch,selected一般指的original branch。
相当于:
git checkout feature
git rebase master
像下图这样:
如果rebase中途出现问题,可以使用git rebase --abort恢复。
git rebase的目的是保持当前feature分支与master主分支同步的另一种方式,虽然与merge的效果相同,但是比merge更加简洁高效。
实际工作中的一个常见场景:在我们的feature开发期间,master上可能发布了很多release,修复了很多hotfix。而且可能刚好影响到了我们目前开发的feature。此时我们需要将feature的代码与master保持同步。
同步有几种方法:自己写一遍;merge;rebase。
在merge PR的过程中,rebase and merge会产生冲突,因此需要补充一下Git rebase的知识点。