使用 GitHub 拉取请求的正确 git 配置是什么?

What is the correct git config for working with GitHub pull requests?

我知道 How can I check out a GitHub pull request?

虽然将 fetch = +refs/pull/*/head:refs/remotes/origin/pr/* 添加到 .git/config 确实允许提取和检出,但拉取操作失败:

[remote "origin"]
    url = https://github.com/the/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

抓取和签出工作正常:

$ git fetch origin

...都很好

$ git checkout -b "pr-123" origin/pr/123
Branch pr-123 set up to track remote branch pr/123 from origin.
Switched to a new branch 'pr-123'

...成功,获取代码!

但是拉取失败:

$ git pull
Your configuration specifies to merge with the ref 'refs/heads/pr/123' 
from the remote, but no such ref was fetched.

...失败。

我可以手动指定 ref:

$ git pull origin refs/pull/123/head

这行得通。但是我如何配置配置文件以便:

  1. 获取和结帐仍然有效,并且
  2. 后续拉取操作无需手动指定远程引用即可工作?

我发现如果我编辑配置文件并更改:

[branch "pr-123"]
    remote = origin
    merge = refs/heads/pr/123

至:

[branch "pr-123"]
    remote = origin
    merge = refs/pull/123/head  # <-- here is the change

... 然后 git pull 工作正常。如果不为每个拉取请求手动编辑配置文件,如何实现这一目标?

一个正确的方法是 hub:)

$ brew install hub
$ hub checkout https://github.com/github/hub/pull/123

...

$ hub pull
Already up-to-date.

它有额外的实用程序来处理 Github 拉取请求,例如

hub pull-request

您只获取了分支,而不是拉取请求。将此添加到您的配置中:

fetch = +refs/pull/*/head:refs/pulls/origin/pr/*

之后您可以检出指向 PR 远程引用的分支:

git checkout -b "pr-123" pulls/origin/pr/123

通常,如果您从远程获取了引用,则可以检出它,因此查看 git fetch 命令输出并找到 PR 的引用名称。这就是您应该在 checkout 命令中输入的内容。您应该会看到类似以下内容:

[new ref] refs/pull/123/head -> refs/pulls/origin/pr/123

请注意,您可以用 pulls 部分替换任何自定义前缀。您现在可以创建一个分支并将其指向 pulls/origin/pr/123,这相当于 refs/pulls/origin/pr/123(请参阅 git refspec doc)。

从获取规范中无法明确地找到远程引用 refs/remotes/origin/pr/123 跟踪 origin:refs/pull/123/head 因为 origin:refs/heads/pr/123 也是可能的。为了帮助它,您可以使用不同的远程名称,例如:

[remote "origin-pr"]
  url = <same as for origin>
  fetch = +refs/pull/*/head:refs/remotes/origin-pr/pr/*

然后 git 使用明确的分支名称(应该在 GUI 中可用)结帐将能够创建正确的跟踪参考:

$ git checkout -b pr/123 origin-pr/pr/123

[branch "pr/123"]
 remote = origin-pr
 merge = refs/pull/123/head

不过,看起来不可能使简单的 git checkout br/123 工作:

$ git checkout pr/123                         
error: pathspec 'pr/123' did not match any file(s) known to git.

我想我找到了一个解决方案,而且非常简单:fetch = +refs... 的行顺序很重要!

我改了:

[remote "origin"]
    url = https://github.com/the/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

至:

[remote "origin"]
    url = https://github.com/the/repo.git
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
    fetch = +refs/heads/*:refs/remotes/origin/*

(最后两行交换)

现在一切正常(fetchcheckoutpull)。

我仍在等待看到此配置的一些(意想不到的)问题,但到目前为止一切顺利...