章节 ▾ 第二版

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 即使它不是快速前进,也要更新引用。

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。如果你想执行一次性的获取,你也可以在命令行上指定特定的 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 之后,你可以在模式中使用部分通配符来匹配多个分支,所以这样也是可以的:

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