Create a gist now

Instantly share code, notes, and snippets.

Checkout github pull requests locally

Locate the section for your github remote in the .git/config file. It looks like this:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url =

Now add the line fetch = +refs/pull/*/head:refs/remotes/origin/pr/* to this section. Obviously, change the github url to match your project's URL. It ends up looking like this:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url =
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Now fetch all the pull requests:

$ git fetch origin
 * [new ref]         refs/pull/1000/head -> origin/pr/1000
 * [new ref]         refs/pull/1002/head -> origin/pr/1002
 * [new ref]         refs/pull/1004/head -> origin/pr/1004
 * [new ref]         refs/pull/1009/head -> origin/pr/1009

To check out a particular pull request:

$ git checkout pr/999
Branch pr/999 set up to track remote branch pr/999 from origin.
Switched to a new branch 'pr/999'



Hey cool. Didn't know you could do that! :) Thanks.




So much love \o/










Nice! I dropped this in my rc file to make this process easy:
function pullify() {

git config --add remote.origin.fetch '+refs/pull//head:refs/remotes/origin/pr/'




Thanks. I just realized that with this trick you can enable it for all your repos at once :-)

git config --global --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*"


Just for fetching only one pull request. Handy, if you're hacking on something.

  git fetch origin pull/7324/head:pr-7324

origin points to the remote server.
pull/7324/head is the remote pull request.
pr-7324 is the local pull-request branch.


@piscisaureus The global config trick has an unfortunate side-effect. See Might be worth the tradeoff, but it's worth being aware of.


Your refspec is wrong, isn't it?

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url =
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

In case you retrieve a branch named pr/3 from the origin fetched based on your first refspec +refs/heads/*:refs/remotes/origin/* and there is a third pull request, it would conflict. I never tried it, but that's why I got fetch = +refs/pull/*/head:refs/gh-pull/remotes/origin/* as refspec, which is not conflicting with anything of git.

On a side note, when building scripts imitating the "merge"-button of github, you can make use of fetch = +refs/pull/*/merge:refs/gh-merge/remotes/origin/* which point to the merge commit of the respective pull request.


Anyone managed to work out how to actually remove the pull ref, for example:
git push origin :pr/1
doesn't seem to work


You can also use and run git checkout


Any reason for, when I do
git fetch origin --prune
it creates the pr local branches and it deletes them right after?


 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
 x [deleted]         (none)     -> origin/pr/1
 x [deleted]         (none)     -> origin/pr/2

@tomjenkinson did you ever figure out a solution to deleting them remotely, or to at least ignore those that are closed?


@arthurnn The fetch line for pull requests needs to be before the one for heads. I wrote a small shell function to do this.


I just wanted to chime in and tell you about a tool I put together to work with pull requests from the command line.

I know it's been done before, but I wanted to take a slightly different approach.

It's here:










The way I normally do this is just to add the other user as a remote:

git remote add other_user other_user_repo_url
git fetch other_user
git checkout -b other_user_branch other_user/branch

Nice, though!


ooh, I've been trying to figure this one out forever ! I strongly dislike just reading and clicking "merge this" without testing.




Thank you


You can also try which shows you a list of pull requests.


For the record, pushing a locally-merged PR closed it in the GitHub UI. ✨


I get an error trying to set up the branch as a tracking branch:

$ git checkout pr/785
error: Not tracking: ambiguous information for ref refs/remotes/origin/pr/785
Switched to a new branch 'pr/785'

Indications are that it's because there are too many such branches?


And also for the record, a fast-forward merge doesn't seem to close the PR in GitHub. That is, I rebased master onto pr/785, then merged pr/785 to master, then pushed, and the PR is still open.


I hypothesize that rebasing meant that the original commit hash was lost, and GitHub looks at commit hashes to determine whether a PR is closed.


I wonder if my broken tracking branch affects this as well?


@whit537 I think you're right about rebase being the issue. Github looks only for the hashes in the original PR commits. A fast-forward vs. non-fast-forward shouldn't matter, but if a rebase changes the hashes it won't work.



It seems that git merge --no-ff pr/785 and git cherry-pick pr/785 might be good parts of a workflow that doesn't confuse GitHub.


@treyhunner Ah, okay, thanks. :)


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

So if I'm reading this right, it means that GitHub keeps pull requests in the pull namespace, ya?


I get the same error message trying to fix up a tracking branch after the fact:

$ git branch --set-upstream-to=origin/pr/782
error: Not tracking: ambiguous information for ref refs/remotes/origin/pr/782

Hellz yeah, thanks!


Here's fetch:

$ git fetch
 * [new ref]         refs/pull/100/head -> origin/pr/100
 * [new ref]         refs/pull/105/head -> origin/pr/105
 * [new ref]         refs/pull/117/head -> origin/pr/117
 * [new ref]         refs/pull/137/head -> origin/pr/137
 * [new ref]         refs/pull/782/head -> origin/pr/782
 * [new ref]         refs/pull/785/head -> origin/pr/785
 * [new ref]         refs/pull/788/head -> origin/pr/788
 * [new ref]         refs/pull/790/head -> origin/pr/790

And then:

$ git remote show origin
* remote origin
  Fetch URL:
  Push  URL:
  HEAD branch: master
  Remote branches:
    master                     tracked
    refs/pull/100/head         tracked
    refs/pull/105/head         tracked
    refs/pull/117/head         tracked
    refs/pull/137/head         tracked
    refs/pull/782/head         tracked
    refs/pull/785/head         tracked
    refs/pull/788/head         tracked
    refs/pull/790/head         tracked
    refs/remotes/origin/pr/100 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/105 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/117 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/137 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/782 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/785 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/788 stale (use 'git remote prune' to remove)
    refs/remotes/origin/pr/790 stale (use 'git remote prune' to remove)
  Local branches configured for 'git pull':
    master   merges with remote master
  Local refs configured for 'git push':
    master            pushes to master            (up to date)

And then:

$ git remote prune origin
Pruning origin
 * [pruned] origin/pr/100
 * [pruned] origin/pr/105
 * [pruned] origin/pr/117
 * [pruned] origin/pr/137
 * [pruned] origin/pr/782
 * [pruned] origin/pr/785
 * [pruned] origin/pr/788
 * [pruned] origin/pr/790

Bringing me back to:

* remote origin
  Fetch URL:
  Push  URL:
  HEAD branch: master
  Remote branches:
    master             tracked
    refs/pull/100/head new (next fetch will store in remotes/origin)
    refs/pull/105/head new (next fetch will store in remotes/origin)
    refs/pull/117/head new (next fetch will store in remotes/origin)
    refs/pull/137/head new (next fetch will store in remotes/origin)
    refs/pull/782/head new (next fetch will store in remotes/origin)
    refs/pull/785/head new (next fetch will store in remotes/origin)
    refs/pull/788/head new (next fetch will store in remotes/origin)
    refs/pull/790/head new (next fetch will store in remotes/origin)
    rubygems           tracked
  Local branches configured for 'git pull':
    master   merges with remote master
  Local refs configured for 'git push':
    master            pushes to master            (up to date)
$ git --version
git version

Got it! The heroku remote in my .git/config conflicts. Let's see how to configure for both ...


Well, next thing:

$ git branch
* pull/782
$ git pull
Your configuration specifies to merge with the ref 'pull/782'
from the remote, but no such ref was fetched.

@jasoncodes's tip above about the order of the fetch refspecs takes the stale output out of git remote show origin.


I fixed the heroku conflict by removing the fetch key in the [heroku] section of .git/config. Now it just looks like:

[remote "heroku"]                                                                             
    url =

I can still push to it just fine.


This is awesome!

Is it possible to filter for pull requests against a specific branch? thx!


Never mind, doesn't look possible without it getting overly complicated. I wouldn't have gotten much out of it anyway.




awesome! :)


Dope!! Thanks for the tip.


I cannot properly express all the love that this small piece of text musters in me. You have my gratitude.




You can create an alias to pull single pulls:

In your global .gitconfig:

 pr = "!f() { git fetch origin refs/pull/$1/head:pr/$1; } ; f"

of course this always assumes origin because thats all I ever use for upstream when I'm a maintainer, but you can customize that part too if you want, relatively trivial


This is the best thing ever.


I'm trying to figure out what's the value of this? Since each PR is attached to a branch you can just checkout the branch, right?


@sickill not if someone forks your repo and works within this repo


Thank you @piscisaureus for the Gist!
However, for my purposes - @gnarf37 - your solution is more concise :-)


Today when I did git pull I got a lot of

 * [new ref]

But I didn't change anything in my .git/config. I thought those new refs would only be pulled if I added the line

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

Is my understanding correct or am I missing something? Thanks in advance for any information.




Great, thanks :)


Modification of @cldwalker suggestion, ~/.gitconfig:

pullify = config --add remote.origin.fetch '+refs/pull/*/head:refs/remotes/origin/pr/*'

or for arbitrary remotes use $1 for 'origin'.




git checkout master
curl | git am



@gnarf has some nice aliases at

$ git pr 537
 * [new ref]         refs/pull/537/head -> pr/537
Switched to branch 'pr/537'
$ co master
Switched to branch 'master'
$ git pr-clean
Deleted branch pr/537 (was e17f10a).

I prefer this method from @joelmccracken, Thanks, BTW.

git remote add other_user other_user_repo_url
git fetch other_user
git checkout -b other_user_branch other_user/branch

tzz commented Jan 6, 2014

clever, thanks!


How would one add commits to a pr? With this:

git checkout pr/74
git commit -m 'Fixed some stuff'
git push origin pr/74

It creates a new branch pr/74


It would be superb if you could pull only open pull requests like this.


@whit537, I' m getting the same issue as you (Your configuration specifies to merge with the ref 'pull/782'
from the remote, but no such ref was fetched), any idea how to fix?


Somehow I get this:

git fetch origin
fatal: refs/remotes/origin/pr/40 tracks both refs/heads/pr/40 and refs/pull/40/head
Unexpected end of command stream

Any ideas what it might be?


Is it possible for a maintainer to rebase a pull from a fork (instead of having to tell the originator of the PR to do it in their fork themselves?)


@JayMarshal - had the same problem and error message. I'd somehow managed to create a branch called pr/22. I verified this by seeing the branch in GitHub.

I used the following to delete the erroneous pr branch (from

git push origin --delete pr/22

Everything now working correctly and I can pull again.


This gist breaks installing Homebrew

Sorry for shouting, lots of comments in here. Don't get me wrong: this won't break installing with brew, but this will break installing brew itself. Indeed, using this trick will give you brew issue #19436, and will probably break some other scripts.

Basically, if a repo does not yet have an origin set, the instruction from this gist will pretend it has. However, since it has no URL (which of course it couldn't, since we want it to be generic), no fetch can happen, but you also can't associate any new origin, since it already exists.


@beporter Yes, you can.
Just create a branch from the submitted branch: git checkout -b pr42-rebased pr/42 ; git rebase master.
As an alternative you can also just cherry-pick each commit of the pr.


It works


Sooo looooog....Greate.


Thank You!


@piscisaureus It appears @jasoncodes's note about the order of the fetch lines is correct, i.e.:

[remote "origin"]
    url =
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
    fetch = +refs/heads/*:refs/remotes/origin/*

If the PR fetch comes after the regular fetch, I end up with an ambiguous (and non-existent) remote tracking branch in on Mac. After the reordering, as above, assigned remote tracking branch is accurate and pulling in new changes works (though I'm sure if the remote PR is rebased and force-pushed a new local branch will still need checked out, as per norm).

This may be specific to the way SourceTree auto-assigns a tracking branch, but nonetheless, works for me.


And also for the record, a fast-forward merge doesn't seem to close the PR in GitHub. That is, I rebased master onto pr/785, then merged pr/785 to master, then pushed, and the PR is still open.

This is a feature github is still missing: Recognizing fast-forward merges.


I love this shit.


Wow. Thanks for posting this!! Just what I needed to rescue a pull request whose original submitter had deleted the repository of, so there was no other reference to the commits.


This used to work fine but now I'm getting:

>>git pull origin
fatal: Cannot fetch both refs/pull/416/head and refs/heads/pr/416 to refs/remotes/origin/pr/416

Any idea?

EDIT: Turns out there was a remote branch named pr/416 I had to delete.


I did this so often that I wrote a tool to do it for me, hope you like it!


Once I am on one of these PR branches, is there anyway to find out the name of the branch this PR was made from?

Eg, say I had a PR open for master..my_feature and I checkout out pr/123... Is there any git command to tell me that ref points to the HEAD of my_feature?


worked for me! Thanks for your efforts.


Thanks for this post. Super helpful.


You know what? You are both cool and awesome.
Thanks a lot.




100 X πŸ‘, Thanks!


never saw that coming!


In addition to

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

I recommend grabbing the merge ref as well:

    fetch = +refs/pull/*/merge:refs/remotes/origin/pr/*/merge

Merge refs are the merge result from your branch to your merge target, they contain an exact copy of what the tip of the master will become when merged (well exact spare for an author perhaps)

rr- commented Sep 4, 2015

Can I use this to recover active pull requests from deleted forks?


nice one !


Nice, thank you ❀️


I use a bash function for this

# Git Checkout a Pull Request locally.
# Usage: gfpr 8
# Where 8 is the number of pull request (can be found right after the PR's title).
# @author Ahmad Awais
function gfpr(){
  echo "${whitef}β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”${reset}"
    echo "${whiteb} ${blackf}0. Fetching the pull request...${reset}"

    git fetch origin pull/"${1}"/head:pull_"${1}"

    echo "${whiteb} ${blackf}1. PR fetched creating a branch...${reset}"

    git checkout pull_"${1}"

    echo "${whiteb} ${blackf}2. Checking out to a new PR branch...${reset}"

    echo "${greenb} ${blackf}3. PR Branch Created!!!${reset}"
  echo "${whitef}β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”${reset}"


There needs to be something in upstream git that just...does that. or at least in github/hub :p


@tomjenkinson & @jimi-c: About removing any remote pull ref from a github repo, I’m pretty sure you can’t. If you could, the way would be:

git push --delete origin refs/pull/1/head

…where 1 is of course the PR number for whatever pull ref you want to remove.

But if you try that, you’ll get a message saying something like:

! [remote rejected] refs/pull/1/head (deny updating a hidden ref)

…the reason being that the github remote refs/pull/ namespace is a (synthetic) read-only namespace.


A stupid way to recover a commit that has been rebased and is now unreachable:

  1. Given unreachable commit
  2. See if you can compare them to any earlier commit you have
  3. Push your local commit up to a recovery branch git checkout f571415f4da9cc28edc83242e353966677dabcd2; git checkout -b recovery; git push origin recovery
  4. See the patch commits and download as recovery.patch (you could curl unless it's private so blah blah)
  5. Apply the patch commits and push up. git am recovery.patch && git push origin recovery

Thank you


Is there way to get only opened pull requests, not all? Because I don't wanna see already merged requests.


Thank you. It's helpful!


Thank you. It's helpful!


@sideshowbarker (@tomjenkinson @jimi-c)

whilst pull is readonly, it seems you can remove from the heads.

git push --delete upstream refs/heads/pr/521

This seems to fix the issue for our team (the PR/branch has since been deleted... I'm hoping it won't come back).


Very Useful thanks.




This is useful, thank you!



Thanks for the useful tip !
One drawback only, how to update it's local branch when someone added a commit to the pull request ?
I tried git pull in the local branch, but I got this error:

pol@localhost ~/d/g/mysite> git pull
Your configuration specifies to merge with the ref 'pr/4'
from the remote, but no such ref was fetched.
pol@localhost ~/d/g/mysite>

oh so nice tip


Reading I do not see a command to add this * refspecs

It seems one can fetch an individual PR by something like git fetch origin master:refs/remotes/origin/mymaster but I haven't figured out as adding the whole lot is much simpler as most of the time one is interested in more then one PR


awesome job it could either checkout upstream pull requests.


awesome \o/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment