Contributing to Open Source - grjug/ChuckNorrisJokes GitHub Wiki

Contributing to Open Source Projects

When working on a project where everyone shares and has write access to the same remote repository, everyone can easily keep their repositories in sync without much effort. There is one primary or canonical branch, often called master, but in our case is called develop (for more on this, see the git-flow model). Contributors create feature branches and submit pull requests to the master or develop branch, the PR gets merged in, and everyone can simply run git pull when in the primary branch to update the changes locally. However, in open source, there are often multiple forks of a single canonical repository, each with its own canonical master or develop branch. How do we properly keep those in sync?

When working on an open source project we follow a very similar pattern as if it was a shared repository, with a few added rules:

  1. Always keep the canonical branch in sync with the upstream repository. This means you will never submit a pull request to, commit directly on, or merge into your own master branch. You can only ever update the primary branch from the upstream repository.
  2. Always follow the branching rules (if there are any) and contributing guidelines for the project you are working on.
  3. Be kind, courteous, and open to comments and suggestions from the maintainers. You are writing the code, but they are the ones who have to maintain it, so it is important that they clearly understand what your code does and why.
  4. When writing commit messages, be clear, concise, and follow good commit message guidelines.
  5. When committing, keep your commits clean, focused, and atomic.
  6. When submitting pull requests, be descriptive about what it does and what problems it solves.

Branching

When we want to write a feature, fix a bug, or write some experimental code, we branch off of develop or master (depending on the project's branch model) and name our branch. We can do this by typing the following command into the terminal:

$ git checkout -b feature/add-joke-sharing

This will create a branch called feature/add-joke-sharing and check it out. You can see this illustrated below:

$ git branch
  master
  develop
* feature/add-joke-sharing

You can now start changing files and committing your changes. Once you've made a few commits, you can push a copy of your branch to the remote for which you have write access: origin:

$ git push -u origin feature/add-joke-sharing

This will create a copy of your branch on your fork of the repository, but will not affect the upstream repository at grjug/ChuckNorrisJokes. In order to do that, we need to make a pull request.

Pull Requests and Forked Repositories

The easiest way to make a pull request is to open up the repository on Github in your browser. If you have a freshly pushed branch, you will see something like this on top of the page:

screen shot 2014-07-15 at 11 53 31 pm

Here's where it's important to make a distinction between working on a shared repository versus collaborating on an open source project: it's very important you keep your canonical branch in sync with the upstream repository. This means that, unlike working on a single shared repo, where you would submit a pull request to your own repository's master or develop branch (or merge them in from the command line), you should submit the pull request to the upstream repository. Github makes this very easy for us; just click the link to the jrjug/ChuckNorrisJokes repository at the top where it says "forked from", and you should see something like this:

screen shot 2014-07-15 at 11 53 53 pm

At this point you can click the green button that says Compare & pull request. Fill in a descriptive name of the pull request and a meaningful explanation in the comment that explains what your pull request is meant to do and how it does it. Well written pull requests are not only more likely to be merged, but they're also helpful for the project maintainer to guide their code review and understand exactly what they're looking at. Once you've filled it out, you can click Create pull request and you'll see a brand new request queued up. If that pull request (or PR) gets merged in, it will become a part of the upstream repository.

Syncing with Upstream

Since our rule above about keeping your canonical branch in sync with the upstream repository is very important, we will never make a change to our own local master or develop branch that does not come directly from the upstream repository. Since our pull request was merged in (or other PRs were merged in while we were working), we can update our canonical branch by updating git's knowledge of the upstream repository, then merging its develop branch into our own:

$ git fetch upstream
$ git checkout develop
$ git merge upstream/develop
$ git push

As you type each of these commands, git will give you some feedback showing whether or not there were changes made. Here's the gist of what's happening:

  1. Tell git to look for any changes that have been made to our upstream remote and cache them locally.
  2. Checkout our canonical branch. Whenever you merge, you should first checkout the branch to which the merge should be applied.
  3. Merge our upstream/develop branch into develop. Note that upstream/develop is just another branch, but git treats it a little differently since it knows it is a copy of a remote. To see this in action, you can type git branch -a into your terminal and see all the branches git knows about for this repository.
  4. Update our forked origin so it stays up to date with everything else.

Committing with Git

One of the most common mistakes users of git make, new and old alike, is reckless commits. There are a few general rules to follow when you start changing code and committing it.

Always review your work before you commit.

Use git add -p to step through your diff and add code in chunks. This can be a little awkward at first, but with a little practice, it will become second nature. This tool can be extremely powerful once you grok it. Only add stuff you know belongs in the commit you're planning.

Committing with git add . or git commit -am are carpet-bomb techniques, and should generally be avoided. You will almost always end up committing something that doesn't belong in that commit. Doing so is like publishing an article without proofreading it first.

Commits should be atomic.

Keep when you are reviewing your commits and picking changes, try to make sure everything you are adding is specifically related to the goal. It helps to have a commit message in mind when picking chunks to add. For instance, you might have fixed a typo you noticed while working on a feature. Skip that patch when you are adding code and put it in its own commit afterward (or before, if you still have a lot of work to do on your feature). This will make it easy to save that change in case the rest of the feature doesn't end up getting merged.

Make good commit messages.

A good commit message describes the purpose of the content of your commit in 50 characters or less. When phrasing a commit message, think of it in terms of what the commit does. Something like "If merged, this commit will ".

Good

  • Add a button for generating random jokes
  • Fix typo in network error message
  • Allow users to use their name in jokes

Bad

  • Update
  • Added a button for generating random jokes
  • add a bunch of stuff

Additionally, if you want to say more about your commit, you can add an extended commit message. If you're writing your commit message in vim, just add an empty line below the first line (think of that as the subject line), and then start typing below that empty line (think of it as the body of an email). Best practice is to add manual line breaks at around 80 characters in the extended commit message.