在 Github 上以提交 PR 的方式參與開源項目是十分簡單的。不過因爲 Git 自己自由度較高,有些隨意提出的 PR 其實是會影響項目歷史記錄的【髒】PR。下文介紹什麼時候會發生這種狀況,以及如何經過 rebase 工做流改進它。git
咱們知道,若是你想爲某個開源項目貢獻代碼,通用的流程是:shell
在最後一步中,你所提交的 PR 會包括新分支上所有的歷史記錄。這時候,若是出現下面的幾種狀況之一,在這裏咱們就認爲這個 PR 屬於【髒】PR:vim
fix bug
/ add dev
等缺少實際意義的提交信息。fetch
原倉庫後將 HEAD merge
到當前分支。這個操做每執行一次,就會在當前分支留下一個相似 Merge xxx
的 commit 記錄。上述的幾種狀況,在開發託管在 Stash 或 Gitlab 上的內部項目時,其實都不是問題,都有着很是簡單的解決方案:安全
git log --graph
,多麼壯觀!你們都很努力的好嗎!並非說這麼處理有什麼問題,尤爲在中國特點每天趕進度的業務項目中,這麼作也基本上是最佳實踐了。下面,咱們重點討論的是在較爲正式地向外提交 PR 時,提高 PR 質量的方法。bash
Github 在很早以前就支持了強制 squash 功能。經過這種方式,原倉庫的維護者能夠在將 PR 提交的分支所更改的內容,squash 到主倉庫的一次提交中。這樣,無論提出 PR 的分支有多【髒】,均可以在併入時獲得淨化了。這大體至關於命令行下這樣的操做:fetch
git merge forked_lib/new_branch --squash
git commmit -m 'something from new_branch'複製代碼
這是獲得 Github 官方支持的實踐,但這麼處理有什麼侷限性呢?主要是這兩點:this
這個方式最棘手的問題實際上在於:它把編輯提交歷史的責任丟給了原倉庫的維護者,PR 提交者並不能在提交 PR 前清理歷史記錄。是否有更好的方案呢?spa
經過 git rebase 命令,咱們可以得到對 git 提交歷史更大的掌控。不過,這也是一個存在風險的命令,所以在實際使用前建議稍加了解其原理。命令行
首先假設項目主幹分支是 master,你在 fork 而來的倉庫下新增了 dev 分支。你從 master 的 m1 提交開始,在 dev 提交了 d一、d2 和 d3 三次提交。這時,master 也更新了 m2 和 m3 兩次提交。這時候版本樹大體長這樣:調試
m0 -- m1 -- m2 -- m3
|
d1 -- d2 -- d3複製代碼
這時你的目標是將三次 dev 上的 commit 合併爲一個新的 d
,讓 dev 的歷史變成這樣:
m0 -- m1 -- m2 -- m3 -- d複製代碼
爲了實現這一點,你能夠在 dev 上 rebase 到 master:
git checkout dev
git rebase -i master複製代碼
rebase 的原理是:
在【依次應用修改】的這一步中,你能夠進一步選擇如何對待 d一、d2 和 d3 的 commit message。在以 -i
參數啓動了交互式的 rebase 後,會進入 vim 界面,由你選擇如何操做 dev 上的提交記錄,形如這樣:
pick 91398f93 d1
pick 65efc762 d2
pick b82e050d d3
# Rebase 4652f96d..b82e050d onto 4652f96d (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out複製代碼
你能夠編輯對 dev 上這幾個 commit 的處理,如輸入 pick 爲保留,輸入 squash 則將該 commit 內容併入上一個 commit 等。在完成操做選擇後(這裏咱們能夠選擇 fixup d1 和 d2,並 reword d3),輸入 :wq
保存退出,會進入一個新的 vim 窗口,在此你能夠進一步編輯新的 commit message,保存後 rebase 便可生效。注意,你至少須要選擇一個須要 use 的 commit,不然會報錯。
rebase 生效後再查閱分支歷史記錄,是否是清淨多了呢?在這個狀態下提交更清爽的 PR 吧😉
在此額外提醒一點,對於已經被 fork 出多份的倉庫,rebase 原倉庫的主幹是危險操做。除此以外,使用 rebase 修改私有分支的歷史記錄是很安全的。
回頭看看髒 PR 的幾個問題,如何經過 rebase 解決呢?
到此,對 rebase 的介紹大致上就結束了。但願對你們更好地參與開源項目有所幫助。
參考: