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

Pull Request的正確打開方式(如何在GitHub上貢獻開源項目)

merge pic 包含 div 額外 orm 為什麽 fork 協作開發

Pull Request的正確打開方式(如何在GitHub上貢獻開源項目)

GitHub的官方幫助如下:

  • Fork A Repo: https://help.github.com/articles/fork-a-repo
  • Using Pull Requests: https://help.github.com/articles/using-pull-requests
  • Merging a pull request: https://help.github.com/articles/merging-a-pull-request
  • Closing a pull request: https://help.github.com/articles/closing-a-pull-request
  • Tidying up Pull Requests: https://help.github.com/articles/tidying-up-pull-requests

發現這個官方文檔寫得比較簡單,並沒有提到開源項目協作方式的一些必要的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 merge是GitHub上最常用的merge Pull Requests的方式,在命令行下merge之後,GitHub上面的PullRequest也會相應地自動關閉。

如果貢獻者一次提交了多條commits,有些是維護者並不想要的,可以用這幾條命令來選擇性地手動commit。(這也適用於某些項目不是借助於GitHub的Pull 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)的貢獻方式更可取。

Pull Request的正確打開方式(如何在GitHub上貢獻開源項目)