What's the workflow to contribute to an open source project using git pull requests? (eg. via Github)

Since changes contributed to open source projects will have to be peer reviewed it's common to see a workflow which relies on git pull requests. Pull requests are not allowed from directly cloned repos (you need your own fork). So these are the steps I follow to maintain a healthy fork and contribute to an open source periodically:

Note: Steps 1, 2 and 3 are only done once per project on a single development machine to set everything up.

Note 2: If the open source project that you will be contributing to doesn't use master as the default working branch you will have to replace all reference to 'master' in the commands of steps 4) and 7) below with the name of that branch.

1) Make sure you're working locally on your "fork" of the project rather than on a cloned repository pointing to the project as origin. In order to fork a Github project go to https://github.com/entity/project , click on "Fork" and choose a suitable GitHub account for the fork eg. your personal Github account. Note that your forked project "origin" will be no longer the original project repo but your own fork on Github. Be careful with privacy if you're forking a private project since you probably don't want your fork to be public.

2) Clone your own project fork into your development machine and cd into that directory.

git clone [email protected]:yourgithubuser/project.git

3) Add the original project repo as upstream repository in your forked project.

git remote add upstream [email protected]:entity/project.git

The original main project repo is now "upstream" but not "origin"

And now comes the work loop that you'll repeat when you work with your forked project:

4) Before starting your work always make sure the master branch of your forked repo is synchronized with the master branch of the original project repo:

git checkout master
git fetch upstream
git merge upstream/master
git push origin master

5) Create a new branch in your project fork for the specific fixes that you want to contribute (name it after either a bugfix, a tracker issue, a documentation section, etc) and switch to it.

git checkout -b myfixes

This automatically creates the branch and switches to it. Make sure the branch does not exist already. You might also want to get rid of your old fix branches that have already been merged into the docs (otherwise you'll have tons of useless branches in your project). You can take a look at your local branches by issuing a git branch and if in that list you find a branch that has already been merged with the upstream project then you can do:

git branch -D myoldfixes
git push origin --delete myoldfixes

Important note: if you were already working on a branch on a different machine and want to continue that work on a new machine you need to redo steps 2, 3 and 4 on the new machine and in step 5 instead of doing git checkout -b myfixes you should do git checkout myfixes (remove the -b). Otherwise you can end up with a "detached head" state which is not good (kind of an anonymous branch)

6) Work on that branch (eg. myfixes) and commit your changes:

git commit -a -m "My fixes"

(Alternatively you can stage specific files and commit without using -a. You can commit as many times as you want but don't leave uncommited changes in the branch)

7) While you were working on your fixes the original upstream project repo might have changed (due to other contributors working on it). So first you'll have to rebase your current branch (myfixes) from the upstream destination branch. In other words you need to replay your fixes on top of that latest work from upstream repo master branch to make sure your commits are still compatible with the latest commits in upstream. This will result in a fast-forward merge for the pull request which is what we want:

git checkout myfixes
git pull --rebase upstream master

Note 3: this can result in conflicts but this is normal, fixing them is part of the process (this happens more often on very active projects)

Note 4: if you have many commits in the branch and you're a considerate person you might want to squash your commits into a single one for the benefit of the maintainer of the original project

8) After fixing the conflicts (if any) of the previous step you have applied your fixes on top of the latest version of upstream master. Since the pull requests are initiated from your forked repository on Github you want to keep that one in sync too:

git checkout myfixes
git push origin myfixes -f

9) Finally, you can go to Github https://github.com/entity/project (the original project not your fork) and click on "Pull Request". Make sure you choose upstream repo "master" as the destination branch and your forked repo "myfixes" as the source branch (the branch will be automatically removed for you after the pull request is accepted)

Enjoy!