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:
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.
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:
[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:
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?
Create your free account to unlock your custom reading experience.