合并请求引用
如果你正在处理 许多 合并请求,不想添加一堆 remote 或者每次都要做一次拉取,这里有一个可以在 GitHub 上用的小技巧。
这是有点高级的技巧,但它相当有用,我们会在 引用规范 有更多的细节说明。
实际上 GitHub 在服务器上把合并请求分支视为一种 “假分支”。
默认情况下你克隆时不会得到它们,但它们还是隐式地存在,你可以很容易地访问到它们。
为了展示这个,我们要用到一个叫做 ls-remote 的低级命令(通常被叫做“plumbing”,
我们会在 底层命令与上层命令 读到更多相关内容)。
这个命令在日常 Git 操作中基本不会用到,但在显示服务器上有哪些引用(reference)时很管用。
如果在我们之前用过的 “blink” 版本库上使用这个命令,我们会得到一个版本库里所有的分支,标签和其它引用(reference)的列表。
$ git ls-remote https://github.com/schacon/blink
10d539600d86723087810ec636870a504f4fee4dHEAD
10d539600d86723087810ec636870a504f4fee4drefs/heads/master
6a83107c62950be9453aac297bb0193fd743cd6erefs/pull/1/head
afe83c2d1a70674c9505cc1d8b7d380d5e076ed3refs/pull/1/merge
3c8d735ee16296c242be7a9742ebfbc2665adec1refs/pull/2/head
15c9f4f80973a2758462ab2066b6ad9fe8dcf03drefs/pull/2/merge
a5a7751a33b7e86c5e9bb07b26001bb17d775d1arefs/pull/4/head
31a45fc257e8433c8d8804e3e848cf61c9d3166crefs/pull/4/merge
当然,如果你在你自己的版本库或其它你想检查的远程版本库中使用 git ls-remote origin ,它会显示相似的内容。
如果版本库在 GitHub 上并且有打开的合并请求,你会得到一些以 refs/pull/ 开头的引用。
它们实际上是分支,但因为它们不在 refs/heads/ 中,所以正常情况下你克隆时不会从服务器上得到它们
——抓取过程正常情况下会忽略它们。
每个合并请求有两个引用——其中以 /head 结尾的引用指向的提交记录与合并请求分支中的最后一个提交记录是同一个。
所以如果有人在我们的版本库中开启了一个合并请求,他们的分支叫做 bug-fix,
指向 a5a775 这个提交记录,那么在 我们的 版本库中我们没有 bug-fix 分支(因为那是在他们的 fork 中),
但我们 可以 有一个 pull//head 指向 a5a775。
这意味着我们可以很容易地拉取每一个合并请求分支而不用添加一堆远程仓库。
现在,你可以像直接抓取引用一样抓取那些分支或提交。
$ git fetch origin refs/pull/958/head
From https://github.com/libgit2/libgit2
* branch refs/pull/958/head -> FETCH_HEAD
这告诉 Git: “连接到 origin 这个 remote,下载名字为 refs/pull/958/head 的引用。”
Git 高高兴兴去执行,下载构建那个引用需要的所有内容,然后把指针指向 .git/FETCH_HEAD 下面你想要的提交记录。
然后你可以用 git merge FETCH_HEAD 把它合并到你想进行测试的分支,但那个合并的提交信息看起来有点怪。
然而,如果你需要审查 一大批 合并请求,这样操作会很麻烦。
还有一种方法可以抓取 所有的 合并请求,并且在你连接到远程仓库的时候保持更新。
用你最喜欢的编辑器打开 .git/config ,查找 origin 远程仓库。
看起来差不多像下面这样:
[remote "origin"]
url = https://github.com/libgit2/libgit2
fetch = +refs/heads/*:refs/remotes/origin/*
以 fetch = 开头的行是一个 “refspec.”
它是一种把 remote 的名称映射到你本地 .git 目录的方法。
这一条(就是上面的这一条)告诉 Git,“remote 上 refs/heads 下面的内容在我本地版本库中都放在 refs/remotes/origin 。”
你可以把这一段修改一下,添加另一个 refspec:
[remote "origin"]
url = https://github.com/libgit2/libgit2.git
fetch = +refs/heads/*:refs/remotes/origin/*
fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
最后一行告诉 Git: “所有看起来像 refs/pull/123/head 的引用应该在本地版本库像 refs/remotes/origin/pr/123 一样存储”
现在,如果你保存那个文件,执行 git fetch:
$ git fetch
# …
* [new ref] refs/pull/1/head -> origin/pr/1
* [new ref] refs/pull/2/head -> origin/pr/2
* [new ref] refs/pull/4/head -> origin/pr/4
# …
现在所有的合并请求在本地像分支一样展现,它们是只读的,当你执行抓取时它们也会更新。
这让在本地测试合并请求中的代码变得超级简单:
$ git checkout pr/2
Checking out files: 100% (3769/3769), done.
Branch pr/2 set up to track remote branch pr/2 from origin.
Switched to a new branch 'pr/2'
你的鹰眼系统会发现在 refspec 的 remote 部分的结尾有个 head 。
在 GitHub 那边也有一个 refs/pull/#/merge 引用,它代表的是如果你在网站上按了 “merge” 按钮对应的提交记录。
这甚至让你可以在按按钮之前就测试这个合并。