章節 ▾ 第二版

10.5 Git 內部原理 - Refspec

Refspec

在本書中,我們一直使用從遠端分支到本地引用的簡單對映,但它們可以更為複雜。假設你一直跟著前幾節操作並建立了一個小的本地 Git 倉庫,現在想往其中新增一個遠端倉庫

$ git remote add origin https://github.com/schacon/simplegit-progit

執行上述命令會在你的倉庫的 .git/config 檔案中新增一個節,指定遠端倉庫的名稱(origin)、遠端倉庫的 URL 以及用於抓取的refspec

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/*:refs/remotes/origin/*

refspec 的格式是,首先是一個可選的 +,後面跟著 <src>:<dst>,其中 <src> 是遠端端引用的模式,<dst> 是這些引用在本地將被跟蹤的位置。+ 告訴 Git 即使它不是一個快進(fast-forward)也要更新引用。

預設情況下,當執行 git remote add origin 命令時,Git 會自動抓取伺服器上 refs/heads/ 下的所有引用,並將其寫入本地的 refs/remotes/origin/。因此,如果伺服器上有一個 master 分支,你可以透過以下任何一種方式在本地訪問該分支的日誌

$ git log origin/master
$ git log remotes/origin/master
$ git log refs/remotes/origin/master

它們都等價,因為 Git 會將它們每個都擴充套件為 refs/remotes/origin/master

如果你想讓 Git 每次只拉取 master 分支,而不是遠端伺服器上的所有其他分支,你可以將抓取行更改為僅引用該分支

fetch = +refs/heads/master:refs/remotes/origin/master

這只是該遠端倉庫的 git fetch 的預設 refspec。如果你想只進行一次性的抓取,也可以在命令列上指定特定的 refspec。要將遠端倉庫上的 master 分支拉取到本地的 origin/mymaster,你可以執行

$ git fetch origin master:refs/remotes/origin/mymaster

你也可以指定多個 refspec。在命令列上,你可以這樣拉取多個分支

$ git fetch origin master:refs/remotes/origin/mymaster \
	 topic:refs/remotes/origin/topic
From git@github.com:schacon/simplegit
 ! [rejected]        master     -> origin/mymaster  (non fast forward)
 * [new branch]      topic      -> origin/topic

在這種情況下,master 分支的拉取被拒絕了,因為它沒有被列為快進引用。你可以透過在 refspec 前面指定 + 來覆蓋此行為。

你也可以在配置檔案中為抓取指定多個 refspec。如果你想總是從 origin 遠端倉庫抓取 masterexperiment 分支,新增兩行

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/experiment:refs/remotes/origin/experiment

從 Git 2.6.0 開始,你可以在模式中使用部分萬用字元(globs)來匹配多個分支,因此這也可以工作

fetch = +refs/heads/qa*:refs/remotes/origin/qa*

更好的是,你可以使用名稱空間(或目錄)來實現相同的目的,並且結構更清晰。如果你有一個 QA 團隊推送一系列分支,並且你只想要獲取 master 分支和 QA 團隊的任何分支,而不需要其他分支,你可以使用這樣的配置段

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/master:refs/remotes/origin/master
	fetch = +refs/heads/qa/*:refs/remotes/origin/qa/*

如果你有一個複雜的工作流程,其中 QA 團隊推送分支,開發人員推送分支,以及整合團隊在遠端分支上進行推送和協作,你可以透過這種方式輕鬆地為它們設定名稱空間。

推送 Refspec

能夠這樣抓取帶名稱空間的引用固然很好,但 QA 團隊最初是如何將他們的分支放入 qa/ 名稱空間的呢?你可以透過使用 refspec 進行推送來實現這一點。

如果 QA 團隊想將他們的 master 分支推送到遠端伺服器上的 qa/master,他們可以執行

$ git push origin master:refs/heads/qa/master

如果他們想讓 Git 在每次執行 git push origin 時自動執行此操作,他們可以在其配置檔案中新增一個 push

[remote "origin"]
	url = https://github.com/schacon/simplegit-progit
	fetch = +refs/heads/*:refs/remotes/origin/*
	push = refs/heads/master:refs/heads/qa/master

同樣,這將導致 git push origin 預設將本地的 master 分支推送到遠端的 qa/master 分支。

注意

你不能使用 refspec 從一個倉庫抓取並推送到另一個倉庫。有關示例,請參閱 保持你的 GitHub 公共倉庫最新

刪除引用

你也可以透過執行類似下面的命令來使用 refspec 從遠端伺服器刪除引用

$ git push origin :topic

因為 refspec 的格式是 <src>:<dst>,所以省略 <src> 部分,這基本上表示將遠端倉庫上的 topic 分支設為無,從而刪除它。

或者你可以使用較新的語法(從 Git v1.7.0 起可用)

$ git push origin --delete topic
scroll-to-top