遠(yuǎn)程分支(remote branch)是對(duì)遠(yuǎn)程倉(cāng)庫(kù)中的分支的索引。它們是一些無(wú)法移動(dòng)的本地分支;只有在 Git 進(jìn)行網(wǎng)絡(luò)交互時(shí)才會(huì)更新。遠(yuǎn)程分支就像是書(shū)簽,提醒著你上次連接遠(yuǎn)程倉(cāng)庫(kù)時(shí)上面各分支的位置。
我們用 (遠(yuǎn)程倉(cāng)庫(kù)名)/(分支名) 這樣的形式表示遠(yuǎn)程分支。比如我們想看看上次同 origin 倉(cāng)庫(kù)通訊時(shí) master 分支的樣子,就應(yīng)該查看 origin/master 分支。如果你和同伴一起修復(fù)某個(gè)問(wèn)題,但他們先推送了一個(gè) iss53 分支到遠(yuǎn)程倉(cāng)庫(kù),雖然你可能也有一個(gè)本地的 iss53 分支,但指向服務(wù)器上最新更新的卻應(yīng)該是 origin/iss53 分支。
可能有點(diǎn)亂,我們不妨舉例說(shuō)明。假設(shè)你們團(tuán)隊(duì)有個(gè)地址為 git.ourcompany.com 的 Git 服務(wù)器。如果你從這里克隆,Git 會(huì)自動(dòng)為你將此遠(yuǎn)程倉(cāng)庫(kù)命名為 origin,并下載其中所有的數(shù)據(jù),建立一個(gè)指向它的 master 分支的指針,在本地命名為 origin/master,但你無(wú)法在本地更改其數(shù)據(jù)。接著,Git 建立一個(gè)屬于你自己的本地 master 分支,始于 origin 上 master 分支相同的位置,你可以就此開(kāi)始工作(見(jiàn)圖 3-22):
圖 3-22. 一次 Git 克隆會(huì)建立你自己的本地分支 master 和遠(yuǎn)程分支 origin/master,并且將它們都指向 origin 上的 master 分支。
如果你在本地 master 分支做了些改動(dòng),與此同時(shí),其他人向 git.ourcompany.com 推送了他們的更新,那么服務(wù)器上的 master 分支就會(huì)向前推進(jìn),而與此同時(shí),你在本地的提交歷史正朝向不同方向發(fā)展。不過(guò)只要你不和服務(wù)器通訊,你的 origin/master 指針仍然保持原位不會(huì)移動(dòng)(見(jiàn)圖 3-23)。
圖 3-23. 在本地工作的同時(shí)有人向遠(yuǎn)程倉(cāng)庫(kù)推送內(nèi)容會(huì)讓提交歷史開(kāi)始分流。
可以運(yùn)行 git fetch origin
來(lái)同步遠(yuǎn)程服務(wù)器上的數(shù)據(jù)到本地。該命令首先找到 origin 是哪個(gè)服務(wù)器(本例為 git.ourcompany.com),從上面獲取你尚未擁有的數(shù)據(jù),更新你本地的數(shù)據(jù)庫(kù),然后把 origin/master 的指針移到它最新的位置上(見(jiàn)圖 3-24)。
圖 3-24. git fetch 命令會(huì)更新 remote 索引。
為了演示擁有多個(gè)遠(yuǎn)程分支(在不同的遠(yuǎn)程服務(wù)器上)的項(xiàng)目是如何工作的,我們假設(shè)你還有另一個(gè)僅供你的敏捷開(kāi)發(fā)小組使用的內(nèi)部服務(wù)器 git.team1.ourcompany.com??梢杂玫诙轮刑岬降?nbsp;git remote add
命令把它加為當(dāng)前項(xiàng)目的遠(yuǎn)程分支之一。我們把它命名為 teamone,以便代替完整的 Git URL 以方便使用(見(jiàn)圖 3-25)。
圖 3-25. 把另一個(gè)服務(wù)器加為遠(yuǎn)程倉(cāng)庫(kù)
現(xiàn)在你可以用 git fetch teamone
來(lái)獲取小組服務(wù)器上你還沒(méi)有的數(shù)據(jù)了。由于當(dāng)前該服務(wù)器上的內(nèi)容是你 origin 服務(wù)器上的子集,Git 不會(huì)下載任何數(shù)據(jù),而只是簡(jiǎn)單地創(chuàng)建一個(gè)名為 teamone/master 的遠(yuǎn)程分支,指向 teamone 服務(wù)器上 master 分支所在的提交對(duì)象 31b8e(見(jiàn)圖 3-26)。
圖 3-26. 你在本地有了一個(gè)指向 teamone 服務(wù)器上 master 分支的索引。
要想和其他人分享某個(gè)本地分支,你需要把它推送到一個(gè)你擁有寫(xiě)權(quán)限的遠(yuǎn)程倉(cāng)庫(kù)。你創(chuàng)建的本地分支不會(huì)因?yàn)槟愕膶?xiě)入操作而被自動(dòng)同步到你引入的遠(yuǎn)程服務(wù)器上,你需要明確地執(zhí)行推送分支的操作。換句話說(shuō),對(duì)于無(wú)意分享的分支,你盡管保留為私人分支好了,而只推送那些協(xié)同工作要用到的特性分支。
如果你有個(gè)叫 serverfix 的分支需要和他人一起開(kāi)發(fā),可以運(yùn)行 git push (遠(yuǎn)程倉(cāng)庫(kù)名) (分支名)
:
$ git push origin serverfix
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
* [new branch] serverfix -> serverfix
這里其實(shí)走了一點(diǎn)捷徑。Git 自動(dòng)把 serverfix 分支名擴(kuò)展為 refs/heads/serverfix:refs/heads/serverfix
,意為“取出我在本地的 serverfix 分支,推送到遠(yuǎn)程倉(cāng)庫(kù)的 serverfix 分支中去”。我們將在第九章進(jìn)一步介紹 refs/heads/
部分的細(xì)節(jié),不過(guò)一般使用的時(shí)候都可以省略它。也可以運(yùn)行 git push origin serverfix:serverfix
來(lái)實(shí)現(xiàn)相同的效果,它的意思是“上傳我本地的 serverfix 分支到遠(yuǎn)程倉(cāng)庫(kù)中去,仍舊稱它為 serverfix 分支”。通過(guò)此語(yǔ)法,你可以把本地分支推送到某個(gè)命名不同的遠(yuǎn)程分支:若想把遠(yuǎn)程分支叫作 awesomebranch,可以用git push origin serverfix:awesomebranch
來(lái)推送數(shù)據(jù)。
接下來(lái),當(dāng)你的協(xié)作者再次從服務(wù)器上獲取數(shù)據(jù)時(shí),他們將得到一個(gè)新的遠(yuǎn)程分支 origin/serverfix,并指向服務(wù)器上 serverfix 所指向的版本:
$ git fetch origin
remote: Counting objects: 20, done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 15 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (15/15), done.
From git@github.com:schacon/simplegit
* [new branch] serverfix -> origin/serverfix
值得注意的是,在 fetch 操作下載好新的遠(yuǎn)程分支之后,你仍然無(wú)法在本地編輯該遠(yuǎn)程倉(cāng)庫(kù)中的分支。換句話說(shuō),在本例中,你不會(huì)有一個(gè)新的 serverfix 分支,有的只是一個(gè)你無(wú)法移動(dòng)的 origin/serverfix 指針。
如果要把該遠(yuǎn)程分支的內(nèi)容合并到當(dāng)前分支,可以運(yùn)行 git merge origin/serverfix
。如果想要一份自己的 serverfix 來(lái)開(kāi)發(fā),可以在遠(yuǎn)程分支的基礎(chǔ)上分化出一個(gè)新的分支來(lái):
$ git checkout -b serverfix origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
這會(huì)切換到新建的 serverfix 本地分支,其內(nèi)容同遠(yuǎn)程分支 origin/serverfix 一致,這樣你就可以在里面繼續(xù)開(kāi)發(fā)了。
從遠(yuǎn)程分支 checkout 出來(lái)的本地分支,稱為 跟蹤分支 (tracking branch)。跟蹤分支是一種和某個(gè)遠(yuǎn)程分支有直接聯(lián)系的本地分支。在跟蹤分支里輸入 git push
,Git 會(huì)自行推斷應(yīng)該向哪個(gè)服務(wù)器的哪個(gè)分支推送數(shù)據(jù)。同樣,在這些分支里運(yùn)行 git pull
會(huì)獲取所有遠(yuǎn)程索引,并把它們的數(shù)據(jù)都合并到本地分支中來(lái)。
在克隆倉(cāng)庫(kù)時(shí),Git 通常會(huì)自動(dòng)創(chuàng)建一個(gè)名為 master 的分支來(lái)跟蹤 origin/master。這正是 git push
和 git pull
一開(kāi)始就能正常工作的原因。當(dāng)然,你可以隨心所欲地設(shè)定為其它跟蹤分支,比如 origin 上除了 master 之外的其它分支。剛才我們已經(jīng)看到了這樣的一個(gè)例子:git checkout -b [分支名] [遠(yuǎn)程名]/[分支名]
。如果你有 1.6.2 以上版本的 Git,還可以用 --track
選項(xiàng)簡(jiǎn)化:
$ git checkout --track origin/serverfix
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
要為本地分支設(shè)定不同于遠(yuǎn)程分支的名字,只需在第一個(gè)版本的命令里換個(gè)名字:
$ git checkout -b sf origin/serverfix
Branch sf set up to track remote branch serverfix from origin.
Switched to a new branch 'sf'
現(xiàn)在你的本地分支 sf 會(huì)自動(dòng)將推送和抓取數(shù)據(jù)的位置定位到 origin/serverfix 了。
假設(shè)你已經(jīng)通過(guò)遠(yuǎn)程分支做完所有的工作了——也就是說(shuō)你和你的協(xié)作者已經(jīng)完成了一個(gè)特性, 并且將其合并到了遠(yuǎn)程倉(cāng)庫(kù)的 master 分支(或任何其他穩(wěn)定代碼分支)。 可以運(yùn)行帶有 --delete 選項(xiàng)的 git push 命令來(lái)刪除一個(gè)遠(yuǎn)程分支。 如果想要從服務(wù)器上刪除 serverfix 分支,運(yùn)行下面的命令:
$ git push origin --delete serverfix
To https://github.com/schacon/simplegit
- [deleted] serverfix
基本上這個(gè)命令做的只是從服務(wù)器上移除這個(gè)指針。 Git 服務(wù)器通常會(huì)保留數(shù)據(jù)一段時(shí)間直到垃圾回收運(yùn)行,所以如果不小心刪除掉了,通常是很容易恢復(fù)的。
也可以使用下面這種非常無(wú)厘頭的語(yǔ)法來(lái)刪除它:git push [遠(yuǎn)程名] :[分支名]
。如果想在服務(wù)器上刪除 serverfix 分支,運(yùn)行下面的命令:
$ git push origin :serverfix
To git@github.com:schacon/simplegit.git
- [deleted] serverfix
咚!服務(wù)器上的分支沒(méi)了。你最好特別留心這一頁(yè),因?yàn)槟阋欢〞?huì)用到那個(gè)命令,而且你很可能會(huì)忘掉它的語(yǔ)法。有種方便記憶這條命令的方法:記住我們不久前見(jiàn)過(guò)的 git push [遠(yuǎn)程名] [本地分支]:[遠(yuǎn)程分支]
語(yǔ)法,如果省略 [本地分支],那就等于是在說(shuō)“在這里提取空白然后把它變成[遠(yuǎn)程分支]”。
更多建議: