很抱歉,你的童年已走失
六一儿童快乐!
Git
上面的这个图就是很好的解释了,在公司的项目代码仓库,你的远程仓库的master是主分枝,你只有在经过你分枝代码提交和检验过后才会有权限合并你的代码到分枝。但是这样也会带来冲突,这里我们着重介绍两个概念吧,git Merage和Rebase.
git rebase 这个命令经常被人认为是一种Git巫术,初学者应该避而远之。但如果使用得当的话,它能给你的团队开发省去太多烦恼。在这篇文章中,我们会比较git
rebase 和类似的git merge 命令,找到Git工作流中rebase的所有用法。
概述
需要知道的第一件事是, git rebase 和 git merge 做的事其实是一样的。它们都被设计来将一个分支的更改并入另一个分支,只不过方式有些不同。
想象一下, 刚创建了一个专门的分支开发新功能,然后团队中另一个成员在master分支上添加了新的提交。这就会造成提交历史被Fork一份, 用Git来协作的开发者应该都很清楚。
现在,如果master中新的提交和你的工作是相关的。为了将新的提交并入你的分支,你有两个选择: merge 或 rebase。
Merge
将master分支合并到feature分支最简单的办法就是用下面这些命令:
git checkout feature
git merge master
或者,你也可以把它们压缩在一行里。
git merge master feature
feature分支中新的合并提交(merge commit)将两个分支的历史连在了一起。你会得到下面这样的分支结构:
merge好在它是一个安全的操作。现有的分支不会被更改,避免了rebase潜在的缺点(后面会说)。
另一方面,这同样意味着每次合并上游更改时feature分支都会引入一个外来的合并提交。如果master非常活跃的话,这或多或少会污染你的分支历史。虽然高级的git
log 选项可以减轻这个问题,但对于开发者来说,还是会增加理解项目历史的难度。
Rebase
作为merge的替代选择, 你可以像下面这样将feature分支并入master分支:
git checkout feature
git rebase master
它会把整个feature分支移动到master分支的后面,有效地把所有master分支上新的提交并入过来。但是, rebase为原分支上每一个提交创建一个新的提交,重写了项目历史, 并且不会带来合并提交。
rebase最大的好处是你的项目历史会非常整洁。首先,它不像git merge 那样引入不必要的合并提交。其次,如上图所示,rebase导致最后的项目历史呈现出完美的
线性――你可以从项目终点到起点浏览而不需要任何的Fork。这让你更容易使用git log 、git bisect 和gitk 来查看项目历史。
不过,这种简单的提交历史会带来两个后果:安全性和可跟踪性。如果你违反了Rebase黄金法则,重写项目历史可能会给你的协作工作流带来灾难性的影响。此外,
rebase不会有合并提交中附带的信息――你看不到feature分支中并入了上游的哪些更改。
交互式Rebase
交互式的rebase允许你更改并入新分支的提交。这比自动的rebase更加强大,因为它提供了对分支上提交历史完整的控制。一般来说,这被用于将feature分支并入
master分支之前,清理混乱的历史。
把-i 传入git rebase 选项来开始一个交互式的rebase过程:
git checkout feature
git rebase -i master
它会打开一个文本编辑器,显示所有将被移动的提交:
pick 33d5b7a Message for commit #1pick 9480b3d Message for commit #2
pick 5c67e61 Message for commit #3
这个列表定义了rebase将被执行后分支会是什么样的。更改pick 命令或者重新排序,这个分支的历史就能如你所愿了。比如说,如果第二个提交修复了第一个提交中
的小问题,你可以用fixup 命令把它们合到一个提交中:
pick 33d5b7a Message for commit #1fixup 9480b3d Message for commit #2pick 5c67e61 Message for commit #3
保存后关闭文件,Git会根据你的指令来执行rebase,项目历史看上去会是这样:
忽略不重要的提交会让你的feature分支的历史更清晰易读。这是git merge 做不到的。
Rebase黄金法则
当你理解rebase是什么的时候, 最重要的就是什么时候 不能 用rebase。git rebase 的黄金法则便是:绝不要在公共的分支上使用它。
比如说, 如果你把master分支rebase到你的feature分支上会发生什么:
这次rebase将master分支上的所有提交都移到了feature分支后面。问题是它只发生在你的代码仓库中,其他所有的开发者还在原来的master上工作。因为rebase引起
了新的提交,Git会认为你的master分支和其他人的master已经分叉了。
同步两个master分支的唯一办法是把它们merge到一起,导致一个额外的合并提交和两堆包含同样更改的提交。不用说,这会让人非常困惑。
所以, 在你运行git rebase 之前,一定要问问你自己“有没有别人正在这个分支上工作?”。如果答案是肯定的,那么把你的爪子放回去,重新找到一个无害的方式
(如git revert )来提交你的更改。不然的话,你可以随心所欲地重写历史。
强制推送
如果你想把rebase之后的master分支推送到远程仓库,Git会阻止你这么做,因为两个分支包含冲突。但你可以传入--force 标记来强行推送。就像下面一样:
# 小心使用这个命令!
git push --force
它会重写远程的master分支来匹配你仓库中rebase之后的master分支,对于团队中其他成员来说这看上去很诡异。所以,务必小心这个命令,只有当你知道你在做什么
的时候再使用。
仅有的几个强制推送的使用场景之一是,当你在想向远程仓库推送了一个私有分支之后,执行了一个本地的清理(比如说为了回滚)。这就像是在说“哦,其实我并不想
推送之前那个feature分支的。用我现在的版本替换掉吧。”同样,你要注意没有别人正在这个feature分支上工作。
工作流
rebase可以或多或少应用在你们团队的Git工作流中。在这一节中,我们来看看在feature分支开发的各个阶段中,rebase有哪些好处。
第一步是在任何和git rebase 有关的工作流中为每一个feature专门创建一个分支。它会给你带来安全使用rebase的分支结构:
本地清理
在你工作流中使用rebase最好的用法之一就是清理本地正在开发的分支。隔一段时间执行一次交互式rebase,你可以保证你feature分支中的每一个提交都是专注和有意义的。你在写代码时不用担心造成孤立的提交――因为你后面一定能修复。
调用git rebase 的时候,你有两个基(base)可以选择:上游分支(比如master)或者你feature分支中早先的一个提交。我们在“交互式rebase”一节看到了第一种的例子。后一种在当你只需要修改最新几次提交时也很有用。比如说,下面的命令对最新的3次提交进行了交互式rebase:
git checkout feature
git rebase -i HEAD~3
通过指定HEAD~3 作为新的基提交,你实际上没有移动分支――你只是将之后的3次提交重写了。注意它不会把上游分支的更改并入到feature分支中。
作者:远方
前端和golang后端微服务开发,架构,团队主要关注前端,客户端,并发响应。现在就职于外企,技术总监,微服务架构。
扫一扫,马上开机!
本文出自 “知乎技术” 博客,请务必保留此出处http://liuzhiying.blog.51cto.com/5850988/1931424