1. 程式人生 > >【Git專案管理】分支 - 遠端分支

【Git專案管理】分支 - 遠端分支

遠端分支

遠端引用是對遠端倉庫的引用(指標),包括分支、標籤等等。 你可以通過 git ls-remote (remote) 來顯式地獲得遠端引用的完整列表,或者通過 git remote show (remote) 獲得遠端分支的更多資訊。 然而,一個更常見的做法是利用遠端跟蹤分支。

遠端跟蹤分支是遠端分支狀態的引用。 它們是你不能移動的本地引用,當你做任何網路通訊操作時,它們會自動移動。 遠端跟蹤分支像是你上次連線到遠端倉庫時,那些分支所處狀態的書籤。

它們以 (remote)/(branch) 形式命名。 例如,如果你想要看你最後一次與遠端倉庫 origin

 通訊時 master分支的狀態,你可以檢視 origin/master 分支。 你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在伺服器上的分支會指向 origin/iss53 的提交。

這可能有一點兒難以理解,讓我們來看一個例子。 假設你的網路裡有一個在 git.ourcompany.com 的 Git 伺服器。 如果你從這裡克隆,Git 的 clone 命令會為你自動將其命名為 origin

,拉取它的所有資料,建立一個指向它的 master 分支的指標,並且在本地將其命名為 origin/master。 Git 也會給你一個與 origin 的 master 分支在指向同一個地方的本地 master 分支,這樣你就有工作的基礎。

Note “origin” 並無特殊含義

遠端倉庫名字 “origin” 與分支名字 “master” 一樣,在 Git 中並沒有任何特別的含義一樣。 同時 “master” 是當你執行 git init

 時預設的起始分支名字,原因僅僅是它的廣泛使用,“origin” 是當你執行 git clone 時預設的遠端倉庫名字。 如果你執行 git clone -o booyah,那麼你預設的遠端分支名字將會是 booyah/master

克隆之後的伺服器與本地倉庫。 Figure 30. 克隆之後的伺服器與本地倉庫

如果你在本地的 master 分支做了一些工作,然而在同一時間,其他人推送提交到 git.ourcompany.com 並更新了它的 master 分支,那麼你的提交歷史將向不同的方向前進。 也許,只要你不與 origin 伺服器連線,你的 origin/master 指標就不會移動。

本地與遠端的工作可以分叉。 Figure 31. 本地與遠端的工作可以分叉

如果要同步你的工作,執行 git fetch origin 命令。 這個命令查詢 “origin” 是哪一個伺服器(在本例中,它是 git.ourcompany.com),從中抓取本地沒有的資料,並且更新本地資料庫,移動 origin/master指標指向新的、更新後的位置。

`git fetch` 更新你的遠端倉庫引用。 Figure 32.  git fetch 更新你的遠端倉庫引用

為了演示有多個遠端倉庫與遠端分支的情況,我們假定你有另一個內部 Git 伺服器,僅用於你的 sprint 小組的開發工作。 這個伺服器位於 git.team1.ourcompany.com。 你可以執行 git remote add 命令新增一個新的遠端倉庫引用到當前的專案,這個命令我們會在 Git 基礎 中詳細說明。 將這個遠端倉庫命名為 teamone,將其作為整個 URL 的縮寫。

新增另一個遠端倉庫。 Figure 33. 新增另一個遠端倉庫

現在,可以執行 git fetch teamone 來抓取遠端倉庫 teamone 有而本地沒有的資料。 因為那臺伺服器上現有的資料是 origin 伺服器上的一個子集,所以 Git 並不會抓取資料而是會設定遠端跟蹤分支 teamone/master 指向 teamone 的 master 分支。

遠端跟蹤分支 `teamone/master`。 Figure 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 分支。

Note 如何避免每次輸入密碼

如果你正在使用 HTTPS URL 來推送,Git 伺服器會詢問使用者名稱與密碼。 預設情況下它會在終端中提示伺服器是否允許你進行推送。

如果不想在每一次推送時都輸入使用者名稱與密碼,你可以設定一個 “credential cache”。 最簡單的方式就是將其儲存在記憶體中幾分鐘,可以簡單地執行 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

要特別注意的一點是當抓取到新的遠端跟蹤分支時,本地不會自動生成一份可編輯的副本(拷貝)。 換一句話說,這種情況下,不會有一個新的 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 能自動地識別去哪個伺服器上抓取、合併到哪個分支。

當克隆一個倉庫時,它通常會自動地建立一個跟蹤 origin/master 的 master 分支。 然而,如果你願意的話可以設定其他的跟蹤分支 - 其他遠端倉庫上的跟蹤分支,或者不跟蹤 master 分支。 最簡單的就是之前看到的例子,執行 git checkout -b [branch] [remotename]/[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'

如果想要將本地分支與遠端分支設定為不同名字,你可以輕鬆地增加一個不同名字的本地分支的上一個命令:

$ 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 拉取。

設定已有的本地分支跟蹤一個剛剛拉取下來的遠端分支,或者想要修改正在跟蹤的上游分支,你可以在任意時間使用 -u 或 --set-upstream-to 選項執行 git branch 來顯式地設定。

$ git branch -u origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Note 上游快捷方式

當設定好跟蹤分支後,可以通過 @{upstream} 或 @{u} 快捷方式來引用它。 所以在 master分支時並且它正在跟蹤 origin/master 時,如果願意的話可以使用 git merge @{u} 來取代 git merge origin/master

如果想要檢視設定的所有跟蹤分支,可以使用 git branch 的 -vv 選項。 這會將所有的本地分支列出來並且包含更多的資訊,如每一個分支正在跟蹤哪個遠端分支與本地分支是否是領先、落後或是都有。

$ git branch -vv
  iss53     7e424c3 [origin/iss53: ahead 2] forgot the brackets
  master    1ae2a45 [origin/master] deploying index fix
* serverfix f8674d9 [teamone/server-fix-good: ahead 3, behind 1] this should do it
  testing   5ea463a trying something new

這裡可以看到 iss53 分支正在跟蹤 origin/iss53 並且 “ahead” 是 2,意味著本地有兩個提交還沒有推送到伺服器上。 也能看到 master 分支正在跟蹤 origin/master 分支並且是最新的。 接下來可以看到 serverfix 分支正在跟蹤 teamone 伺服器上的 server-fix-good 分支並且領先 3 落後 1,意味著伺服器上有一次提交還沒有合併入同時本地有三次提交還沒有推送。 最後看到 testing 分支並沒有跟蹤任何遠端分支。

需要重點注意的一點是這些數字的值來自於你從每個伺服器上最後一次抓取的資料。 這個命令並沒有連線伺服器,它只會告訴你關於本地快取的伺服器資料。 如果想要統計最新的領先與落後數字,需要在執行此命令前抓取所有的遠端倉庫。 可以像這樣做:$ git fetch --all; git branch -vv

拉取

當 git fetch 命令從伺服器上抓取本地沒有的資料時,它並不會修改工作目錄中的內容。 它只會獲取資料然後讓你自己合併。 然而,有一個命令叫作 git pull 在大多數情況下它的含義是一個 git fetch 緊接著一個 git merge 命令。 如果有一個像之前章節中演示的設定好的跟蹤分支,不管它是顯式地設定還是通過 clone 或 checkout 命令為你建立的,git pull 都會查詢當前分支所跟蹤的伺服器與分支,從伺服器上抓取資料然後嘗試合併入那個遠端分支。

由於 git pull 的魔法經常令人困惑所以通常單獨顯式地使用 fetch 與 merge 命令會更好一些。

刪除遠端分支

假設你已經通過遠端分支做完所有的工作了 - 也就是說你和你的協作者已經完成了一個特性並且將其合併到了遠端倉庫的 master 分支(或任何其他穩定程式碼分支)。 可以執行帶有 --delete 選項的 git push 命令來刪除一個遠端分支。 如果想要從伺服器上刪除 serverfix 分支,執行下面的命令:

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

基本上這個命令做的只是從伺服器上移除這個指標。 Git 伺服器通常會保留資料一段時間直到垃圾回收執行,所以如果不小心刪除掉了,通常是很容易恢復的。

遠端分支

遠端引用是對遠端倉庫的引用(指標),包括分支、標籤等等。 你可以通過 git ls-remote (remote) 來顯式地獲得遠端引用的完整列表,或者通過 git remote show (remote) 獲得遠端分支的更多資訊。 然而,一個更常見的做法是利用遠端跟蹤分支。

遠端跟蹤分支是遠端分支狀態的引用。 它們是你不能移動的本地引用,當你做任何網路通訊操作時,它們會自動移動。 遠端跟蹤分支像是你上次連線到遠端倉庫時,那些分支所處狀態的書籤。

它們以 (remote)/(branch) 形式命名。 例如,如果你想要看你最後一次與遠端倉庫 origin 通訊時 master分支的狀態,你可以檢視 origin/master 分支。 你與同事合作解決一個問題並且他們推送了一個 iss53 分支,你可能有自己的本地 iss53 分支;但是在伺服器上的分支會指向 origin/iss53 的提交。

這可能有一點兒難以理解,讓我們來看一個例子。 假設你的網路裡有一個在 git.ourcompany.com 的 Git 伺服器。 如果你從這裡克隆,Git 的 clone 命令會為你自動將其命名為 origin,拉取它的所有資料,建立一個指向它的 master 分支的指標,並且在本地將其命名為 origin/master。 Git 也會給你一個與 origin 的 master 分支在指向同一個地方的本地 master 分支,這樣你就有工作的基礎。

Note “origin” 並無特殊含義

遠端倉庫名字 “origin” 與分支名字 “master” 一樣,在 Git 中並沒有任何特別的含義一樣。 同時 “master” 是當你執行 git init 時預設的起始分支名字,原因僅僅是它的廣泛使用,“origin” 是當你執行 git clone 時預設的遠端倉庫名字。 如果你執行 git clone -o booyah,那麼你預設的遠端分支名字將會是 booyah/master

克隆之後的伺服器與本地倉庫。 Figure 30. 克隆之後的伺服器與本地倉庫

如果你在本地的 master 分支做了一些工作,然而在同一時間,其他人推送提交到 git.ourcompany.com 並更新了它的 master 分支,那麼你的提交歷史將向不同的方向前進。 也許,只要你不與 origin 伺服器連線,你的 origin/master 指標就不會移動。

本地與遠端的工作可以分叉。 Figure 31. 本地與遠端的工作可以分叉

如果要同步你的工作,執行 git fetch origin 命令。 這個命令查詢 “origin” 是哪一個伺服器(在本例中,它是 git.ourcompany.com),從中抓取本地沒有的資料,並且更新本地資料庫,移動 origin/master指標指向新的、更新後的位置。

`git fetch` 更新你的遠端倉庫引用。 Figure 32.  git fetch 更新你的遠端倉庫引用

為了演示有多個遠端倉庫與遠端分支的情況,我們假定你有另一個內部 Git 伺服器,僅用於你的 sprint 小組的開發工作。 這個伺服器位於 git.team1.ourcompany.com。 你可以執行 git remote add 命令新增一個新的遠端倉庫引用到當前的專案,這個命令我們會在 Git 基礎 中詳細說明。 將這個遠端倉庫命名為 teamone,將其作為整個 URL 的縮寫。

新增另一個遠端倉庫。 Figure 33. 新增另一個遠端倉庫

現在,可以執行 git fetch teamone 來抓取遠端倉庫 teamone 有而本地沒有的資料。 因為那臺伺服器上現有的資料是 origin 伺服器上的一個子集,所以 Git 並不會抓取資料而是會設定遠端跟蹤分支 teamone/master 指向 teamone 的 master 分支。

遠端跟蹤分支 `teamone/master`。 Figure 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 分支。

Note 如何避免每次輸入密碼

如果你正在使用 HTTPS URL 來推送,Git 伺服器會詢問使用者名稱與密碼。 預設情況下它會在終端中提示伺服器是否允許你進行推送。

如果不想在每一次推送時都輸入使用者名稱與密碼,你可以設定一個 “credential cache”。 最簡單的方式就是將其儲存在記憶體中幾分