---
title: 8 New Steps for Fixing Other People's Code
teaser:
tags: web,git,ruby,open source,testing
author: Alex Grant
published_on: 2012-09-15
---

Way back in mid-2007, when Rails 1.2 was the new hotness and GitHub was still a
year away from crawling out of the primordial internet soup, prolific open
source contributor [Dr Nic](http://drnicwilliams.com/about/) wrote an article
titled ["8 steps for fixing other people's
code"](http://drnicwilliams.com/2007/06/01/8-steps-for-fixing-other-peoples-code/).
It offers excellent general advice, but the workflow details are clearly a
product of their time: RubyForge, SVN, and `.patch` files feature heavily.

Here in the fantastical future world of 2012, while we still don't have
[hoverboards](http://www.youtube.com/watch?v=TkyLnWm1iCs) or household nuclear
fusion, we do have some great tools that make fixing other people's code a lot
easier. Join me as we rewrite **"8 steps"** for the modern age!

## 1. Get annoyed by a bug or missing feature

Open source projects are usually far from perfect. In many cases they started as
something the author threw together to solve a problem, then released into the
wild just in case it could be useful to someone else. Open source contributions
come from regular people -- just like you! -- who start using the project and
run into a bug that annoys them, or get an idea for a feature that would make
their life easier.

The experience that prompted me to write this post started with finding a bug in
[Chronic](https://github.com/mojombo/chronic), a date-parsing library. The issue
is described in the [pull request](https://github.com/mojombo/chronic/pull/114)
I submitted to fix it (pull requests are the final step in this process; we'll
get to them in a bit).

## 2. Locate the repository and read up

In recent years [git](http://git-scm.com/) and [GitHub](https://github.com/)
have emerged as the de facto standard, if not for open source projects in
general, then at least for open source Ruby projects. Lucky you! In Dr Nic's
time it was all SVN, uphill both ways.

If your target project has a web site, it will probably link to the official
GitHub repository. Failing that, you can [search
GitHub](https://github.com/search) for the name of the project. This may also
turn up other people's forks of the project -- if you're not sure which one is
the original, just pick one and follow the **"forked from"** links.

Once you've found the repository, scroll down to the README and scan it for "How
to Contribute" directions. Some projects have a particular process they want
contributors to follow, and it might be different from the steps outlined here.
[Chronic's instructions](https://github.com/mojombo/chronic#contribute) are
typical and straightforward.

## 3. Fork the repository

Forking a project creates your own personal copy of the repository that you're
free to modify however you want. It's integral to the GitHub workflow, and is
therefore stupidly easy: Just hit the **Fork** button.

![''](http://media.tumblr.com/tumblr_ma6xg1fAAR1rwdzbb.jpg)

Copy the Read+Write link from your newly-forked repo and clone it down:

```sh
$ git clone git@github.com:grantovich/chronic.git
Cloning into 'chronic'...
```

Then copy the Read-Only link *from the original repository*
([mojombo/chronic](https://github.com/mojombo/chronic) in my case) and add it as
a "remote" like so:

```bash
cd chronic
git remote add upstream git://github.com/mojombo/chronic.git
```

## 4. Run the tests

Many projects use automated tests to ensure that bugs stay fixed and new
features don't introduce new bugs. Running a project's tests is also a useful
sanity check, since no tests should fail on an unmodified clone of the
**master** branch.

Before doing this, you'll need to install the project's dependencies -- if it
has any, it should include a `Gemfile`. Use `gem install bundler` to install
Bundler if you haven't already, then simply `bundle install`.

In most Ruby projects, running "`rake`" with no arguments will execute the full
test suite. Ensure this doesn't give you any failures before proceeding.

## 5. Make your changes

Come up with a short, descriptive name for a branch that will contain your
changes. Here's my Chronic branch:

```bash
git checkout -b handle-sm-sd-with-time
```

Now you're ready to start coding! Assuming the project has tests, you can do
some [TDD](http://en.wikipedia.org/wiki/Test-driven_development) and start by
writing a failing test. Poke around the existing test suite -- it likely
involves [Minitest](http://docs.seattlerb.org/minitest/) or
[Rspec](http://rspec.info/) -- then write one or more new tests that *would*
succeed if your feature existed or your bug was fixed.

Re-run the test suite to ensure your tests fail (and you didn't somehow break
any other tests). Then, write the code to make them pass! Follow the style of
the existing code as much as possible, and resist the temptation to "clean up"
or reformat things that aren't relevant to your change.

Many libraries have Rake tasks applicable to this step. `rake console` is a
common task that opens an IRB shell with your in-development copy of the library
loaded into it. If the library is made available as a gem, there will be a task
that builds the gem (e.g. `rake build`), and you'll want to make sure this still
works after you change things.

Note that while [the changes I made to
Chronic](https://github.com/mojombo/chronic/pull/114/files) were in multiple
commits, you should really put both the tests and the code that passes them into
a single commit. Any given commit should pass all the tests that exist within
it. You can still make multiple commits locally -- just [squash
them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
later using `git rebase -i origin/master`.

## 6. Document your changes

If you've added a new feature or changed how something works, and the project's
documentation lives in the repository (this is usually true for at least the
README file), update it to be consistent with your changes. Documentation never
gets enough love, and the owner will probably appreciate your thoughtfulness.

## 7. Get up-to-date

Pull down any changes made to the original repository since you started working,
and replay your commits onto the updated code. This ensures that your changes
can still be successfully applied to the latest version. It sounds complicated,
but the commands are quite simple:

```bash
git fetch upstream
git rebase upstream/master
```

## 8. Submit a pull request

Here's the other half of the fork-based GitHub workflow. After making changes in
your fork, you *request* that the original author *pull* those changes into
their repository.

First push the branch containing your commits up to GitHub...

```bash
git push -u
```

...then hit the **Pull Request** button on your forked repository.

![''](http://media.tumblr.com/tumblr_ma7cs5oQUT1rwdzbb.jpg)

Set the "head branch" on the right side of the pull request to your new branch.

![''](http://media.tumblr.com/tumblr_maavquepv01rwdzbb.jpg)

You'll be prompted to give your pull request a title (e.g. "Add support for
XYZ") and detailed description. Fill these in, and hit the **Send pull request**
button!

Now comes the hardest part: Waiting. The owners of the repository will be
notified of your pull request, and at some point -- hopefully -- will get around
to reviewing it. They might suggest some changes: Make them in your branch and
`git push`, and the pull request will automatically update with your new
commits. If your changes look good, they'll be officially merged into the
project. [Success!](https://github.com/mojombo/chronic/pull/114)

## Final thoughts

After you've done this once for a given project, the process is simplified: When
you're ready to contribute again, `git pull upstream master` so you're working
with the latest code, and start again from step 4.

While the GitHub web interface is more accessible if you're not used to the
workflow yet, it's actually possible to do all this without leaving your
terminal. Check out the [hub](https://github.com/defunkt/hub) tool, and more
specifically the commands dealing with [forks and pull
requests](https://github.com/defunkt/hub#git-fork). In fact, my Chronic pull
request was originally a bug report that I later "converted" using `hub`.

Remember these steps are [more like
guidelines](http://www.quickmeme.com/meme/36d2ks/) than actual rules. Every
project is different, and the owners of the one you're working on might prefer
you do things a bit (or a lot) differently. Be receptive to the feedback you get
on your pull requests, even if it seems nitpicky. You'll be hailed as a model
open source citizen in no time!
