章节 ▾ 第二版

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/*

引用规格的格式是:首先是一个可选的 + 号,接着是 <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 的默认引用规格。如果你只想进行一次性抓取,也可以在命令行中指定特定的引用规格。要将远程的 master 分支拉取到本地的 origin/mymaster,可以运行:

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

你也可以指定多个引用规格。在命令行中,可以像这样拉取多个分支:

$ 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 分支的拉取被拒绝,因为它没有被列为快进引用。你可以通过在引用规格前加上 + 来覆盖此限制。

你也可以在配置文件中指定多个用于获取数据的引用规格。如果你想始终从 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 起,你可以在模式中使用部分通配符来匹配多个分支,因此这样写也有效:

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 团队推送分支、开发者推送分支以及集成团队在远程分支上协作,你可以通过这种方式轻松地进行命名空间管理。

推送引用规格 (Pushing Refspecs)

能够以这种方式获取命名空间引用是很棒,但 QA 团队是如何将他们的分支放入 qa/ 命名空间的呢?这需要通过使用推送的引用规格来实现。

如果 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 分支。

注意

你不能使用引用规格从一个仓库获取数据并将其推送到另一个仓库。有关此类示例,请参阅 保持 GitHub 公开仓库为最新状态

删除引用 (Deleting References)

你还可以使用引用规格通过运行如下命令来删除远程服务器上的引用:

$ git push origin :topic

因为引用规格是 <src>:<dst>,通过省略 <src> 部分,这本质上是说将远程的 topic 分支设为空,从而将其删除。

或者,你可以使用较新的语法(自 Git v1.7.0 起可用):

$ git push origin --delete topic