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

4

20

I'm aware of How can I check out a GitHub pull request?

While adding fetch = +refs/pull/*/head:refs/remotes/origin/pr/* to .git/config does allow fetch and checkout, pull actions fail:

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

Fetch and checkout work fine:

$ git fetch origin

... all good

$ 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'

... success, got the code!

But pull fails:

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

... failed.

I can specify the ref manually:

$ git pull origin refs/pull/123/head

and this works. But how can I configure the config file so that:

  1. fetch & checkout still work, and
  2. subsequent pull actions work without manually specifying the remote ref?

I have found that if I edit the config file and change:

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

to:

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

... then git pull works fine. How can this be achieved without manually editing the config file for every pull request?

Coincidence answered 17/11, 2016 at 18:49 Comment(4)
Are you asking how to edit the git config once for all pull requests? That link you posted has the answer, does that not work for you?Bipetalous
@yBot It does not. Namely, pull does not work. I have added the config file bit to the question, maybe there is something wrong there?Coincidence
I'm not sure how checking out origin/pr/123 worked for you, there should be no such ref for PR (maybe you have a remote branch with this name?). Try refs/remote/origin/pr/123. When you do fetch, this is what you should see getting fetched.Bipetalous
@yBot Frankly I don't know why (or why it shouldn't) but it does work. Also, adding refs/remote/ makes the checkout command fail. Fetch results look like this: * [new ref] refs/pull/123/head -> origin/pr/123 ... I'm tempted to start up a virtual machine and make a screencast :)Coincidence
C
4

I think I found a solution, and it's unbelievably simple: Order of the lines with fetch = +refs... matters!

I changed:

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

to:

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

(last two lines swapped)

Now everything works (fetch, checkout, pull).

I'm still waiting to see some (un)expected problems with this configuration, but so far so good...

Coincidence answered 27/11, 2016 at 11:35 Comment(2)
If anyone encounters a problem with this solution, please commentCoincidence
I was having the same problem -- and even today with Git 2.33.1 this solution still works. I am astounded that this order matters, but it very much does. Without this, git checkout pr/1 creates a bad merge entry in config: merge = refs/heads/pull/1. But with this fix, somehow the same command, git checkout pr/1 creates merge = refs/pull/1/head With the correct branch.pr/1.merge config entry -- everything works.Jahncke
B
9

You've only fetched branches, not pull requests. Add this to your config:

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

After that you can checkout a branch that points to a PR remote ref:

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

Generally, you can check out a ref if you've fetched it from the remote, so look through the git fetch command output and find the PR's ref name. That's what you should put in the checkout command. You should see something like:

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

Note that you can substitute the pulls part for any custom prefix. You can now create a branch and point it to pulls/origin/pr/123, which is equivalent to refs/pulls/origin/pr/123 (see git refspec doc).

Bipetalous answered 20/11, 2016 at 4:25 Comment(3)
My bad, you should omit the prefix refs, it's implied. Please see the updated answer.Bipetalous
Despite all the upvotes, this answer does not solve my problem. It simply does not work, actually.Coincidence
I'm very interested to know why it doesn't work for you. It works fine for me. If someone else can confirm that would be great too.Bipetalous
B
4

From the fetch specs is not possible to find unambiguously find that remote reference refs/remotes/origin/pr/123 tracks origin:refs/pull/123/head because origin:refs/heads/pr/123 is also possible. To help it, you could use different remote name for example:

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

Then git checkout with explicit branch name (which should be available in GUIs) would be able to create correct tracking reference:

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

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

Though, looks like it is not possible to make simple git checkout br/123 work:

$ git checkout pr/123                         
error: pathspec 'pr/123' did not match any file(s) known to git.
Barnardo answered 20/11, 2016 at 7:26 Comment(1)
This answer is a solution. We can configure two remotes: origin for regular branches, and origin-pr for PRs. It seems to work just fine, as long as the correct remote is chosen.Coincidence
C
4

I think I found a solution, and it's unbelievably simple: Order of the lines with fetch = +refs... matters!

I changed:

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

to:

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

(last two lines swapped)

Now everything works (fetch, checkout, pull).

I'm still waiting to see some (un)expected problems with this configuration, but so far so good...

Coincidence answered 27/11, 2016 at 11:35 Comment(2)
If anyone encounters a problem with this solution, please commentCoincidence
I was having the same problem -- and even today with Git 2.33.1 this solution still works. I am astounded that this order matters, but it very much does. Without this, git checkout pr/1 creates a bad merge entry in config: merge = refs/heads/pull/1. But with this fix, somehow the same command, git checkout pr/1 creates merge = refs/pull/1/head With the correct branch.pr/1.merge config entry -- everything works.Jahncke
R
1

One correct way is with hub! :)

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

...

$ hub pull
Already up-to-date.

It has extra utilities for working with Github pull requests, such as

hub pull-request
Religiose answered 20/11, 2016 at 4:18 Comment(5)
How does this help the author at all? The question is about the correct git config.Bipetalous
Does not help, because in the end this git config is used by a GUI (SourceTree). Thanks for the info, though.Coincidence
There are custom actions in SourceTree which can run arbitrary commandsBarnardo
To all the downvoters: really?! Yeah, it's not a direct answer to my exact question, but it is quite related, isn't it? It could have been useful in a bit different circumstances. And it may yet be useful to a googler in the future.Coincidence
Andy Ray: here have my upvote! I think it was a useful answer! Not exactly what OP wanted but might be useful for someone else.Hexagon

© 2022 - 2024 — McMap. All rights reserved.