The common model for contributing to an open-source project is the fork/pull request model. In this model, if you want to contribute to a project, you don't need commit rights to the projects GitHub repository. Instead, you "fork" the repository to create your own copy. You make your changes in your own fork and then submit a "pull request" (PR) which is a request that your changes get merged into the main repository. The fork/PR model is beneficial even in a work environment, as it allows fine-grained control over repository permissions while still allowing non-owners to contribute. See GitHub's About collaborative development models and its "Further reading" section for more information.
This document gives some tips for:
- cloning (making a local copy of) a repository
- forking (making a remote copy of) a repository
- fetching pull request code
Cloning a git repository means making a local copy of it. When I clone a repository I like my local copy to refer to the official remote repository as upstream
(I use origin
to refer to my remote fork of the main repository). When I want to clone a repository, I usually do something like this:
First, navigate to the project GitHub page (so something like https://github.com/typelevel/cats). Click on the "Clone or download" button, and you should see a URI that looks something like [email protected]:typelevel/cats.git
. You may want to click Use SSH
if you see an https
URI, but if you aren't logged in you'll only see an https
URI, and it should work just fine for now.
Now you can clone the repository with the URI that you've obtained:
cd ~/code
# The name upstream is ultimately arbitrary, so feel free to change it.
# Make sure that you change the URI to the repository that you want to clone
git clone -o upstream [email protected]:typelevel/cats.git
To fork a repository, click on the Fork
button toward the upper-right corner of the project's GitHub page.
Let's say that you've already made a local clone of the cats
repository into your ~/code/cats
directory and now you've forked the Cats GitHub repository and want your local git repository to be aware of your fork. You can do this by adding a new remote
named origin
(or whatever your name preference is):
cd ~/code/cats
# Make sure that you change the URI to point to your fork.
git remote add origin [email protected]:ceedubs/cats.git
Now you can run commands like git fetch origin
or git push -u origin my-branch-name
to work with your fork.
Sometimes when you are reviewing a pull request it's handy to pull the code locally so you can view it in your editor of choice, play around with it, etc. Luckily, a git alias can be used to make this easy.
First, you are going to add a git alias to your global git configuration:
# This assumes that you call the official repository "upstream".
# Change both occurences of "upstream" to "origin" (or whatever) depending on your preferences.
git config --global --add alias.add-prs "config --add remote.upstream.fetch '+refs/pull/*/head:refs/remotes/upstream/pr/*'"
The above command will add a a line or two to your ~.gitconfig
to set up a git alias named add-prs
. Once your global git configuration has been updated, you shouldn't need to run this command again on the same machine.
Okay, so what does add-prs
actually do? Lets say that you've cloned a repository named cats
using a command like git clone -o upstream [email protected]:typelevel/cats.git
. If you look at cats/.git/config
you should see something like this:
[remote "upstream"]
url = [email protected]:typelevel/cats.git
fetch = +refs/heads/*:refs/remotes/upstream/*
This means that whenever you call git fetch upstream
, it will fetch updates from the remote repository.
Now, when you are inside the cats
project, you can run git add-prs
. This will update cats/.git/config
to look something like:
[remote "upstream"]
url = [email protected]:typelevel/cats.git
fetch = +refs/heads/*:refs/remotes/upstream/*
fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*
For each GitHub repository, GitHub stores pull requests in a git repository named pull
. So now when you run get fetch upstream
, you will also fetch pull request updates and store them in branches with names like upstream/pr/42
.
Give it a try!
git fetch upstream
git checkout upstream/pr/42
Now you are working on a copy of the latest code from pull request #42 and can give it a spin.