改進合作 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