GitHub 從單機(jī)到聯(lián)機(jī):玩轉(zhuǎn) Pull Request

最近在參與一個(gè)叫 Exercism 的項(xiàng)目哭当,這是一個(gè)由 GitHub 生態(tài)工程師 Katrina Owen 發(fā)起的編程練習(xí)社區(qū),提供了超過50門語言的練習(xí)溺蕉。作為用戶某宪,你僅需使用命令行工具即可下載和提交練習(xí),提交后還可以和社區(qū)中其他學(xué)習(xí)者交流討論掏秩。

Exercism的社區(qū)互動(dòng)性

在和世界各地的小伙伴們愉快地玩耍了十來天之后或舞,我覺得可以為這個(gè)社區(qū)貢獻(xiàn)些什么。由于我比較擅長 Python蒙幻,所以決定為 exercism/python 這個(gè)倉庫貢獻(xiàn)代碼映凳。我知道很多朋友都是在“單機(jī)模式”下使用 GitHub ——一個(gè)人默默地維護(hù)自己的倉庫,卻始終沒有和他人互動(dòng)乃至協(xié)作過邮破。接下來我將分享第一次踏入開源世界诈豌、“聯(lián)機(jī)”使用 GitHub 的體驗(yàn),并將對(duì)應(yīng) GitHub Flow 手把手教會(huì)你怎么提交 Pull Request(下面簡稱 PR )抒和。

在閱讀本文前矫渔,希望你已經(jīng)具備以下條件:

  1. 已經(jīng)安裝好 Git,能夠用命令行進(jìn)行基本的 Git 操作构诚。如果不熟悉 Git蚌斩,你可以看一下廖雪峰的 Git 教程;如果你對(duì)自己的英文有自信范嘱,那么 Learn Git Branching 這個(gè)互動(dòng)教程一定會(huì)讓你受益更多送膳!

  2. 已經(jīng)注冊(cè)一個(gè) GitHub 帳號(hào),并對(duì) GitHub 的一些基本概念(例如倉庫丑蛤,Issue叠聋,還有我們討論的核心 PR)有所了解。

  3. 擁有一顆在開源社區(qū)呼風(fēng)喚雨的雄心壯志(手動(dòng)滑稽)受裹。

尋找值得解決的 Issue

通常碌补,貢獻(xiàn)的第一步是尋找值得解決的 Issue。選擇正確的 Issue 并不簡單棉饶,除了力所能及厦章,還要看一下有沒有人已經(jīng)在解決這個(gè)問題。你可以看一下這個(gè) Issue 是否有人已經(jīng)回復(fù)打算解決照藻,或者在 Pull Requests 列表中搜索一下有沒有人已經(jīng)在解決袜啃,否則真的就是在浪費(fèi)寶貴的時(shí)間。

選擇合適的 Issue

這里我們選擇解決 rational-numbers: implement exercise幸缕,任務(wù)就是實(shí)現(xiàn)一個(gè)新的練習(xí)群发,名為 rational-numbers晰韵。之所以選擇這個(gè) Issue,是因?yàn)閭}庫維護(hù)者很認(rèn)真地把實(shí)現(xiàn)新練習(xí)的詳細(xì)步驟都告訴了我們熟妓,而且也沒有其他人領(lǐng)這個(gè)任務(wù)雪猪。于是我們回復(fù)一句“I'll work on this”,既是通知維護(hù)者起愈,也是告訴其他人我們已經(jīng)負(fù)責(zé)解決這個(gè) Issue只恨,請(qǐng)不要重復(fù)勞動(dòng)。

好了告材,開始動(dòng)手吧坤次!

準(zhǔn)備工作

第一步:Fork原倉庫

在頁面右上角點(diǎn)擊 Fork 按鈕,隨后就生成了屬于你的倉庫斥赋。

Fork 原倉庫
Fork 來的倉庫

為什么要先 Fork 別人的倉庫呢?不能直接把 exercism/python 直接 clone 到本地嗎产艾?

如果你只是打算閱讀別人的源代碼疤剑,這樣做當(dāng)然是可以的,然后每次你只需要 git pull 就可以獲取最新的代碼了闷堡。但如果你打算貢獻(xiàn)代碼就不能簡單地 clone 了隘膘。由于你不具備 exercism/python 的 write access(寫入權(quán)限),因此你就無法使用 git push 來推送你的修改杠览,這時(shí)候就只能 Fork 到自己的帳號(hào)下弯菊,GitHub 會(huì)為你生成 mRcfps/python(mRcfps 是我的 GitHub 用戶名)。對(duì)于這個(gè) Fork 來的倉庫踱阿,你就擁有了所有的權(quán)限(克隆管钳、修改甚至是刪除倉庫)。這時(shí)候就可以進(jìn)行任何想要的修改了软舌。

第二步:將 Fork 來的倉庫 clone 到本地

在命令行中輸入下面的命令:

$ git clone https://github.com/mRcfps/python.git

第三步:創(chuàng)建新分支

GitHub Flow:創(chuàng)建新分支階段

這一步是最容易被忽視的一步才漆,卻恰恰是正式開始貢獻(xiàn)的第一步。

$ git checkout -b impl-rational-numbers

這里我創(chuàng)建了一個(gè)新的分支 impl-rational-numbers佛点,意思就是 implement (exercise) rational numbers醇滥。在創(chuàng)建分支時(shí)要盡量保證易于記憶、易于辨認(rèn)超营,這樣做有兩點(diǎn)好處:

  • 在多個(gè)分支上切換工作時(shí)會(huì)方便很多
  • 在提交 PR 后便于倉庫主進(jìn)行維護(hù)

一個(gè)需要思考的問題是鸳玩,為什么需要開新的分支?不能直接在 master 分支上修改嗎演闭?

先給出簡單的回答:能不跟,但是非常非常不推薦。

根據(jù) GitHub Flow 的定義船响,master 分支應(yīng)當(dāng)確保始終是可部署的(deployable)躬拢,所以在 master 分支上進(jìn)行開發(fā)和嘗試是非常不推薦的做法躲履。而且 GitHub 的 PR 都是以分支為單位的,如果你選擇 master 分支進(jìn)行開發(fā)聊闯,那么當(dāng)你想要解決另一個(gè) Issue 的時(shí)候就會(huì)變得非常棘手(熟悉 Git 的朋友也許會(huì)說可以通過回退節(jié)點(diǎn)再開新分支工猜,但是那樣分支管理就會(huì)變得一團(tuán)糟)。

貢獻(xiàn)代碼

GitHub Flow:貢獻(xiàn)代碼階段

這里就不展示全部的工作了菱蔬,具體代碼變化請(qǐng)參考這里篷帅。

$ git status
On branch impl-rational-numbers
Changes not staged for commit:

  (use"git add <file>..."to update what will be committed)
  (use"git checkout -- <file>..."to discard changes in working directory)

      modified: config.json
      modified: exercises/rational-numbers/example.py
      modified: exercises/rational-numbers/rational_numbers.py
      modified: exercises/rational-numbers/rational_numbers_test.py
      modified: exercises/rational-numbers/README.md

no changes added to commit (use "git add" and/or "git commit -a")

好的,然后我們進(jìn)行 commit:

$ git commit -am "rational-numbers: implement exercise"

提交工作

GitHub Flow:提交 PR 階段

接下來就是激動(dòng)人心的時(shí)刻:提交我們貢獻(xiàn)的代碼拴泌!

首先魏身,我們需要把修改提交到 mRcfps/python ,也就是我們自己的遠(yuǎn)程倉庫蚪腐。

$ git push -u origin impl-rational-numbers

選項(xiàng) -u 等同于 —set-upstream箭昵。impl-rational-numbers 就是我們剛才進(jìn)行修改的分支。然后回季,我們打開 mRcfps/python家制,也就是我們 Fork 來的倉庫,會(huì)看到一點(diǎn)小小的變化:

Fork 來的倉庫自動(dòng)檢測到新提交的分支

實(shí)際上如果你打開 exercism/python 的頁面也會(huì)出現(xiàn)這樣的提示泡一。然后點(diǎn)擊按鈕 Compare & pull request颤殴,開始編輯我們的 PR:

編輯 PR 信息

這里要說明一下 GitHub 關(guān)鍵詞:當(dāng)使用 fix(es),close(s) 或 resolve(s) 時(shí)鼻忠,如果這個(gè) Pull Request 被合并涵但,會(huì)自動(dòng)關(guān)閉對(duì)應(yīng)的 Issue。這里我標(biāo)出了 Closes #1300帖蔓,那么當(dāng)我們貢獻(xiàn)的代碼被接受時(shí)矮瘟,就會(huì)關(guān)閉 rational-numbers: implement exercise 這個(gè) Issue。正確地使用 GitHub 關(guān)鍵詞能夠極大地方便倉庫維護(hù)者讨阻,他們就不需要去查找對(duì)應(yīng)的是哪個(gè) Issue 并去手動(dòng)關(guān)閉它了芥永。

點(diǎn)擊 Create pull request,進(jìn)行提交钝吮!

討論和評(píng)審

GitHub Flow:評(píng)審討論階段

接下來就是等待埋涧。第二天起來發(fā)現(xiàn)倉庫維護(hù)者回復(fù)我們了。

維護(hù)者進(jìn)行了代碼評(píng)審

他指出我們修改的 config.json 有問題奇瘦,并給出了修改建議棘催。至于他手抖一不小心 approve 我們的修改就不必在意了(再次手動(dòng)滑稽)。

按照他的建議修改好之后耳标,我們提交新的修改醇坝。

$ git commit -am "rational-numbers: fix topics in config.json"
$ git push

可以打開 PR 頁面查看我們新的修改。

新的修改出現(xiàn)在 Pull Request 頁面

部署階段

GitHub Flow:部署階段

倉庫維護(hù)者同意了我們的修改!

維護(hù)者部署了我們的修改

然后他將 exercism/python 的 master 分支并入了我們的 impl-rational-numbers 分支呼猪。他為什么要這么做呢画畅?因?yàn)楫?dāng)我們?cè)谶@個(gè)分支上工作時(shí),exercism/python 的 master 分支上可能提交了新的修改宋距,導(dǎo)致我們的分支并不是最新的轴踱。

master 上新的修改使我們的分支過時(shí)

通過將 master 分支并入我們的分支,我們的分支就能進(jìn)入即將部署(Ready to Deploy)狀態(tài)了谚赎。如果這時(shí)候 CI (持續(xù)集成淫僻,會(huì)在后面講到)報(bào)錯(cuò),這就說明我們的分支還不能部署壶唤,還需要進(jìn)一步修改甚至是回滾雳灵。但是這里,我們合并后的分支通過了 CI 的測試闸盔。

合并階段

GitHub Flow:合并階段

維護(hù)者緊接著就將我們的分支正式并入了 exercism/python 的 master 分支悯辙,這意味著我們的 PR 畫上了圓滿的句號(hào),我們的貢獻(xiàn)真正地進(jìn)入到了原倉庫迎吵!

維護(hù)者合并了我們的分支

由于 impl-rational-numbers 已經(jīng)合并笑撞,可以安全刪除,所以我們點(diǎn)擊 Delete branch 按鈕钓觉,刪除我們遠(yuǎn)程倉庫 mRcfps/python 中的分支。然后在本地輸入下面的命令坚踩,刪除本地分支:

$ git checkout master
$ git branch -D impl-rational-numbers

這里為什么使用 -D 進(jìn)行強(qiáng)制刪除呢荡灾?因?yàn)?impl-rational-numbers 在本地并沒有與 mRcfps/python 的 master 分支合并(不要繞暈了,剛才我們只是和 exercism/python 的 master 進(jìn)行了合并)瞬铸。我們自己的 master 分支推薦用下面介紹到的方法進(jìn)行同步批幌。

一些補(bǔ)充

關(guān)于 PR 生命周期的介紹就到此結(jié)束了。接下來我會(huì)講一些相關(guān)的較為重要的地方嗓节。

保持 Fork 來的倉庫同步

如果其他的貢獻(xiàn)者向 exercism/python 提交代碼荧缘,或者是我們自己提交的代碼,我們的 mRcfps/python 就會(huì)過時(shí)拦宣。要經(jīng)常保持我們 Fork 來的倉庫與原倉庫同步截粗,這樣能盡可能地降低沖突發(fā)生的概率。接下來還是以我們 Fork 來的倉庫 mRcfps/python 為例鸵隧,來與 exercism/python 保持同步绸罗。

首先,查看 mRcfps/python 有哪些遠(yuǎn)程倉庫豆瘫。這里應(yīng)該只有 origin珊蟀。

$ git remote -v
origin  https://github.com/mRcfps/python.git (fetch)
origin  https://github.com/mRcfps/python.git (push)

然后,將 exercism/python 添加進(jìn)我們的 remote 倉庫中外驱,將其命名為 upstream(當(dāng)然也可以取其他名字育灸,但是按照慣例會(huì)更加方便)腻窒。

$ git remote add upstream https://github.com/exercism/python.git

再看看 remote 列表中是不是多了些什么……

$ git remote -v
origin  https://github.com/mRcfps/python.git (fetch)
origin  https://github.com/mRcfps/python.git (push)
upstream        https://github.com/exercism/python.git (fetch)
upstream        https://github.com/exercism/python.git (push)

upstream 已經(jīng)在 remote 列表中!然后我們就可以輕松地進(jìn)行同步了磅崭。先確保當(dāng)前處在 master 分支上儿子,然后獲取 upstream 的修改,再并入我們本地的 master 分支绽诚。

$ git checkout master
$ git fetch upstream
$ git merge upstream/master

再把本地的更新 push 到 origin典徊,也就是我們的 GitHub 倉庫:

$ git push

同步工作完成!

持續(xù)集成

很多開源項(xiàng)目都會(huì)通過持續(xù)集成(Continuous Integration恩够,簡稱 CI)來確保代碼質(zhì)量卒落。對(duì)于我們貢獻(xiàn)者來說,這意味著每次提交 PR 和繼續(xù) push 代碼蜂桶,CI 都會(huì)對(duì)我們的提交進(jìn)行構(gòu)建并執(zhí)行倉庫維護(hù)者指定的檢查儡毕,例如代碼風(fēng)格檢查、單元測試等等扑媚。

如果你查看你新提交的 PR腰湾,你會(huì)發(fā)現(xiàn)右上角有個(gè)黃色的圓圈,這表示 CI 正在檢查你的提交疆股。

CI 正在檢查我們的 PR

當(dāng)右上角的黃色圓圈變成綠色的勾费坊,就表示你的代碼通過了 CI !

這個(gè) PR 通過了 CI

有時(shí)候會(huì)出現(xiàn)紅色的叉旬痹,表示未通過 CI 測試附井。

這個(gè) PR 未通過 CI

這時(shí)候我們就需要進(jìn)入 PR 頁面,翻到最下面两残,查看 Travis-CI (這個(gè)倉庫使用的是流行的 Travis CI)檢查的詳細(xì)信息永毅,找出錯(cuò)誤原因后進(jìn)行修改,然后 git push 提交我們的修改即可人弓,直到通過 CI沼死。

總結(jié)

可能步驟有點(diǎn)復(fù)雜,所以這里總結(jié)一下 Pull Request 的生命周期 :

  1. 確定要貢獻(xiàn)的項(xiàng)目崔赌,尋找值得解決的 Issue意蛀。

  2. 將原倉庫 Fork 到自己的帳號(hào)下,然后克隆到本地峰鄙。

$ git clone https://github.com/<YOUR_USERNAME>/<FORKED_REPO>.git
  1. 開啟新分支浸间,修改代碼并提交。
$ git checkout -b <NEW_BRANCH_NAME>
$ git commit -am "<COMMIT_MESSAGE>"
$ git push -u origin <NEW_BRANCH_NAME>
  1. 打開倉庫的 GitHub 頁面吟榴,點(diǎn)擊提示的 Compare & pull request 按鈕魁蒜,填寫 PR 信息(記得使用 GitHub 關(guān)鍵詞關(guān)閉對(duì)應(yīng)的 Issue)然后提交。

  2. 如果 CI 測試未通過,或者倉庫維護(hù)者要求修改(request changes)兜看,那么就在本地繼續(xù)修改代碼锥咸,然后 git push 再次提交,直到通過 CI 和倉庫維護(hù)者的評(píng)審细移。

  3. 倉庫維護(hù)者部署和并入你的分支搏予,貢獻(xiàn)完成。

親自實(shí)踐

這篇文章的 GitHub 倉庫在這里弧轧,你可以隨意地發(fā)起 Issue 或 Pull Request雪侥。如果你只是想要親自實(shí)踐一下上面所講的內(nèi)容,就請(qǐng)?jiān)?THOUGHTS.md 中隨意寫下你的想法并提交給我精绎,我會(huì)盡快合并你的分支速缨。當(dāng)然如果你對(duì)本文有改進(jìn)意見,那更歡迎你的 Pull Request代乃,讓這篇文章變得更好旬牲!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市搁吓,隨后出現(xiàn)的幾起案子原茅,更是在濱河造成了極大的恐慌,老刑警劉巖堕仔,帶你破解...
    沈念sama閱讀 217,657評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件擂橘,死亡現(xiàn)場離奇詭異,居然都是意外死亡摩骨,警方通過查閱死者的電腦和手機(jī)贝室,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仿吞,“玉大人,你說我怎么就攤上這事捡偏』礁裕” “怎么了?”我有些...
    開封第一講書人閱讀 164,057評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵银伟,是天一觀的道長你虹。 經(jīng)常有香客問我,道長彤避,這世上最難降的妖魔是什么傅物? 我笑而不...
    開封第一講書人閱讀 58,509評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮琉预,結(jié)果婚禮上董饰,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好卒暂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評(píng)論 6 392
  • 文/花漫 我一把揭開白布啄栓。 她就那樣靜靜地躺著,像睡著了一般也祠。 火紅的嫁衣襯著肌膚如雪昙楚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,443評(píng)論 1 302
  • 那天诈嘿,我揣著相機(jī)與錄音堪旧,去河邊找鬼。 笑死奖亚,一個(gè)胖子當(dāng)著我的面吹牛淳梦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播遂蛀,決...
    沈念sama閱讀 40,251評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼谭跨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了李滴?” 一聲冷哼從身側(cè)響起螃宙,我...
    開封第一講書人閱讀 39,129評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎所坯,沒想到半個(gè)月后谆扎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,561評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芹助,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評(píng)論 3 335
  • 正文 我和宋清朗相戀三年堂湖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片状土。...
    茶點(diǎn)故事閱讀 39,902評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡无蜂,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蒙谓,到底是詐尸還是另有隱情斥季,我是刑警寧澤,帶...
    沈念sama閱讀 35,621評(píng)論 5 345
  • 正文 年R本政府宣布累驮,位于F島的核電站酣倾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谤专。R本人自食惡果不足惜躁锡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望置侍。 院中可真熱鬧映之,春花似錦拦焚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至抬伺,卻和暖如春螟够,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背峡钓。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評(píng)論 1 269
  • 我被黑心中介騙來泰國打工妓笙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人能岩。 一個(gè)月前我還...
    沈念sama閱讀 48,025評(píng)論 2 370
  • 正文 我出身青樓寞宫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拉鹃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辈赋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,661評(píng)論 9 163
  • 明天是媽媽的生日。上周妹妹就已經(jīng)開始在微信里問我“老大膏燕,咱媽什么時(shí)候生日钥屈?”猛然想起,翻看手機(jī)后發(fā)現(xiàn)還有一個(gè)星期坝辫。...
    永無島教室閱讀 396評(píng)論 0 0
  • 生病的時(shí)候近忙,最怕媽媽離開 前幾天小家伙病了竭业。扁桃體發(fā)炎,我們沒有及時(shí)發(fā)現(xiàn)及舍。辛苦了他未辆。去醫(yī)院檢查的時(shí)候,小家伙的喉嚨...
    魚羊正史閱讀 631評(píng)論 0 1
  • 彩霞锯玛,似天空的拓荒者鼎姐,無悔地將自己展開。山更振,在夢里沉默,囈語是遠(yuǎn)在身體內(nèi)部的黑暗饭尝。樹肯腕,停止飛翔。云霧钥平,因夕陽的祈禱...
    每日愛圖閱讀 849評(píng)論 1 3
  • 在通往成功的路上 得承受一些人的不屑與輕視 還得承受一些人的不理解與不信任 OK实撒,這些都不重要 重要的是姊途,你的心夠...
    葉娜姐姐閱讀 199評(píng)論 0 1