改进合作 Git 工作流:自动提取、合并提交
每天,美团的上百名工程师都在不断改进美团的用户体验,或是加入各种新鲜的功能。作为负责展现、交互的前端工程师,我们上线的次数可达一天数十次。
我们使用 Stash 托管项目代码。每个功能都新增一个新任务分支 (feature branch),当开发测试完成后,推送任务分支到 Stash 上,并创建 pull request 进入代码审查,直到被通过,等待上线。
为了保证开发速度,我们不断改进完善这个发布流程,让这个过程更简单、高效。
前端工作现状
前端工作是连接后台实现和视觉表现交互的桥梁,前端工作有以下特点:
- 往往需要和后端工程师合作开发
- 在测试时也需要 checkout 后端代码,并在此基础上进行开发
- 双方频繁 merge/rebase 分支
- 每个人使用 Git 的方式不太一样,我们的工作流需要较强的适应性
- 在开发测试完成之后,我们要求每一次上线的代码都必须经过 pull request 加代码审核
多人合作开发的一般工作流可以参见 A successful Git branching model 和 Git Workflows,在一般开发阶段使用 merge 或 rebase 都能够胜任。
但在 pull request 之前我们需要把双方的提交分开,这个工作往往还不够自动化。一种常见的做法是git reset --soft HEAD~将所有改动移出暂存区 (staging area),然后手工添加那些我们改了的文件。
事实上,我们可以用 rebase 来帮我们提高效率,实现自动提取、合并提交。
rebase 是什么?
首先简单介绍一下 rebase(衍合),git-scm 上有很好的介绍(中文翻译),简单的说,git rebase A B会把在 A 分支里提交的改变移到 B 分支里重放一遍。
它的原理是回到两个分支最近的共同祖先,根据 B 的历次提交对象,生成一系列文件补丁,然后以 A 为基底分支最后一个提交对象为新的出发点,逐个应用之前准备好的补丁文件,最后会生成一个新的合并提交对象,从而改写 B 的提交历史,使它成为 A 分支的直接下游。
通过修改提交历史,我们可以更方便的准备 pull request。
用 git rebase 来提取、合并提交
比如说后端的 Alice 和前端的 Bob 合作开发一个功能,他们分别从 master 分支上 checkout,并开始工作。
他们互相 merge 对方的分支的进行开发、测试。最终,这个功能开发测试完成,Bob 合并了 Alice 的分支(图中星号的位置),可以进入代码审核和上线的流程了。
这时候 Alice 和 Bob 需要提取、合并各自的提交,并分别发送 pull request 进入代码审核。我们站在 Bob 的角度来解释一下如何使用 rebase 来方便的做到这一点。
Bob 现在处在 bob/fb 上(图中星号的位置),这时候 bob/fb 实际上包含了 alice/fb 的所有提交。首先我们从 bob/fb 上新建一个分支
// 准备一个新的分支 $ git checkout -b bob/review
然后我们通过 rebase 把自己的提交排到一起
// 把 Alice 的提交和自己的提交分别排在一起 $ git rebase alice/fb
接下来我们把 bob/review 上的提交合并
// 用 interactive rebase 合并提交 $ git rebase -i HEAD~`git rev-list --first-parent master...bob/fb --no-merges --count`
执行上面这行命令会打开终端默认的编辑器(可通过 EDITOR 环境变量设置)。
这些信息表示从在 bob/review 上找到了两个在 bob/fb 上的提交。每个提交都另起一行来表示,行格式如下:
(action) (partial SHA-1) (short commit message)
按照下面的提示,我们可以把除了第一行外的 pick 替换成 fixup (f) 或是 squash (s) 来实现合并提交。另外,上下移动一行可以对提交进行重排序。一旦你完成对提交信息的编辑,并退出编辑器,git 会按照你指定的顺序去应用提交,并且做出相应的操作(action),形成的新提交和提交信息会被保存起来。(备注:在 Git 1.7 之后,我们还可以使用rebase --autosquash自动合并提交,进一步提高生产效率。)
合并完之后我们的分支是这样的
然后,我们可以使用rebase --onto取出 bob/review 上有而 alice/fb 上没有的提交,并指定新的基底分支(也就是主干分支 master)
// 取出 Bob 的提交,并排除 alice/fb 上的提交 git rebase --onto master alice/fb bob/review
这样在 bob/review 分支上就只有 Bob 自己的提交了。
这时候就可以用git merge master或者git rebase master来更新分支,然后发送 pull request 进入代码审核环节了。
小结
以上是我们处理代码审查之前提取、合并提交的一点思考和实践。例子中命令虽然长,但可以很方便的写成一个脚本自动进行,除非遇到冲突,否则需要人工 干预的情况并不多在。在美团,我们一直努力用好现有工具,降低重复操作,让工具自动化融入工作流程之中,成为我们不断提升工作效率的重要帮手。希望我们的 实践能对你有帮助。
来自:http://tech.meituan.com/improving-git-flow_squashing-commits.html