Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Working With Multiple Repositories On GitHub

Working With Multiple Repositories On GitHub

Most projects on GitHub have a main repository that's the focal point of activity. For example, the Example organization has the Example.com repository:

https://github.com/example/example.com

Developers of Example.com typically call this the 'upstream' repository. We'll come back to it in a moment.

Using GitHub, each individual developer of Example.com uses the Fork button to create his or her own GitHub-hosted copy of the Example.com repository. For example, Alice forks the repository to her account:

https://github.com/alice/example.com

Using standard Git terminology, this is Alice's remote 'origin' repository. She can create a copy of it on her local computer using the git clone command:

git clone https://github.com/alice/example.com.git

Changing directory into her local repository, she can now add to her remote list the upstream repository and fetch data from it:

cd example.com
git remote add upstream https://github.com/example/example.com
git fetch --all

To edit a file, Alice checks out a new branch based off of the upstream repository (not her own), edits the file, commits her change, and pushes it to her remote origin.

git checkout -b new_branch upstream/master
$EDITOR the_file
git commit -a -m 'Edited The File'
git push origin new_branch

From the GitHub user interface, she can now open a Pull Request (PR). Her PR number is #123.

Opening A PR For A PR

Bob discovers a bug in Alice's PR#123. Rather than trying to explain it, he wants to send Alice a patch using GitHub. He has already setup his own fork on GitHub, cloned it, and added a remote upstream. He just needs a local copy of Alice's code.

He could add Alice's repository as a remote, but he'd need to do that for each new contributor to Example.com. Instead, he wants to use GitHub's special pull references to access Alice's code directly. Bob changes directory to his local repository and opens his Git configuration file for editing:

cd example.com
$EDITOR .git/config

Then he adds the following lines to the bottom of the file:

[remote "upstream-pull"]
        url = https://github.com/example/example.com.git
        fetch = +refs/pull/*:refs/remotes/upstream-pull/*

After saving and closing the file, he pulls in the references for his new 'upstream-pull' remote:

git fetch --all

Bob can now checkout a new branch based on Alice's PR#123, fix the bug, commit his changes, and push them to his origin:

git checkout -b fix-the-file upstream-pull/123/head
$EDITOR the_file
git commit -a -m 'Fixed a bug'
git push origin fix-the-file

Finally, Bob can open a pull request against Alice's new_branch. Unfortunately, GitHub isn't smart enough yet to guess what branch you want to patch, so Bob's best bet is to browse to Alice's origin and open the PR from there:

https://github.com/alice/example.com

Bob's PR is assigned the number #7 in Alice's repository.

Locally Accessing PRs To Your Origin

Alice is notified of Bob's PR#7, but she wants to test it locally. Unfortunately, she can't use the upstream-pull trick directly because it only applies to PRs made to the upstream repository---but she can modify it to work for her repository. Editing her own .git/config, Alice adds the following lines:

[remote "origin-pull"]
        url = https://github.com/alice/example.com.git
        fetch = +refs/pull/*:refs/remotes/origin-pull/*

She then fetches the refs and then locally-only merges PR#7 into her new_branch for testing.

git fetch --all
git checkout new_branch
git merge origin-pull/7/head

After testing, Alice is satisfied and pushes the updated branch to her origin, which automatically updates her PR#123 and marks as merged Bob's PR#7:

git push origin new_branch

A Note On Fetching

You need to run git fetch --all or an equivalent command to get the most recent data from all of your remotes. For example, if someone opens PR#8 on the Alice's repository, Alice won't be able to see it until she runs fetch.

This can cause confusion when remote branches are updated, so it is recommended to always run fetch immediately before running commands like checkout and merge using a remote.

Summary

In this document, we showed you how to:

  1. Create an 'origin' remote pointing to your GitHub fork by using git clone

  2. Create an 'upstream' remote pointing to a project main repository

  3. Create an 'upstream-pull' remote containing a branch for every PR in the upstream repository

  4. Create an 'origin-pull' remote containing a branch for every PR to your own repository

In addition to enabling the process above, it is convenient to use the upstream-pull remote to make signed merges on the command line:

git checkout master
git pull
git merge -S upstream-pull/123/head
git diff upstream/master
git push upstream master

Thanks goes to Pieter Wuille for describing the -pull remote trick.

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