1. 程式人生 > >Pull Request的正確開啟方式(如何在GitHub上貢獻開源專案)

Pull Request的正確開啟方式(如何在GitHub上貢獻開源專案)

GitHub的官方幫助如下:

發現這個官方文件寫得比較簡單,並沒有提到開源專案協作方式的一些必要的trick(比如建立topic branch),還有PullRequest的運作細節也沒有提到。寫個簡單的總結補充一下。

Step 1: Fork原專案

這個不解釋了,單擊一下滑鼠就能做到的事情。參見GitHub幫助的原文

記得用git remote add新增上游遠端庫的地址,否則無法追蹤上游庫的更新。

Step 2: 建立你的主題(topic)branch

這一步非常重要GitHub的幫助裡沒有提到建立主題branch的必要性,你當然可以直接在原專案的預設branch(如master)上進行工作,但實際上:

如果打算為原專案作貢獻,強烈建議你為每個主題建立一個單獨的branch。

舉例:如果需要修復原專案的一個和Unicode相關的issue:

$ git branch fix-unicode-error
$ git checkout fix-unicode-error

然後在自己的主題branch(這裡是fix-unicode-error)下進行工作。

Step 3: 在主題branch下完成需要的工作

記得push相應的主題branch到GitHub

*(針對貢獻者)rebase還是merge

從實用的角度來講,

  • 當你在主題branch下工作,想要匯入來自上游庫的(與你當前的工作不衝突的情況下)更新時,使用git rebase

例如,(假設上游branch為upstream/master)

$ git rebase upstream/master fix-unicode-error

或者直接(如果當前branch已經是fix-unicode-error):

$ git rebase upstream/master

這將把當前branch的開發“base(基礎)”推進到一個新的起點,而不會引入多餘的commits。

  • 當你在某個branch下工作時,git merge可以用來合併來自其他branch的更新。

如果merge的branch來自遠端庫,一次merge操作會增加一個額外的commit(“Merge branch 'master' of something”)。如果在一個需要傳送Pull Request

的主題branch下面進行這種操作,(我個人覺得)這不是一種乾淨的手段。

當你在主線branch(例如master)下進行開發時,git merge可以用來吸收其他開發branch引入的新特性(包括主專案維護者用來直接merge Pull Requests),很恰當。

Step 4: 傳送第一個Pull Request

GitHub的介面:左邊選擇base branch,右邊選擇head branch。

  • base branch:相當於target branch,你希望Pull Request被merge到上游專案的哪個branch裡。

    • 為什麼要叫base branch:base可以理解為你在進行git rebase操作時的那個“base”,也就是你的主題branch所基於的開發base(基礎)。
  • head branch:相當於source branch,你希望自己開發庫裡的哪個branch被用來進行Pull Request(當然也就是你的主題branch)。

    • 為什麼要叫head branch:參見下面關於head的定義。

注意head與HEAD(大寫)的區別:

  • head:簡單地理解,就是指向某個commit物件的一個reference。它可以是一個branch的名稱(例如,預設的master),也可以是一個tag的名稱。一個庫可以同時有任意多個head。

  • HEAD當前活動的head。在任意時刻,存在且僅存在一個HEAD。它可以是指向當前branch的head(比如,指向master,假如master是當前branch的話);也可以不指向任何特定的branch(這叫做detached HEAD)。

系統會從你選擇的head branch(在這裡,是主題branch)的這個head開始匹配所有不包含在base branch中的commits,然後自動視作你的主題branch相對於base所增加的新特性,放進同一個Pull Request中提交。

Step 5: Pull Request傳送之後……

一旦你從自己的主題branch(例如fix-unicode-error)推送了一條Pull Request,那麼在這條Pull Request被關閉之前,再次向這個branch裡push程式碼,所有的commits都會被自動追加到這個Pull Request後面(不需要再另開Pull Request)。

這個功能尤其有用,比如你最初提交的Pull Request裡存在某些問題,專案維護者要求你打回去修改;或者要求你給你的新feature新增一條相應的unit test(這種情況簡直太常見了)。只要追加commits到你的這個主題branch中即可。

(題外話:如果原專案有Travis CI,那麼它也會在每次追加push之後對Pull Request重新執行一遍測試)

*(針對專案維護者)cherry-pickformat-patcham

這幾條命令主要針對專案的維護者,稍微提一下。

git pullgit mergeGitHub上最常用的merge Pull Requests的方式,在命令列下merge之後,GitHub上面的PullRequest也會相應地自動關閉。

如果貢獻者一次提交了多條commits,有些是維護者並不想要的,可以用這幾條命令來選擇性地手動commit。(這也適用於某些專案不是藉助於GitHubPull Request,而是通過郵件列表和patch檔案來進行協作開發的情形)

在這種情況下,GitHub上面的Pull Request並不能自動關閉,需要維護者手工操作。

Step 6: Pull Request關閉之後

如果是已經被merge後關閉的Pull Request,你可以在頁面的最下方找到一個“Delete this branch”的藍色按鈕。

這表明這個主題branch的歷史使命已經完成(fix-unicode-error的commit已經被合併到主專案中),可以安全地從遠端庫中刪除了。

在本地庫中亦可刪除這個branch:

$ git branch -d fix-unicode-error

反之,如果你的主題branch並沒有被merge就被維護者關掉的話,你還可以繼續再拿它來開新的Pull Request去騷擾主專案(�0�7▽‘ )。

總結

在哪些情況下可以直接使用master branch來提交Pull Request

  • 你只想為主專案貢獻某一處程式碼,貢獻完自己的repo就可以扔的那種。
  • 你打算為主專案長期貢獻程式碼,而且希望追隨原專案的主線開發,不保留自己的特性。
  • 你打算為主專案長期貢獻程式碼,預設master branch追隨原專案主線,把自己的特性放到別的branch中。

在哪種情況下應該使用主題branch來提交Pull Request

  • 想用master branch完全來做自己的開發。在這種情形下:
    • 會從上游庫合併更新,但是這些merge本身的commits顯然不可能作為返還到上游庫的Pull Request的一部分。
    • 存在自己的(未被merge或者不想被merge到上游庫的)commits。

鑑於Git的分散式開發哲學,每一個庫均可以看作是一個獨立的專案,顯然是後一種(為每一個新特性建立一個專門的主題branch來向主專案推送Pull Request)的貢獻方式更可取。