章節 ▾ 第二版

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 行更改為僅引用該分支:

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

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

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

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

$ 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 前指定 + 來覆蓋它。

你也可以在配置檔案中為 fetch 指定多個 refspecs。如果你想始終從 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 起,你可以在模式中使用部分 glob 來匹配多個分支,因此這很有效:

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 團隊推送分支,開發人員推送分支,整合團隊推送並協作遠端分支,你可以透過這種方式輕鬆地為它們新增名稱空間。

推送 Refspecs

透過這種方式獲取名稱空間引用很方便,但 QA 團隊如何才能將他們的分支推送到 *qa/* 名稱空間中呢?你透過使用 refspecs 來推送實現這一點。

如果 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