章节 ▾ 第二版

10.5 Git 内部原理 - 引用规范

引用规范

在本书中,我们一直使用将远程分支简单映射到本地引用的方法,但它们可以更复杂。假设你跟着前几节的内容,创建了一个小的本地 Git 仓库,现在想往里面添加一个 远程 仓库

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

运行上述命令会给你的仓库的 .git/config 文件添加一个节,指定远程仓库的名称 (origin)、远程仓库的 URL 以及用于抓取的 引用规范

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

引用规范的格式是,首先,一个可选的 +,后面跟着 <src>:<dst>,其中 <src> 是远程端引用的模式,<dst> 是这些引用将在本地跟踪的位置。+ 告诉 Git 即使它不是快进,也要更新引用。

在由 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 的默认引用规范。如果你想进行一次性抓取,也可以在命令行上指定特定的引用规范。要将远程的 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 团队推送分支,开发人员推送分支,以及集成团队在远程分支上推送和协作,你可以通过这种方式轻松地对它们进行命名空间划分。

推送引用规范

能够以这种方式抓取命名空间引用很好,但 QA 团队最初是如何将他们的分支放入 qa/ 命名空间的呢?你可以通过使用引用规范进行推送来实现这一点。

如果 QA 团队想将他们的 master 分支推送到远程服务器上的 qa/master,他们可以运行

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

如果他们希望每次运行 git push origin 时 Git 都能自动完成此操作,他们可以向其配置文件添加一个 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 公共仓库最新

删除引用

你还可以通过运行类似以下命令的命令,使用引用规范从远程服务器删除引用

$ git push origin :topic

因为引用规范是 <src>:<dst>,所以省略 <src> 部分,这基本上表示将远程上的 topic 分支设为空,从而将其删除。

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

$ git push origin --delete topic