My first Pull Request

Paul Cochrane edited this page Feb 3, 2015 · 15 revisions

Intro

What is a Pull Request?

A pull request (abbreviated as PR) is the ability to request a Git repository administrator to fetch changes you've made to their repository.

The concept is simple: Lisa has a repository of code. Bart would like to help out. Bart creates a copy (what's called a fork) of Lisa's code, makes changes, and submits a pull request to Lisa. She can then decide whether she would like to accept Bart's changes (by pulling the changes from Bart's Git repository - hence the name) or not.

Github provides a comfortable interface to submit pull requests and to accept and merge pull requests. It makes it close to trivial to provide changes and have them easily reviewed and added to an existing code-base.

Preparation:

In order to submit a pull request you will need a Github account. Jump over to Github and create your account. It's free and takes only a moment or two.

If you're familiar with SSH keys, you should add yours so you won't have to keep repeating your password when you push and pull. (You may also want to have a look at github-keygen to ease the creation of your SSH setup; by the way, this is Perl code written by a CPAN author where PR are also welcome!).

My first Pull Request:

While Github provides an excellent tutorial on how to use the pull request functionality, this tutorial here is directed at the CPAN Pull Request Challenge.

Every project you receive will have a Github repository URL. This is where the code resides.

First, check if the repository contains a CONTRIBUTING file. Read it first as the maintainer of the module may have specific requirements on how to contribute to the project.

We will go over the following steps:

  1. Making our own copy of the code
  2. Making the changes
  3. Committing them to our own copy
  4. Pushing the code and finally,
  5. Submitting them to the author as a pull request

Our very own copy

We begin by creating our own copy of the code. This is called a repository fork and it's fairly easy to do. When opening the repository on Github, we simply press Fork on the top right.

Once the forking process has finished, Github will host another copy of the repository under our username. However, since it's on the Github server and we don't have access to the server, we actually need to make a local copy on our hard drive. We'll be able to edit it on our computer and sync it with our Github copy.

If you're using the Git command-line application, you can do this using the following command:

git clone https://github.com/$USERNAME/$REPOSITORY.git

If you've provided SSH keys in your profile, you could use the following command to clone it using ssh:

git clone git@github.com:$USERNAME/$REPOSITORY.git

You will have to replace $USERNAME and $REPOSITORY with your username and the repository name.

You can also find this path on the right menu between Settings and Download ZIP. It's called clone URL. You can just copy paste it.

Our contribution

Once we've cloned our code, we have a directory set up containing the entire code. We can simply edit it and commit, but providing this change in an isolated form is favored and considered much more helpful.

Git works in branches with the default being master. By providing your code under a new branch (for example, doc/rework-chapters) makes it easy for the author to review it in isolation from the rest of the code in the main branch, make any changes they find necessary (which tends to happen) and merge it cleanly.

Using the command line, we simply create a new branch and move to it:

git checkout -b doc/rework-chapters

We then begin reworking the chapters: adding new files, removing old, editing the content, structuring the index for them, etc.

It's worth noting that if you remove files, you should remove them with git rm <file name> instead of just deleting them.

Committing to commit

A commit is basically a change with a summary and a possible description.

In order to make a commit, you can either have Git open your editor for you and let you write a commit message, or simply ask Git to commit with a message from the command line without opening an editor.

First, let's add all the files we've edited:

# assuming we changed/added these files
git add lib/Module.pm MANIFEST ...

Now we can commit those:

# give git the message in the command line
git commit -m "short description"

# ask git to open an editor so you could write your message
git commit
# you can set your preferred editor with the EDITOR environment variable, for example
export EDITOR=nano

If you want to know what Git is going to commit, we can run:

git status

The commit message is an important piece of the puzzle. It helps understand what the change entails, why it's necessary, the importance of it, and a historical record of all the relevant bits. Big projects with many contributors depend on commit messages to provide insight into a change.

There are recommendations for writing a useful and helpful commit message:

  • Summary should be around 50 characters. Short and to the point.
  • Description should include: Reason for change, how it works, and any information which makes it easier to review the work when merging and when looking back at it.

An example for a good commit message:

Support PDF MIME type:

The MIME type "application/pdf" was not supported. It is now implemented
by using the module Acme::PDF::Creator.

In order to accomplish this, the MIME types had been refactored. The
tests were improved to support multiple types as well.

(Notice there's a line of separation between the summary and the description, it's mandatory.)

Not all commit messages must be this long. The rule of thumb is to be as helpful as possible for both the current maintainer(s) and new contributors such as yourself.

Imagine you're a new contributor to the code and want to fix a problem. You read a few lines of code that don't seem to make sense. You try to be thorough and understand why it's written this way. You ask the maintainer and they say "I haven't written those lines" or "I don't remember". What do you do? You check the Git history! Unfortunately the commit message is "make it work" and you sigh. :)

Pushing the change

Now we have our branch ready with our change committed. It has a clear summary and helpful description. We're almost ready to provide this to the author.

A pull request on Github can only be sent from other Github repositories. What we want to do is simply sync our local copy with our Github copy. Then we can submit the pull request.

Doing this is simple enough:

git push

However, depending on your Git version and configuration, that might not work automatically. The way to make this always work is to simply be explicit, asking Git to push to our Github copy the branch we worked on:

git push origin feature/pdf-mime-support

Now we have our code and our branch on both our local copy on our disk and on our Github copy. Now we can send a pull request to the author.

Submitting the pull request

Check again if the repository contains a CONTRIBUTING file, and read it again to ensure you are doing things in the way the maintainer expects.

If we go to the Github page containing our own repository copy, Github will display a message at the center of the page (right above the directory tree of the code) telling us we pushed a new branch, and providing us with a button that says Compare & pull request.

Once we press the button, it opens a page showing us the change we made. It will take the last commit message we provided and use it as the description it will send to the author (and allow us to edit it). We can review it, decide if we want to change the message the author gets or not, and then pick Create pull request.

Done. :)

Cleaning up after the pull request has been merged

At some point in time your pull request will hopefully be merged by the distribution's author/maintainer. This means the branches you created both in your local repository and in your fork on GitHub are no longer necessary. You can check which branches exist both remotely and locally via:

git branch -a

where remote branches are prefixed with remotes and local branches are shown with simply their branch name.

You can remove merged branches in a couple of different ways.

Use the GitHub interface

On the GitHub page for your pull request, you will see that once it has been merged, a message will appear that you can now delete your branch. Simply click on Delete branch to remove your branch from your fork on GitHub.

This still leaves a branch in your local copy of the repository. To remove the local branch simply use the Git command:

git branch -d <branch_name>

Use the Git command line interface

The remote and local branches can be deleted via the Git command line alone. To remove the remote branch use:

git push origin --delete <branch_name>

And then you can delete the local branch as in the previous section with:

git branch -d <branch_name>