Skip to content

Instantly share code, notes, and snippets.

@piscisaureus
Created August 13, 2012 16:12
Show Gist options
  • Save piscisaureus/3342247 to your computer and use it in GitHub Desktop.
Save piscisaureus/3342247 to your computer and use it in GitHub Desktop.
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 = [email protected]:joyent/node.git

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 = [email protected]:joyent/node.git
	fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

Now fetch all the pull requests:

$ git fetch origin
From github.com:joyent/node
 * [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'
@darthwalsh
Copy link

This is a great way to know if a commit is contained by some GitHub PR branch and won't be garbage collected!

Here's an example I went through: in a wiki I pasted several links to github repo files, using a specific hash abc in the URL in case the files was refactoring later. These commits might or might not have been part of some PR where Irebased and force-pushed over the PR branch, so I wasn't sure if this commit was still referenced by some branch, or might someday get deleted.

Running git branch -r --contains abc to search all remote commits didn't show anything, but git branch -r doesn't include all the refs/pull/* so that's not surprising. I could manually checkout relevant commits in git ls-remote and look through the logs to find abc as a parent, but that is error-prone. Making the .git/config change above, git fetch, then running git branch -r --contains abc outputed origin/pr/58 so that answered my question.

@subhamkumar-oyo
Copy link

I think it's not possible but still confirming if there is a way to check PR's title locally

@darthwalsh
Copy link

@subhamkumar-oyo testing this out, the PR branch only has the commits, and not the PR title. By default the PR title will be the commit title, but that's not guaranteed. Instead, you need to query for the PR title using the GitHub API, which is simple using the gh1 cli:

~/code/FireSocket $ gh pr list --state merged | grep 7.3.1
13	chore(deps): update dependency eslint to v7.3.1	renovate/eslint-7.x	MERGED

@kindlehl
Copy link

This is helpful :)

@msaroufim
Copy link

❤️

@patgarcia
Copy link

A decade later this gist is still super useful. I review homework PRs and this workflow makes that a breeze. Thank you @piscisaureus!!

@yuis-ice
Copy link

yuis-ice commented Feb 2, 2022

Very cool.

@matu3ba
Copy link

matu3ba commented Feb 13, 2022

I had to make a small correction for multiple remotes: git checkout upstream/pr/999, which would be nice to add for completeness.
This is much more compact than the github help page.

@nebbish
Copy link

nebbish commented Sep 13, 2022

There is an implementation "oddity" within Git about how this works. The new line added to the [remote "origin"] section does not have to be appended as the last line of that section. It could be inserted as the first line of that section.

Miraculously this makes a difference!

If you get the order correct -- then git pull just works after git checkout pr/1234 😃
This S.O. answer has the details.

No matter what though, as @dougludlow points out, git pull origin refs/pull/1234/head should work even if your branch.pr/1234.merge config value is not correct.

@simonmcnair
Copy link

Is this a reasonable python script to clone a repo and add the PR's ?

import subprocess
import os
from git import Repo

def clone_and_configure(github_url, local_path):
    # Perform the initial Git clone
    if os.path.exists(local_path):
        print(f"Local repository already exists in {local_path}. Skipping clone.")
    else:
        # Perform the initial Git clone
        subprocess.run(['git', 'clone', github_url, local_path])
        print(f"Repository cloned to {local_path}.")

    git_path = f'{local_path}/.git/'

    repo = Repo(git_path)
    # Read the existing Git configuration

    repoconfig = repo.config_reader()  # Get a config reader for read-only access.
    
    if any('origin' in key for key in repoconfig.sections()):
        print("found a section with origin")
        for section_name in repoconfig.sections():
            if 'origin' in section_name:
                fetch_line = '+refs/pull/*/head:refs/remotes/origin/pr/*'
                # Which to use ?
                #fetch_line = '+refs/pull/*/head:refs/gh-pull/remotes/origin/*'
                repo.git.config('--add', f'remote.origin.fetch', fetch_line)
                # Update the URL if needed
                repo.remote('origin').set_url(github_url)
    
    #subprocess.run(['git', 'fetch','origin', local_path])
    subprocess.run(['git', 'fetch', 'origin'], cwd=local_path)


def main():
    # Specify your GitHub project URL
    github_url = 'https://github.com/hardikvasa/google-images-download'  # Replace with your project URL
    # Specify the local path where you want to clone the repository
    local_path = 'C:/Users/Simon/Desktop/google-image-downloader'  # Replace with your desired local path

    # Perform the initial Git clone and configure
    clone_and_configure(github_url, local_path)

if __name__ == "__main__":
    main()

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