How to Handle Github Pull Requests Like A Boss

Written by fagnerbrack | Published 2016/05/23
Tech Story Tags: git | github | programming | software-development | software-engineering

TLDRvia the TL;DR App

An "old, but gold" trick to easily fetch Pull Requests from Github

A dark wallpaper with the Github logo's silhouette in the center

There's a practice widely used in popular Open Source projects hosted on Github for receiving contributions efficiently. The contributor creates a small branch that represents a single feature, and when that branch is pushed to the contributor's fork they create a Pull Request. I have elaborated on the best practices of how to do this in a previous post called One Pull Request. One Concern.

As from the time of this writing, jQuery uses this model extensively among their contributors. They document the model in their Commits and Pull Requests guideline and use it as a requirement for new contributions. They have been using it for years.

A common practice in Open Source projects is to request for a contributor to fork the project, create a temporary branch and create a Pull Request from that branch that represents a single concern.

There are companies that also use this model for managing their development. Pull Requests allow developers to integrate their changes frequently, which reduces the chances for code conflict and make it possible to spot bugs early. This is early feedback, which is one of the core principles of Continuous Integration.

There's one trick, though, that we can use to manage Pull Requests.

When using Github, everyone that have permissions to merge Pull requests to the master branch have 2 options:

  1. Use the Github Pull Request UI to merge the commits to the master branch.
  2. Use git in the command line to add the reference to the Pull Request branch as a remote locally (git remote add <contributor's fork url>), fetch the Pull Request branch from that remote and then merge the commits to the master branch.

The first option is the most common and the easiest one. Whoever has permissions can go to the Pull Request page on Github and click the "merge" button.

The second option is most commonly used when who is merging the Pull Request want to have total control over the commits that are landed on master. Why is that? Well, there are workflows that may need to commit on master with git information that Github don’t set through their Pull Request Web UI. Linus have complained about this in the past and that's why he doesn’t even accept Github Pull Requests in the Linux Kernel.

The issue with the second option is that you need to add a remote for every Pull Request in order to commit on master. Many Pull Requests can have different contributors with different forks. Adding all of them can become messy because you will eventually have tons of remotes in our local copy of the project.

Bert Belder published an interesting trick 4 years ago that allow someone to download all Pull Requests from a repository locally with a single git fetch command.

The trick is to add the line below to the .git/config file that is located from the root of the project you want to change:

fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

The part that says origin can be different. It just represents the name of the remote that has a reference to the repository you want to fetch the Pull Requests from. It's the default name for the remote that git creates when we use the command git clone <path to the repository>.

When running the git fetch command with this trick, git will fetch all Pull Requests that have been opened against that remote:

The output of the "git fetch" command when the Pull Request fetching technique is applied. It's fetching the refs from a copy of the js-cookie project.

Notice the [new ref] refs/pull/280/head -> origin/pr/280 part, that's when the Pull Requests are fetched from the remote. They will be available to be checked out using git checkout origin/pr/280.

Ok, now can you push the changes to a Pull Request using the same command line trick?

According to the Github documentation, you can't. Github doesn’t allow pushing to a hidden ref:

The remote refs/pull/ namespace is read-only

— Github's "Checking out pull requests locally" documentation

Any attempt to push to the ref will present the following error:

! [remote rejected] HEAD -> refs/pull/1/head (deny updating a hidden ref)

The only way to update a Pull Request is adding a new remote that has a reference to the fork of the contributor who created it. If you have permissions to write in their fork, you can push any changes to the Pull Request branch in their remote and it will be updated on the Github Pull Request Web UI automatically.

It's impossible to change a Pull Request using the multiple Pull Requests fetching trick because Github makes hidden refs as read-only

This Pull Request fetching trick will make your workflow more convenient when working with Pull Requests. It's one of those things that are very simple and still yields a lot of benefits depending on your workflow.

I have been using this for a long time in projects using the second option.

What about you?

Thanks for reading. If you have some feedback, reach out to me on Twitter, Facebook or Github.


Published by HackerNoon on 2016/05/23