-
A1. 附錄 A:其他環境中的 Git
- A1.1 圖形介面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 總結
-
A2. 附錄 B:在您的應用程式中嵌入 Git
-
A3. 附錄 C:Git 命令
6.2 GitHub - 參與專案
參與專案
現在我們的帳戶已經設定完成,讓我們來瀏覽一些在協助您參與現有專案時可能有用的細節。
Fork 專案
如果您想要參與一個您沒有推送權限的現有專案,您可以「fork」該專案。當您「fork」一個專案時,GitHub 會建立該專案的副本,完全屬於您;它會存在於您的命名空間中,並且您可以推送至該副本。
注意
|
在歷史上,「fork」這個詞在語境中帶有負面含義,表示有人將開源專案導向不同的方向,有時會創建一個競爭專案並分裂貢獻者。在 GitHub 中,「fork」只是您自己命名空間中的相同專案,讓您可以公開對專案進行變更,作為一種更開放的貢獻方式。 |
這樣一來,專案就不必擔心將使用者新增為協作者來授予他們推送權限。人們可以 fork 專案,推送至該專案,並透過建立所謂的「Pull Request」將他們的變更貢獻回原始儲存庫,我們將在接下來的部分中介紹。「Pull Request」會開啟一個帶有程式碼審查的討論串,擁有者和貢獻者可以針對變更進行溝通,直到擁有者對其感到滿意,此時擁有者可以將其合併。
若要 fork 專案,請瀏覽專案頁面,並按一下頁面右上角的「Fork」按鈕。

幾秒鐘後,您將被帶到您的新專案頁面,其中包含您自己可寫入的程式碼副本。
GitHub 流程
GitHub 的設計圍繞著特定的協作流程,以 Pull Request 為中心。無論您是在單一共享儲存庫中與緊密合作的團隊協作,還是在全球分散的公司或由陌生人組成的網路透過數十個 fork 參與專案,此流程都能運作。它以主題分支工作流程為中心,詳情請參閱Git 分支。
其大致運作方式如下
-
Fork 專案。
-
從
master
建立一個主題分支。 -
進行一些提交來改進專案。
-
將此分支推送至您的 GitHub 專案。
-
在 GitHub 上開啟 Pull Request。
-
討論,並選擇性地繼續提交。
-
專案擁有者合併或關閉 Pull Request。
-
將更新後的
master
同步回您的 fork。
這基本上是整合管理員工作流程中涵蓋的工作流程,但團隊不是使用電子郵件來溝通和審查變更,而是使用 GitHub 的網頁工具。
讓我們透過一個範例來逐步了解如何使用此流程向託管在 GitHub 上的開源專案提出變更。
提示
|
您可以使用官方的 GitHub CLI 工具,而不是使用 GitHub 網頁介面來進行大部分操作。該工具可以在 Windows、macOS 和 Linux 系統上使用。請前往 GitHub CLI 首頁,以取得安裝說明和手冊。 |
建立 Pull Request
Tony 正在尋找可在 Arduino 可程式微控制器上執行的程式碼,並且在 GitHub 上的 https://github.com/schacon/blink 找到了一個很棒的程式檔案。

唯一的問題是閃爍速度太快。我們認為每次狀態變更之間等待 3 秒會比 1 秒好得多。所以讓我們改進程式碼,並將其作為建議的變更提交回專案。
首先,我們點擊先前提到過的「Fork」按鈕,以取得我們自己的專案副本。這裡我們的使用者名稱是「tonychacon」,所以我們這個專案的副本位於 https://github.com/tonychacon/blink
,我們可以在這裡編輯它。我們會將其複製到本地端,建立一個主題分支,進行程式碼變更,最後將變更推送回 GitHub。
$ git clone https://github.com/tonychacon/blink (1)
Cloning into 'blink'...
$ cd blink
$ git checkout -b slow-blink (2)
Switched to a new branch 'slow-blink'
$ sed -i '' 's/1000/3000/' blink.ino (macOS) (3)
# If you're on a Linux system, do this instead:
# $ sed -i 's/1000/3000/' blink.ino (3)
$ git diff --word-diff (4)
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
digitalWrite(led, HIGH); // turn the LED on (HIGH is the voltage level)
[-delay(1000);-]{+delay(3000);+} // wait for a second
digitalWrite(led, LOW); // turn the LED off by making the voltage LOW
[-delay(1000);-]{+delay(3000);+} // wait for a second
}
$ git commit -a -m 'Change delay to 3 seconds' (5)
[slow-blink 5ca509d] Change delay to 3 seconds
1 file changed, 2 insertions(+), 2 deletions(-)
$ git push origin slow-blink (6)
Username for 'https://github.com': tonychacon
Password for 'https://tonychacon@github.com':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
* [new branch] slow-blink -> slow-blink
-
將我們 fork 的專案複製到本地端。
-
建立一個具描述性的主題分支。
-
對程式碼進行變更。
-
檢查變更是否正確。
-
將變更提交到主題分支。
-
將新的主題分支推送回我們的 GitHub fork。
現在,如果我們回到 GitHub 上的 fork,我們會看到 GitHub 注意到我們推送了一個新的主題分支,並顯示一個大綠色按鈕,讓我們可以查看變更並向原始專案開啟一個 Pull Request。
或者,您可以前往 https://github.com/<user>/<project>/branches
的「Branches」頁面,找到您的分支並從那裡開啟新的 Pull Request。

如果我們點擊該綠色按鈕,會看到一個畫面,要求我們為 Pull Request 提供標題和描述。這幾乎總是值得花一些力氣的,因為良好的描述可以幫助原始專案的所有者判斷您嘗試做什麼、您提出的變更是否正確,以及接受變更是否會改進原始專案。
我們還會看到一個主題分支中的 commit 清單,這些 commit 「領先」於 master
分支(在這個案例中只有一個),以及一個合併差異,顯示如果此分支被專案所有者合併,將會進行的所有變更。

當您在這個畫面上按下「Create pull request」按鈕時,您 fork 的專案所有者將會收到通知,表示有人建議變更,並會連結到一個包含所有相關資訊的頁面。
注意
|
雖然 Pull Request 通常用於像這樣的公開專案,當貢獻者有完整的變更準備好提交時,它也經常在內部專案的開發週期的開始時使用。由於即使在開啟 Pull Request 之後,您仍然可以繼續推送至主題分支,所以通常會提早開啟,並作為團隊在環境中疊代工作的一種方式,而不是在流程的最後才開啟。 |
疊代 Pull Request
此時,專案所有者可以查看建議的變更,並合併、拒絕或評論它。假設他喜歡這個想法,但希望燈熄滅的時間比亮起的時間稍微長一點。
在 分散式 Git 中介紹的工作流程中,此對話可能會透過電子郵件進行,但在 GitHub 上,這會線上發生。專案所有者可以查看合併差異,並點擊任何一行來留下評論。

維護者發表評論後,開啟 Pull Request 的人(實際上,任何關注儲存庫的人)都會收到通知。我們稍後會介紹如何自訂此設定,但如果他開啟了電子郵件通知,Tony 會收到如下的電子郵件

任何人也可以在 Pull Request 上留下一般評論。在 Pull Request 討論頁面 中,我們可以看到專案所有者在程式碼行上評論,然後在討論區留下一般評論的範例。您可以看到程式碼評論也帶入了對話中。

現在,貢獻者可以看到他們需要做什麼才能讓他們的變更被接受。幸運的是,這非常簡單。當您透過電子郵件時,可能必須重新調整您的系列並將其重新提交至郵件清單,而在 GitHub 上,您只需再次提交至主題分支並推送,這將自動更新 Pull Request。在 Pull Request final 中,您也可以看到舊的程式碼註解在更新的 Pull Request 中已折疊,因為它是在自此之後已變更的行上建立的。
將 commit 新增至現有的 Pull Request 不會觸發通知,因此 Tony 在推送更正後,決定留下評論,通知專案所有者他已進行請求的變更。

值得注意的是,如果您點擊此 Pull Request 上的「Files Changed」索引標籤,您會得到「合併」差異,也就是如果將此主題分支合併到您的主要分支中,會引入的總體差異。以 git diff
的術語來說,它基本上會自動顯示您此 Pull Request 所基於的分支的 git diff master…<branch>
。有關此類型差異的更多資訊,請參閱判斷引入的內容。
您會注意到的另一件事是,GitHub 會檢查 Pull Request 是否可以順利合併,並提供一個按鈕讓您在伺服器上執行合併。只有當您擁有儲存庫的寫入權限,且可以進行簡單合併時,才會顯示此按鈕。如果您點擊它,GitHub 將執行「非快速轉發」合併,這表示即使合併可以是快速轉發,它仍然會建立合併 commit。
如果您願意,您可以直接將分支拉下來並在本地合併。如果您將此分支合併到 master
分支並將其推送至 GitHub,Pull Request 將會自動關閉。
這是大多數 GitHub 專案使用的基本工作流程。會建立主題分支,在其上開啟 Pull Request,進行討論,可能會對分支進行更多工作,最後要求會被關閉或合併。
注意
|
不只有 Fork
請務必注意,您也可以在同一儲存庫中的兩個分支之間開啟 Pull Request。如果您與某人共同開發一項功能,並且你們都擁有專案的寫入權限,您可以將主題分支推送至儲存庫,並對同一專案的 |
進階 Pull Request
既然我們已經介紹了在 GitHub 上貢獻專案的基本知識,接下來讓我們介紹一些關於 Pull Request 的有趣提示和技巧,以便您可以更有效地使用它們。
將 Pull Request 作為 Patch
請務必瞭解,許多專案並未將 Pull Request 視為應依序順利套用的完美 Patch 佇列,就像大多數基於郵件清單的專案認為的 Patch 系列貢獻。大多數 GitHub 專案將 Pull Request 分支視為圍繞擬議變更的疊代對話,最終會形成透過合併套用的統一差異。
這是一個重要的區別,因為通常在認為程式碼完美之前就會建議變更,這在基於郵件清單的 Patch 系列貢獻中要少得多。這使得可以更早與維護者進行對話,以便達成正確的解決方案更像是一種社群努力。當透過 Pull Request 提出程式碼,並且維護者或社群建議進行變更時,通常不會重新調整 Patch 系列,而是將差異作為新的 commit 推送至分支,在保留先前工作上下文的情況下推進對話。
例如,如果您回去再次查看Pull Request final,您會注意到貢獻者並未重新設置其 commit 的基礎,並發送另一個 Pull Request。相反地,他們新增了新的 commit 並將其推送至現有的分支。這樣一來,如果您將來回頭查看此 Pull Request,您可以輕鬆找到決策背後的所有上下文。按下網站上的「Merge」按鈕會特意建立一個參考 Pull Request 的合併 commit,以便在必要時可以輕鬆地回頭研究原始對話。
與上游保持同步
如果您的 Pull Request 過時或無法順利合併,您會想要修正它,以便維護者可以輕鬆合併它。GitHub 會為您測試此項目,並在每個 Pull Request 的底部告知您合併是否簡單。

如果您看到類似Pull Request 無法順利合併的內容,您會想要修正您的分支,使其變成綠色,並且維護者不必進行額外的工作。
您有兩種主要的選擇可以執行此操作。您可以將分支重新設置在目標分支的頂部(通常是您 fork 的儲存庫的 master
分支),或者您可以將目標分支合併到您的分支中。
GitHub 上的大多數開發人員會選擇後者,原因與我們在上一節中剛剛介紹的相同。重要的是歷程記錄和最終合併,因此重新設置基礎並不能為您帶來太多好處,除了稍微乾淨的歷程記錄之外,而且反而更加困難且容易出錯。
如果您想要合併目標分支以使您的 Pull Request 可以合併,您會將原始儲存庫新增為新的遠端,從中提取,將該儲存庫的主要分支合併到您的主題分支中,修正任何問題,最後將其推送回您開啟 Pull Request 的相同分支。
例如,假設在我們之前使用的「tonychacon」範例中,原始作者進行了一項變更,會在 Pull Request 中建立衝突。讓我們逐步執行這些步驟。
$ git remote add upstream https://github.com/schacon/blink (1)
$ git fetch upstream (2)
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
* [new branch] master -> upstream/master
$ git merge upstream/master (3)
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.
$ vim blink.ino (4)
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
into slower-blink
$ git push origin slow-blink (5)
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
ef4725c..3c8d735 slower-blink -> slow-blink
-
將原始儲存庫新增為名為
upstream
的遠端。 -
從該遠端提取最新的工作。
-
將該儲存庫的主要分支合併到您的主題分支中。
-
修正發生的衝突。
-
推送回相同的主題分支。
一旦您完成這些操作,Pull Request 將會自動更新並重新檢查,以確認是否能順利合併。

Git 的一大優點是您可以持續執行此操作。如果您有一個非常長期的專案,您可以輕鬆地一次又一次地從目標分支合併,並且只需處理自上次合併以來發生的衝突,這使得整個過程非常容易管理。
如果您絕對希望將分支變基 (rebase) 以進行清理,您當然可以這麼做,但強烈建議不要強制推送 (force push) 到已開啟 Pull Request 的分支上。如果其他人已經將其拉下來並在其上進行了更多工作,您會遇到變基的風險中概述的所有問題。相反,請將變基後的分支推送到 GitHub 上的一個新分支,並開啟一個全新的 Pull Request 來參考舊的,然後關閉原來的。
參考資料
您的下一個問題可能是「我該如何參考舊的 Pull Request?」。事實證明,您幾乎可以在 GitHub 上任何可以寫字的地方,用許多不同的方式來參考其他事物。
讓我們先從如何交叉參考另一個 Pull Request 或 Issue 開始。所有的 Pull Request 和 Issue 都會被分配一個數字,並且在專案中是獨一無二的。例如,您不能同時擁有 Pull Request #3 *和* Issue #3。如果您想從任何其他的 Pull Request 或 Issue 中參考任何 Pull Request 或 Issue,您只需在任何評論或描述中放入 #<num>
即可。如果 Issue 或 Pull Request 位於其他地方,您也可以更明確地指定;如果您要參考您所在儲存庫的 Fork 中的 Issue 或 Pull Request,請寫 username#<num>
,或者寫 username/repo#<num>
來參考另一個儲存庫中的內容。
讓我們來看一個例子。假設我們在先前的範例中將分支變基,為它建立了一個新的 Pull Request,現在我們想要從新的 Pull Request 中參考舊的 Pull Request。我們還想參考儲存庫 Fork 中的一個 Issue 和一個完全不同專案中的一個 Issue。我們可以像Pull Request 中的交叉參考一樣填寫描述。

當我們提交此 Pull Request 時,我們會看到所有內容都像Pull Request 中呈現的交叉參考一樣呈現出來。

請注意,我們在那裡放入的完整 GitHub URL 已縮短為僅顯示所需資訊。
現在,如果 Tony 回去並關閉原來的 Pull Request,我們可以看見,藉由在新的一個 Pull Request 中提及它,GitHub 已自動在 Pull Request 時間軸中建立了一個回溯事件。這表示任何造訪此 Pull Request 並發現它已關閉的人都可以輕鬆連結回取代它的 Pull Request。該連結看起來會像已關閉的 Pull Request 時間軸中返回新 Pull Request 的連結。

除了 Issue 編號之外,您也可以透過 SHA-1 參考特定的 Commit。您必須指定完整的 40 個字元的 SHA-1,但如果 GitHub 在評論中看到該 SHA-1,它將直接連結到該 Commit。同樣地,您可以使用與處理 Issue 相同的方式來參考 Fork 或其他儲存庫中的 Commit。
GitHub Flavored Markdown
連結到其他 Issue 只是您可以在 GitHub 上幾乎任何文字方塊中執行的有趣操作的開端。在 Issue 和 Pull Request 描述、評論、程式碼註解等地方,您可以使用所謂的「GitHub Flavored Markdown」。Markdown 就像是用純文字寫作,但會以豐富的方式呈現。
請參閱GitHub Flavored Markdown 的撰寫方式和呈現方式範例,以了解如何使用 Markdown 撰寫並呈現評論或文字。

GitHub 的 Markdown 版本增加了更多您可以在基本 Markdown 語法之外執行的操作。在建立有用的 Pull Request 或 Issue 評論或描述時,這些功能都非常有用。
任務清單
第一個非常有用的 GitHub 特定 Markdown 功能,特別適用於 Pull Request,就是任務清單。任務清單是一個勾選方塊列表,列出您想要完成的事情。將它們放入 Issue 或 Pull Request 中通常表示您希望在認為該項目完成之前完成的事情。
您可以像這樣建立一個任務清單
- [X] Write the code
- [ ] Write all the tests
- [ ] Document the code
如果我們將此加入 Pull Request 或 Issue 的描述中,我們會看到它像Markdown 評論中呈現的任務清單一樣呈現。

這通常用於 Pull Request 中,以指示您在 Pull Request 準備好合併之前希望在分支上完成的所有事項。真正酷的地方是,您可以簡單地按一下勾選方塊來更新評論 — 您不必直接編輯 Markdown 來勾選已完成的任務。
更重要的是,GitHub 會在您的 Issue 和 Pull Request 中尋找任務清單,並將它們顯示為列出它們的頁面上的 Metadata。例如,如果您有一個帶有任務的 Pull Request,並且查看所有 Pull Request 的概述頁面,您可以看到它的完成度。這有助於人們將 Pull Request 分解為子任務,並幫助其他人追蹤分支的進度。您可以在Pull Request 清單中的任務清單摘要中看到此範例。

當您提早開啟 Pull Request 並使用它來追蹤您在實作該功能時的進度時,這些功能非常有用。
程式碼片段
您也可以在評論中加入程式碼片段。如果您想展示在實際將其作為分支上的 Commit 實作之前可以嘗試的操作,這會特別有用。這也常用於加入程式碼範例,說明哪些地方無法運作,或是此 Pull Request 可以實作哪些功能。
若要加入程式碼片段,您必須用反引號將其「圍起來」。
```java
for(int i=0 ; i < 5 ; i++)
{
System.out.println("i is : " + i);
}
```
如果您像我們在那裡一樣加入了語言名稱(例如 'java'),GitHub 也會嘗試對程式碼片段進行語法高亮顯示。在上述範例的情況下,它最終會像呈現的圍欄式程式碼範例一樣呈現。

引用
如果您要回覆長評論中的一小部分,您可以透過在行前面加上 >
字元,有選擇性地從其他評論中引用。事實上,這種做法非常常見且非常有用,因此有一個鍵盤快速鍵可以使用。如果您在想要直接回覆的評論中反白文字並按下 r
鍵,它會在評論方塊中為您引用該文字。
引用看起來像這樣
> Whether 'tis Nobler in the mind to suffer
> The Slings and Arrows of outrageous Fortune,
How big are these slings and in particular, these arrows?
一旦呈現,該評論看起來會像呈現的引用範例。

表情符號
最後,您也可以在評論中使用表情符號。事實上,這在您在許多 GitHub Issue 和 Pull Request 上看到的評論中經常使用。GitHub 中甚至有一個表情符號輔助程式。如果您正在輸入評論並且從 :
字元開始,自動完成器將協助您找到您正在尋找的內容。

表情符號在評論中的任何地方都採用 :<name>:
的形式。例如,您可以寫像這樣的內容
I :eyes: that :bug: and I :cold_sweat:.
:trophy: for :microscope: it.
:+1: and :sparkles: on this :ship:, it's :fire::poop:!
:clap::tada::panda_face:
呈現時,它看起來會像大量使用表情符號的評論。

並非說這非常有用,但它確實為原本難以表達情感的媒介增加了一些樂趣和情感。
注意
|
事實上,現在有相當多的網路服務正在使用表情符號字元。您可以在以下網址找到一個很棒的作弊表,可以參考,以找到可以表達您想說的話的表情符號: |
圖片
這在技術上並非 GitHub Flavored Markdown,但它非常有用。除了在評論中加入 Markdown 圖片連結之外(很難找到並嵌入 URL),GitHub 還允許您將圖片拖放到文字區域中以嵌入它們。

如果您查看拖放圖片以上傳並自動嵌入它們,您可以在文字區域上方看到一個小的「已剖析為 Markdown」提示。按一下該提示會顯示您可以在 GitHub 上使用 Markdown 執行之所有操作的完整作弊表。
讓您的 GitHub 公開儲存庫保持最新
一旦您 Fork 了 GitHub 儲存庫,您的儲存庫(您的「Fork」)就會獨立於原始儲存庫而存在。特別是,當原始儲存庫有新的 Commit 時,GitHub 會透過類似這樣的訊息通知您
This branch is 5 commits behind progit:master.
但您的 GitHub 儲存庫永遠不會由 GitHub 自動更新;這必須由您自己執行。幸運的是,這很容易做到。
一種執行此操作的可能性不需要任何組態。例如,如果您從 https://github.com/progit/progit2.git
Fork,您可以像這樣讓您的 master
分支保持最新:
$ git checkout master (1)
$ git pull https://github.com/progit/progit2.git (2)
$ git push origin master (3)
-
如果您在另一個分支上,請返回
master
。 -
從
https://github.com/progit/progit2.git
提取變更,並將它們合併到master
中。 -
將您的
master
分支推送至origin
。
這樣可以正常運作,但是每次都必須拼寫出提取 URL 有點繁瑣。您可以使用一些組態來自動化此工作
$ git remote add progit https://github.com/progit/progit2.git (1)
$ git fetch progit (2)
$ git branch --set-upstream-to=progit/master master (3)
$ git config --local remote.pushDefault origin (4)
-
加入來源儲存庫並為其命名。在這裡,我選擇將其稱為
progit
。 -
取得 progit 分支(特別是
master
)的參考。 -
設定你的
master
分支從progit
遠端抓取。 -
定義預設的推送儲存庫為
origin
。
一旦完成這些設定,工作流程將會變得簡單許多。
$ git checkout master (1)
$ git pull (2)
$ git push (3)
-
如果您在另一個分支上,請返回
master
。 -
從
progit
抓取變更,並將變更合併到master
。 -
將您的
master
分支推送至origin
。
這種方法可能很有用,但並非沒有缺點。Git 會很樂意靜默地為您執行這些工作,但如果您在 master
上提交變更,從 progit
拉取變更,然後推送至 origin
,它不會警告您 — 在這種設定下,所有這些操作都是有效的。因此您必須小心,永遠不要直接提交到 master
,因為該分支實際上屬於上游儲存庫。