章節 ▾ 第二版

6.2 GitHub - 參與專案

參與專案

現在我們的賬戶已經設定好了,讓我們來詳細瞭解一些可以幫助你參與到現有專案中的細節。

Forking Projects (複製專案)

如果你想參與到一個你沒有推送許可權的現有專案中,你可以“fork”該專案。當你“fork”一個專案時,GitHub 會為你建立一個完全屬於你的專案副本;它會存放在你的名稱空間下,你可以向其中推送。

注意

歷史上,“fork”這個詞在語境中帶有一定的負面含義,表示有人將一個開源專案導向了不同的方向,有時會建立一個競爭專案並分裂貢獻者。在 GitHub 中,“fork”僅僅是指在你自己的名稱空間下的同一個專案,允許你公開地對專案進行修改,從而以一種更開放的方式進行貢獻。

這樣,專案就無需擔心新增使用者作為協作者來給予他們推送許可權。人們可以 fork 一個專案,向其中推送,並透過建立一個稱為“Pull Request”(拉取請求)的東西將他們的更改貢獻回原始倉庫,我們將在下一節介紹它。這會開啟一個帶有程式碼審查的討論執行緒,然後專案所有者和貢獻者可以就更改進行溝通,直到所有者滿意為止,屆時所有者就可以將其合併。

要 fork 一個專案,請訪問專案頁面,然後點選頁面右上角的“Fork”按鈕。

The “Fork” button
圖 88. “Fork”按鈕

幾秒鐘後,你就會被帶到你的新專案頁面,裡面是程式碼的一個可寫副本。

The GitHub Flow (GitHub 工作流)

GitHub 是圍繞一個特定的協作工作流設計的,該工作流以 Pull Requests 為中心。這個工作流適用於你是在一個共享倉庫中與緊密協作的團隊合作,還是在一個全球分佈的公司或由眾多 fork 貢獻專案的陌生人網路中工作。它以 Git 分支 中介紹的 主題分支 工作流為中心。

大致工作流程如下:

  1. Fork 專案。

  2. master 分支建立一個主題分支。

  3. 進行一些提交來改進專案。

  4. 將此分支推送到你的 GitHub 專案。

  5. 在 GitHub 上開啟一個 Pull Request。

  6. 討論,並可選地繼續提交。

  7. 專案所有者合併或關閉 Pull Request。

  8. 將更新後的 master 同步回你的 fork。

這基本上就是 整合管理器工作流 中介紹的整合管理器工作流,但不同之處在於,團隊使用 GitHub 的基於 Web 的工具來溝通和審查更改,而不是使用電子郵件。

讓我們透過一個例子來演示如何使用這個工作流來向 GitHub 上託管的開源專案提出更改。

提示

你可以使用官方的 **GitHub CLI** 工具而不是 GitHub 網頁介面來完成大部分操作。該工具可在 Windows、macOS 和 Linux 系統上使用。請訪問 GitHub CLI 主頁 以獲取安裝說明和手冊。

建立 Pull Request

Tony 正在尋找可以在他的 Arduino 可程式設計微控制器上執行的程式碼,並在 GitHub 上找到了一個很棒的程式檔案,地址是 https://github.com/schacon/blink

The project we want to contribute to
圖 89. 我們想貢獻的專案

唯一的問題是閃爍速率太快了。我們認為在狀態變化之間等待 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
  1. 將專案 fork 克隆到本地。

  2. 建立一個描述性的主題分支。

  3. 對程式碼進行更改。

  4. 檢查更改是否正確。

  5. 將更改提交到主題分支。

  6. 將新的主題分支推送到你的 GitHub fork。

現在,如果我們回到 GitHub 上的 fork,可以看到 GitHub 注意到我們推送了一個新的主題分支,並提供了一個大大的綠色按鈕讓我們檢查更改並向原始專案開啟一個 Pull Request。

你也可以選擇透過訪問“Branches”頁面 https://github.com/<user>/<project>/branches 來定位你的分支並從那裡開啟一個新的 Pull Request。

Pull Request button
圖 90. Pull Request 按鈕

如果點選那個綠色按鈕,我們會看到一個螢幕,要求我們為 Pull Request 提供一個標題和描述。花費一些精力在這一點上幾乎總是值得的,因為一個好的描述可以幫助原始專案的作者瞭解你的意圖,你的提議的更改是否正確,以及接受這些更改是否會改進原始專案。

我們還看到了我們主題分支中“ahead”(超前)於 master 分支的提交列表(在本例中只有一個),以及如果該分支被專案作者合併,將引入的所有更改的統一 diff。

Pull Request creation page
圖 91. Pull Request 建立頁面

當我們點選此螢幕上的“Create pull request”按鈕時,你 fork 的專案的作者會收到一個通知,告知有人在建議更改,並且會連結到一個包含所有這些資訊的頁面。

注意

雖然 Pull Requests 常用於像這樣的公共專案,當貢獻者準備好完成更改時,它也經常在內部專案**開發週期早期**使用。由於你甚至可以在 Pull Request 開啟**之後**繼續推送到主題分支,所以通常會提前開啟它,並用它作為團隊在一個上下文中迭代工作的工具,而不是在流程的最後才打開。

迭代 Pull Request

此時,專案所有者可以檢視建議的更改並將其合併、拒絕或評論。假設他喜歡這個想法,但希望燈熄滅的時間比亮著的時間稍長一些。

分散式 Git 中介紹的工作流中,這種對話可能會透過電子郵件進行,而在 GitHub 上,則線上進行。專案所有者可以審查統一 diff,並透過點選任意行來留下評論。

Comment on a specific line of code in a Pull Request
圖 92. 對 Pull Request 中的特定程式碼行發表評論

一旦維護者發表了這條評論,提交 Pull Request 的人(實際上,任何關注倉庫的人)都會收到通知。稍後我們會詳細介紹如何自定義,但如果他開啟了郵件通知,Tony 會收到如下郵件:

Comments sent as email notifications
圖 93. 作為郵件通知傳送的評論

任何人都可以對 Pull Request 發表一般性評論。在 Pull Request 討論頁面 中,我們可以看到一個例子,專案作者既評論了程式碼行,又在討論區發表了一般性評論。可以看到,程式碼評論也被帶入了對話中。

Pull Request discussion page
圖 94. Pull Request 討論頁面

現在貢獻者可以看到他們需要做什麼才能使他們的更改被接受。幸運的是,這非常簡單。在電子郵件中,你可能需要重新打包你的系列並重新提交給郵件列表,而在 GitHub 上,你只需再次提交到主題分支並推送,就會自動更新 Pull Request。在 Pull Request final 中,你還可以看到舊的程式碼評論在更新的 Pull Request 中已被摺疊,因為它是在一個已經被更改過的行上發表的。

向現有的 Pull Request 新增提交不會觸發通知,所以一旦 Tony 推送了他的更正,他就會決定發表一條評論來通知專案作者他已完成請求的更改。

Pull Request final
圖 95. Pull Request final

值得注意的是,如果你點選此 Pull Request 上的“Files Changed”選項卡,你會看到“unified”diff —— 也就是說,如果將此主題分支合併到主分支,將引入的總聚合差異。以 git diff 的術語來說,它基本上會自動顯示 git diff master…​<branch> 對於這個 Pull Request 所基於的分支。有關這種 diff 的更多資訊,請參閱 確定引入的內容

你還會注意到,GitHub 會檢查 Pull Request 是否能幹淨地合併,並提供一個按鈕讓你在伺服器上執行合併。此按鈕僅在你擁有倉庫的寫入許可權且可以進行簡單合併時才會顯示。如果你點選它,GitHub 將執行一個“非快進式”合併,這意味著即使合併**可以**是快進式,它仍然會建立一個合併提交。

如果你願意,你也可以簡單地將分支拉下來並在本地合併。如果你將此分支合併到 master 分支並推送到 GitHub,Pull Request 將自動關閉。

這是大多數 GitHub 專案使用的基本工作流。建立主題分支,在上面開啟 Pull Requests,進行討論,可能在此分支上進行更多工作,最終請求被關閉或合併。

注意
不只是 Fork

需要注意的是,你也可以在同一個倉庫的兩個分支之間開啟 Pull Request。如果你和某人正在開發一個功能,並且你們倆都擁有該專案的寫入許可權,你可以將一個主題分支推送到倉庫,並就該分支向同一專案的 master 分支開啟一個 Pull Request,以啟動程式碼審查和討論過程。無需 fork。

高階 Pull Requests

現在我們已經介紹了在 GitHub 上參與專案貢獻的基礎知識,接下來讓我們介紹一些關於 Pull Requests 的有趣技巧和竅門,以便你更有效地使用它們。

Pull Requests 作為 Patch (補丁)

重要的是要理解,許多專案並不真正將 Pull Requests 視為應該乾淨地按順序應用的完美補丁佇列,就像大多數基於郵件列表的專案認為補丁系列貢獻一樣。大多數 GitHub 專案將 Pull Request 分支視為圍繞提議更改的迭代對話,最終透過合併應用一個統一的 diff。

這是一個重要的區別,因為通常在程式碼被認為是完美之前就提出了更改,這與基於郵件列表的補丁系列貢獻非常罕見。這使得與維護者能更早地展開對話,從而使達成正確的解決方案更像是一個社群的努力。當透過 Pull Request 提出程式碼,並且維護者或社群建議更改時,通常不會重新生成補丁系列,而是將差異作為新的提交推送到分支,在保留先前工作上下文的情況下推進對話。

例如,如果你回去重新看看 Pull Request final,你會注意到貢獻者沒有變基他的提交併傳送另一個 Pull Request。相反,他們添加了新的提交併將其推送到現有的分支。這樣,如果你將來回去檢視這個 Pull Request,你可以輕鬆找到所有關於為什麼做出決定的上下文。在該網站上按下“Merge”按鈕會故意建立一個引用 Pull Request 的合併提交,這樣就可以輕鬆地回去研究原始對話,如有必要。

跟進上游 (Upstream)

如果你的 Pull Request 過時或合併不乾淨,你需要修復它,以便維護者可以輕鬆地將其合併。GitHub 會為你測試,並在每個 Pull Request 的底部告訴你合併是否是簡單的(trivial)或不是。

Pull Request does not merge cleanly
圖 96. 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
  1. 將原始倉庫新增為名為 upstream 的遠端。

  2. 從該遠端抓取最新的工作。

  3. 將該倉庫的主分支合併到你的主題分支。

  4. 修復發生的衝突。

  5. 推回到同一個主題分支。

完成這些操作後,Pull Request 將會自動更新並重新檢查是否可以乾淨地合併。

Pull Request now merges cleanly
圖 97. Pull Request 現在可以乾淨合併了

Git 的一個優點是你可以持續地這樣做。如果你有一個長期執行的專案,你可以輕鬆地反覆地從目標分支進行合併,並且只需要處理自上次合併以來出現的衝突,這使得整個過程非常易於管理。

如果你確實希望變基分支以進行清理,你當然可以這樣做,但強烈建議不要強制推送已開啟 Pull Request 的分支。如果其他人已經拉取了它並在此基礎上進行了更多工作,你就會遇到 變基的危險 中概述的所有問題。相反,將變基後的分支推送到 GitHub 上的一個新分支,並開啟一個新的 Pull Request 來引用舊的那個,然後關閉原始的。

引用

你的下一個問題可能是“如何引用舊的 Pull Request?”。事實證明,在 GitHub 中幾乎任何可以寫文字的地方,都有許多方法可以引用其他內容。

讓我們從如何交叉引用另一個 Pull Request 或 Issue 開始。所有 Pull Requests 和 Issues 都分配有編號,並且在專案中是唯一的。例如,你不能同時擁有 Pull Request #3 和 Issue #3。如果你想從任何其他 Pull Request 或 Issue 引用,你只需在任何評論或描述中輸入 #<num>。如果你想引用的 Issue 或 Pull Request 位於其他地方,你可以更具體地寫 username#<num> 來引用倉庫的 fork 中的 Issue 或 Pull Request,或者 username/repo#<num> 來引用另一個倉庫中的內容。

讓我們看一個例子。假設我們變基了前一個示例中的分支,為它建立了一個新的 Pull Request,現在我們想從新的 Pull Request 中引用舊的 Pull Request。我們還想引用 fork 倉庫中的一個 Issue 和一個完全不同的專案中的一個 Issue。我們可以像 Pull Request 中的交叉引用 中那樣填寫描述。

Cross references in a Pull Request
圖 98. Pull Request 中的交叉引用

當我們提交這個 Pull Request 時,我們會看到所有這些內容都像 在 Pull Request 中渲染的交叉引用 一樣被渲染。

Cross references rendered in a Pull Request
圖 99. 在 Pull Request 中渲染的交叉引用

請注意,我們輸入的完整 GitHub URL 被縮短為僅包含必要的資訊。

現在,如果 Tony 回去關閉原始的 Pull Request,我們可以看到,透過在新 Pull Request 中提及它,GitHub 已經在 Pull Request 時間線中自動建立了一個回溯事件。這意味著任何訪問此 Pull Request 並看到它已被關閉的人都可以輕鬆地連結回取代它的那個。連結看起來像 關閉的 Pull Request 時間線中連結回新的 Pull Request

Link back to the new Pull Request in the closed Pull Request timeline
圖 100. 關閉的 Pull Request 時間線中連結回新的 Pull Request

除了 Issue 編號之外,你還可以透過 SHA-1 來引用特定的提交。你必須指定一個完整的 40 個字元的 SHA-1,但如果 GitHub 在評論中看到它,它將直接連結到該提交。同樣,你可以像引用 Issue 一樣引用 fork 或其他倉庫中的提交。

GitHub Flavored Markdown (GitHub 風味 Markdown)

連結到其他 Issue 僅僅是你在 GitHub 的幾乎任何文字框中可以做到的有趣事情的開始。在 Issue 和 Pull Request 的描述、評論、程式碼評論等等中,你可以使用所謂的“GitHub Flavored Markdown”。Markdown 就像寫純文字,但它會以豐富的格式渲染。

請參閱 GitHub Flavored Markdown 的書寫和渲染示例,瞭解註釋或文字如何編寫然後使用 Markdown 渲染。

An example of GitHub Flavored Markdown as written and as rendered
圖 101. GitHub Flavored Markdown 的書寫和渲染示例

Markdown 的 GitHub 風味在基本 Markdown 語法之外增加了更多功能。當建立有用的 Pull Request 或 Issue 評論或描述時,這些功能都非常有用。

任務列表

第一個真正有用的 GitHub 特有的 Markdown 功能,尤其適用於 Pull Requests,就是任務列表。任務列表是你想完成的事情的複選框列表。將它們放入 Issue 或 Pull Request 通常表示你想在考慮完成該專案之前需要完成的事情。

你可以像這樣建立一個任務列表:

- [X] Write the code
- [ ] Write all the tests
- [ ] Document the code

如果我們將它包含在我們的 Pull Request 或 Issue 的描述中,我們將看到它像 Markdown 評論中渲染的任務列表 一樣被渲染。

Task lists rendered in a Markdown comment
圖 102. Markdown 評論中渲染的任務列表

這通常用於 Pull Requests,以表明在 Pull Request 可以合併之前,你想在分支上完成的所有工作。最酷的部分是你可以簡單地點選複選框來更新評論——你不需要直接編輯 Markdown 來勾選任務。

更重要的是,GitHub 會查詢 Issues 和 Pull Requests 中的任務列表,並在列出它們的頁面上將它們顯示為元資料。例如,如果你有一個帶有任務的 Pull Request,並且檢視所有 Pull Requests 的概述頁面,你可以看到它完成了多少。這有助於人們將 Pull Requests 分解為子任務,並幫助其他人跟蹤分支的進度。你可以在 Pull Request 列表中的任務列表摘要 中看到一個例子。

Task list summary in the Pull Request list
圖 103. Pull Request 列表中的任務列表摘要

當你在早期開啟一個 Pull Request 並用它來跟蹤功能實現進度時,這些內容非常有幫助。

程式碼片段

你也可以在評論中新增程式碼片段。當你想要展示一些你**可能**會嘗試做但還沒有實際實現為分支提交的事情時,這一點尤其有用。它也常用於新增不起作用的程式碼示例,或者這個 Pull Request 可以實現的程式碼。

要新增程式碼片段,你需要用反引號將其“圍起來”。

```java
for(int i=0 ; i < 5 ; i++)
{
   System.out.println("i is : " + i);
}
```

如果你像我們在這裡用 'java' 一樣新增語言名稱,GitHub 還會嘗試對程式碼片段進行語法高亮。以上面的例子為例,它會渲染成 渲染的圍起來的程式碼示例

Rendered fenced code example
圖 104. 渲染的圍起來的程式碼示例

引用

如果你正在回覆一個長評論中的一小部分,你可以透過在行前加上 > 字元來選擇性地引用該評論。事實上,這非常普遍且有用,有一個快捷鍵。如果你在評論中高亮顯示你想直接回復的文字,然後按 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?

渲染後,評論將看起來像 渲染的引用示例

Rendered quoting example
圖 105. 渲染的引用示例

表情符號

最後,你也可以在評論中使用表情符號。這實際上在許多 GitHub Issue 和 Pull Request 的評論中被廣泛使用。GitHub 中甚至有一個表情符號助手。如果你正在輸入評論並且以 : 字元開頭,一個自動完成器會幫助你找到你想要的東西。

Emoji autocompleter in action
圖 106. 表情符號自動完成器生效中

表情符號的形式是 :<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:

渲染後,它看起來會像 大量的表情符號評論

Heavy emoji commenting
圖 107. 大量的表情符號評論

這並非極其有用,但它為一種難以傳達情感的媒介增添了樂趣和情感的元素。

注意

如今,有相當多的網路服務在使用表情符號字元。一個很好的備忘單,可以用來查詢表達你想要說的話的表情符號,可以在這裡找到:

圖片

這在技術上不是 GitHub Flavored Markdown,但它非常有用。除了在評論中新增 Markdown 圖片連結(這可能很難找到和嵌入 URL)之外,GitHub 還允許你將圖片拖放到文字區域來嵌入它們。

Drag and drop images to upload them and auto-embed them
圖 108. 拖放圖片以上傳並自動嵌入它們

如果你檢視 拖放圖片以上傳並自動嵌入它們,你會看到文字區域上方有一個小的“Parsed as Markdown”(解析為 Markdown)提示。點選它將為你提供一個 Markdown 在 GitHub 上可以做的所有事情的完整備忘單。

保持你的 GitHub 公共倉庫更新

一旦你 fork 了 GitHub 倉庫,你的倉庫(你的“fork”)就獨立於原始倉庫存在。特別地,當原始倉庫有新的提交時,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)
  1. 如果你在其他分支上,請返回 master

  2. https://github.com/progit/progit2.git 拉取更改並將其合併到 master

  3. 將你的 master 分支推送到 origin

這樣做有效,但每次都得寫出 fetch 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)
  1. 新增源倉庫併為其命名。在這裡,我選擇將其命名為 progit

  2. 獲取 progit 的分支的引用,特別是 master

  3. 設定你的 master 分支從 progit 遠端進行 fetch。

  4. 定義預設推送倉庫為 origin

完成這些後,工作流會變得更簡單:

$ git checkout master (1)
$ git pull (2)
$ git push (3)
  1. 如果你在其他分支上,請返回 master

  2. progit 拉取更改併合併到 master

  3. 將你的 master 分支推送到 origin

這種方法可能有用,但並非沒有缺點。Git 會默默地為你完成這項工作,但如果你在 master 上提交、從 progit 拉取、然後推送到 origin,它不會警告你——所有這些操作在此設定下都是有效的。所以你必須小心,永遠不要直接提交到 master,因為該分支實際上屬於上游倉庫。