章節 ▾ 第二版

3.5 Git 分支 - 遠端分支

遠端分支

遠端引用是指你的遠端倉庫中的引用(指標),包括分支、標籤等等。你可以透過 git ls-remote <remote> 命令明確地獲取遠端引用的完整列表,或者使用 git remote show <remote> 來檢視遠端分支以及更多資訊。儘管如此,更常見的方式是利用遠端跟蹤分支。

遠端跟蹤分支是對遠端分支狀態的引用。它們是本地引用,你無法移動它們;當你進行任何網路通訊時,Git 會為你移動它們,以確保它們準確地反映遠端倉庫的狀態。你可以將它們視為書籤,用於提醒你在上次連線遠端倉庫時,遠端倉庫中的分支所在的位置。

遠端跟蹤分支的命名格式為 <remote>/<branch>。例如,如果你想檢視 origin 遠端上的 master 分支在你上次與它通訊時的狀態,你應該檢視 origin/master 分支。如果你正在與夥伴合作處理某個問題,他們推送了一個 iss53 分支,你可能有一個本地的 iss53 分支,但伺服器上的分支將由遠端跟蹤分支 origin/iss53 來表示。

這可能會有點令人困惑,所以讓我們看一個例子。假設你在網路上有一個 Git 伺服器,地址是 git.ourcompany.com。如果你從這裡克隆,Git 的 clone 命令會自動將它命名為 origin,下載所有資料,建立一個指向其 master 分支的本地指標,並將其命名為 origin/master。Git 還會建立一個與 originmaster 分支相同的本地 master 分支,這樣你就有了可以開始工作的內容。

注意
“origin” 並非特殊

就像 Git 中“master”分支名沒有特殊含義一樣,“origin”也沒有。雖然“master”是執行 git init 時預設的起始分支名稱,也是它被廣泛使用的唯一原因,“origin”是你執行 git clone 時預設的遠端名稱。如果你執行 git clone -o booyah,那麼你的預設遠端分支將是 booyah/master

Server and local repositories after cloning
圖 30. 克隆後伺服器和本地倉庫

如果你在本地的 master 分支上進行了一些工作,而與此同時,其他人推送到了 git.ourcompany.com 並更新了它的 master 分支,那麼你的提交歷史就會向前發展得不一樣。另外,只要你與 origin 伺服器沒有通訊,你的 origin/master 指標就不會移動。

Local and remote work can diverge
圖 31. 本地和遠端工作可能會分歧

要同步你與某個遠端倉庫的工作,你需要執行 git fetch <remote> 命令(在我們的例子中是 git fetch origin)。這個命令會查詢“origin”是哪個伺服器(在這個例子中是 git.ourcompany.com),從它那裡獲取你還沒有的資料,並更新你的本地資料庫,將你的 origin/master 指標移動到它新的、更更新的位置。

`git fetch` updates your remote-tracking branches
圖 32. git fetch 更新你的遠端跟蹤分支

為了演示擁有多個遠端伺服器以及這些遠端專案的遠端分支是什麼樣的,讓我們假設你還有一個內部 Git 伺服器,它只供一個衝刺團隊用於開發。這個伺服器的地址是 git.team1.ourcompany.com。你可以透過執行 git remote add 命令將其新增為當前專案中新的遠端引用,這在我們之前 Git 基礎 中已經講過了。將此遠端命名為 teamone,這將是該完整 URL 的簡寫名稱。

Adding another server as a remote
圖 33. 新增另一個伺服器作為遠端

現在,你可以執行 git fetch teamone 來獲取 teamone 遠端伺服器上所有你還沒有的內容。因為該伺服器目前擁有的資料是你的 origin 伺服器資料的一個子集,Git 不會獲取任何資料,但會設定一個名為 teamone/master 的遠端跟蹤分支,指向 teamonemaster 分支提交。

Remote-tracking branch for `teamone/master`
圖 34. teamone/master 的遠端跟蹤分支

推送

當你想要與他人共享一個分支時,你需要將其推送到你有寫入許可權的遠端倉庫。你的本地分支不會自動同步到你寫入的遠端倉庫——你必須顯式地推送你想要共享的分支。這樣,你就可以使用私有分支進行不希望共享的工作,只推送你想要協作的話題分支。

如果你有一個名為 serverfix 的分支,你想與他人一起工作,你可以以推送第一個分支的方式推送它。執行 git push <remote> <branch>

$ git push origin serverfix
Counting objects: 24, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (24/24), 1.91 KiB | 0 bytes/s, done.
Total 24 (delta 2), reused 0 (delta 0)
To https://github.com/schacon/simplegit
 * [new branch]      serverfix -> serverfix

這是一種快捷方式。Git 會自動將 serverfix 分支名展開為 refs/heads/serverfix:refs/heads/serverfix,意思是“將我的 serverfix 本地分支推送到遠端並更新遠端的 serverfix 分支”。我們將在 Git 內部原理 中詳細介紹 refs/heads/ 部分,但通常你可以省略它。你也可以執行 git push origin serverfix:serverfix,這會做同樣的事情——它表示“將我的 serverfix 推送到遠端並使其成為遠端的 serverfix”。你可以使用此格式將本地分支推送到命名不同的遠端分支。如果你不希望它在遠端被命名為 serverfix,你可以改為執行 git push origin serverfix:awesomebranch,將你的本地 serverfix 分支推送到遠端專案中的 awesomebranch 分支。

注意
不要每次都輸入密碼

如果你使用 HTTPS URL 進行推送,Git 伺服器會要求你輸入使用者名稱和密碼進行身份驗證。預設情況下,它會在終端提示你輸入這些資訊,以便伺服器可以判斷你是否有許可權推送。

如果你不想每次推送時都輸入密碼,可以設定一個“憑據快取”。最簡單的方法是將其儲存在記憶體中幾分鐘,你可以透過執行 git config --global credential.helper cache 來輕鬆設定。

有關各種可用憑據快取選項的更多資訊,請參閱 憑據儲存

下一次你的協作者從伺服器拉取時,他們將在遠端分支 origin/serverfix 下獲得指向伺服器 serverfix 版本位置的引用。

$ git fetch origin
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/schacon/simplegit
 * [new branch]      serverfix    -> origin/serverfix

需要注意的是,當你執行一個獲取(fetch)操作並下載了新的遠端跟蹤分支時,你並不會自動獲得可編輯的本地副本。換句話說,在這種情況下,你並沒有一個新的 serverfix 分支——你只有一個無法修改的 origin/serverfix 指標。

要將此工作合併到你當前的工作分支,你可以執行 git merge origin/serverfix。如果你想擁有自己的 serverfix 分支以便進行工作,你可以基於你的遠端跟蹤分支來建立它

$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

這會建立一個本地分支,你可以對其進行工作,它從 origin/serverfix 的位置開始。

跟蹤分支

從遠端跟蹤分支檢出一個本地分支會自動建立一個所謂的“跟蹤分支”(而它跟蹤的分支稱為“上游分支”)。跟蹤分支是與遠端分支有直接關係的本地分支。如果你在跟蹤分支上並鍵入 git pull,Git 會自動知道從哪個伺服器拉取以及合併哪個分支。

當你克隆一個倉庫時,通常會自動建立一個 master 分支來跟蹤 origin/master。但是,如果你願意,你也可以設定其他跟蹤分支——跟蹤其他遠端倉庫上的分支,或者不跟蹤 master 分支。最簡單的情況就是你剛才看到的例子,執行 git checkout -b <branch> <remote>/<branch>。這是一個足夠常見的操作,以至於 Git 提供了 --track 簡寫。

$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

事實上,這已經非常普遍了,甚至還有一個針對這個簡寫的簡寫。如果你的目標檢出(checkout)的分支名(a)不存在,並且(b)只在一個遠端倉庫中與一個分支名完全匹配,Git 會為你建立一個跟蹤分支。

$ git checkout serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'

要設定一個與遠端分支名稱不同的本地分支,你可以輕鬆地使用第一個版本,並指定不同的本地分支名稱。

$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'

現在,你的本地分支 sf 將會自動從 origin/serverfix 拉取。

如果你已經有一個本地分支,並希望將其設定為你剛剛拉下來的某個遠端分支,或者想更改你要跟蹤的上游分支,你可以隨時使用 git branch-u--set-upstream-to 選項來顯式設定。

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
注意
上游簡寫

當你設定了一個跟蹤分支後,你可以使用 @{upstream}@{u} 簡寫來引用它的上游分支。所以,如果你在 master 分支上,並且它跟蹤 origin/master,那麼如果你願意,你可以說 git merge @{u} 而不是 git merge origin/master

如果你想檢視你設定了哪些跟蹤分支,可以使用 git branch -vv 選項。這將列出你的本地分支以及更多資訊,包括每個分支正在跟蹤什麼,以及你的本地分支是超前、落後還是兩者兼有。

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] Add forgotten brackets
  master    1ae2a45 [origin/master] Deploy index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] This should do it
  testing   5ea463a Try something new

所以在這裡我們可以看到,我們的 iss53 分支正在跟蹤 origin/iss53,並且“超前”了兩次,這意味著我們本地有兩個提交尚未推送到伺服器。我們還可以看到,我們的 master 分支正在跟蹤 origin/master,並且是最新的。接下來,我們看到我們的 serverfix 分支正在跟蹤我們 teamone 伺服器上的 server-fix-good 分支,並且超前了三次,落後了一次,這意味著伺服器上有一個我們尚未合併的提交,以及三個我們尚未推送的本地提交。最後,我們可以看到我們的 testing 分支沒有跟蹤任何遠端分支。

需要注意的是,這些數字僅表示自上次你從每個伺服器獲取以來(的狀態)。此命令不會連線到伺服器,它告訴你的是本地快取的這些伺服器的資訊。如果你想獲得完全最新的超前和落後數字,你需要在執行此命令之前從所有遠端倉庫進行獲取。你可以這樣做:

$ git fetch --all; git branch -vv

拉取

雖然 git fetch 命令會獲取伺服器上所有你還沒有的更改,但它不會修改你的工作目錄。它只會獲取資料,讓你自己進行合併。但是,有一個名為 git pull 的命令,在大多數情況下,它實際上是 git fetch 後面緊接著一個 git merge。如果你設定了一個跟蹤分支(如上一節所示),無論是透過顯式設定還是透過 clonecheckout 命令為你建立的,git pull 都會查詢你當前分支正在跟蹤的伺服器和分支,從該伺服器獲取,然後嘗試合併該遠端分支。

刪除遠端分支

假設你已經完成了某個遠端分支的工作——比如你和你的協作者已經完成了某個功能,並將其合併到了你遠端倉庫的 master 分支(或者你穩定程式碼行的任何分支)。你可以使用 git push--delete 選項來刪除遠端分支。如果你想從伺服器上刪除你的 serverfix 分支,可以執行以下命令:

$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
 - [deleted]         serverfix

基本上,這只是從伺服器上移除了指標。Git 伺服器通常會暫時保留這些資料,直到垃圾回收執行,所以如果它被意外刪除,通常很容易恢復。