Many of the organizations that use Git—and probably the vast majority of open-source projects as well—employ a workflow centered around the pull request (PR). The PR process–a.k.a. the bulk of pre-merge idle time–is when the contributor asks the maintainer of a project to accept their branch and merge it into the project’s mainline. Accepting and merging a pull request should signal the end of the specific contribution, but if things don’t work as planned for some reason, you might need to revert a pull request in Git.

In this post, we’ll dive deep into how to revert a merged pull request. We’ll explore: 

  • The PR process at a high level 
  • How it works
  • Examples of situations that require reverting a merged PR
  • The “how” of reverting PRs in GitHub, GitLab, and “vanilla” Git (using git revert)

Let’s get started.

The Pull Request Process: What It Is and How It Works

Let’s start with some fundamentals: defining a pull request.

What Is a Git Pull Request?

A pull request is the mechanism by which a contributor to a Git repository offers some code and asks for the project’s maintainer to accept it and merge it to the mainline. 

Pull requests are not a feature of the native Git software. Rather, they are a feature of source code management (SCM) providers. First popularized by GitHub, nowadays they’re common in other platforms such as GitLab, BitBucket, and Azure DevOps.

Quick note: Git does offer a command called request-pullBecause who doesn’t love more complexity? It predates hosting services such as GitHub and what it does is generate a list of changes in the format of a patch file which gets sent by email.)

How Does a Pull Request Work?

TThe way a pull request—or merge request, as they’re called in GitLab—works varies depending on the source code hosting service you’re using. Here’s what the workflow looks like for a company using a service such as GitLab or Azure DevOps:

  1. The engineer clones the repository locally on their machine.
  2. They create a new branch—generally off of the main branch, but this could vary—and add their commits locally by pushing their commits to the remote repository. Pro tip: It’s a good practice for backup purposes.
  3. After completing the task—or deciding a fresh pair of eyes would be beneficial (even if the task is incomplete)—they create a new PR. It includes a title and a description explaining the reason for the change. Pro tip: Always include a reference in the PR title or description to the ticket/job number in the PM tool to ensure data hygiene and minimize project risk.
  4. Though not mandatory, there’s typically a code review process in which one or more people review the changes and give feedback on them before merging them.
  5. When the reviewers accept the PR, they merge the changes into the destination branch—often deleting the source branch—and mark the pull request as closed.

It should be noted that this process can take a long time and is the most time-consuming aspect of software development. That’s why PR merge time is one of the core metrics for companies like Slack. 

In fact, on average code reviews sit idle for 70% of cycle time!

Why Would You Want to Revert a Pull Request?

Here are some of the reasons why you might need to revert a pull request:

  • Merge resulted in a logical conflict. Sometimes a merge results in a logical conflict—i.e. as far as Git’s concerned, the merge happens cleanly (there are no merge conflicts), but changes in both branches result in the introduction of bugs.
  • Pull request was made to the wrong branch. This can happen, especially when the team uses a complex branch strategy, such as Git Flow.
  • Pull request merged without review. You might want to revert a pull request because the maintainer merged it without proper review. This is highly dangerous! LinearB’s WorkerB bot can alert you in real-time when this happens.

Identify your team rebels. Schedule a demo of WorkerB alerts for PRs merged without review.

Improve your code review process with tags, context for PR contents, and flags for risks like security vulnerabilities or use of deprecated components. 

Want to see how these tools can help you improve core metrics and drive more developer productivity? Get a free forever account of LinearB today!

Please note that reverting a pull request should be the exception rather than the norm. Having problems like the ones above is a sign your team has deeper issues that it needs to address. 

Merges resulting in conflict are often caused by pull requests taking too long to be reviewed and merged. Pull request pickup time is an important engineering metric that you should work to improve. With LinearB, you can get a detailed breakdown of your development cycles so that you can determine if valuable time is being wasted by pull requests sitting idle. One of the most impactful metrics a team can optimize is PR size–as smaller PRs get picked up, reviewed, and merged faster with fewer problems.

Check out our industry benchmarks based on an analysis of 2000+ dev teams. It covers metrics like PR size, Pickup time, Review time, and Cycle time and provides visibility into how teams stack up to industry peers. 

Benchmarks.png

How to Revert a Pull Request

With the “what” and “why” out of the way, let’s explore the how. We’ll start by explaining how to revert a pull request in GitHub.

Reverting a Pull Request in GitHub

GitHub offers the functionality of reverting pull requests. To illustrate this, I did the following:

  • Using GitHub’s web interface, I created a new repository.
  • Still in the UI, I added a few commits to the main branch.
  • On the command line, I cloned the repository locally using git fetch.
  • I created a new branch called new and added a few commits to it.
  • I then pushed the new branch to the remote repository.
  • Finally, I created a pull request from new to main, accepted it, and merged it.

On the repository’s page, I go to the pull requests tab and filter to see the closed PRs:

Screenshot of pull requests tab

After clicking on the PR, I access the detailed pull request page where I can see the Revert button:

Screenshot of revert button

This button does an interesting thing. It offers me the chance to create a new pull request whose changes effectively undo the changes resulting from the merge:

Screenshot "revert new"

I only have to click on the Create pull request button and I’ll be redirected to the page of the new pull request:

Screenshot new pull request

We can see that this pull request contains three commits. I’ll go over there to inspect them:

Screenshot of commits

Interestingly, GitHub created three new commits that undo the three original commits that I added when accepting the pull request (I’ve used the “rebase” option when accepting the PR, which means I’ve preserved the original commits as they were in the new branch.)

Completing the reversion is a walk in the park: just complete the pull request and you’re done.

Reverting a Pull Request in GitLab

GitLab is a bit less resourceful than its competitor when it comes to reverting pull requests. GitHub offers the ability to revert pull requests regardless of the method you used while merging them. Whether you rebased or squashed, used a fast forward merge or a merge commit, GitHub will be able to revert the changes. However, GitLab only shows the Revert option for projects that use git merge (which produces a “merge commit”) when accepting merge requests.

This time I did the same steps I did before to create a merge request with a few commits:

Screenshot create merge request

Then I created and accepted the merge request:

Screenshot accept merge request

Notice the Revert button at the top. After clicking it, I’m prompted to configure a few options:

Screenshot configure

I’m satisfied with the default options, so I click the Revert button, which brings me to the new merge request page:

Screenshot new merge request

The rest is super simple: I finish creating the PR, then merge it, and the original pull request is no more.

Reverting a Pull Request Using Git

What if GitHub and/or GitLab didn’t offer the option to revert a PR? You could still use vanilla Git to revert a pull request. Let’s see how you can do that in two ways.

The Non-Destructive Way: The Git Revert Command

Under the hood, both GitHub and GitLab resort to the git revert functionality. So, there’s nothing stopping you from using the same command.

Here’s a step-by-step guide of how you’d go about it:

Under the hood, both GitHub and GitLab resort to the git revert functionality. So, there’s nothing stopping you from using the same command.

Here’s a step-by-step guide of how you’d go about it:

  • The first step would be to create a branch off of main—or whatever your default branch is.
  • Then, you’d use git revert, passing the ID of the commit(s) you wish to revert.
    • If the merge was done via the squash or merge commit methods, the situation is easier. Just target the resulting merge commit or squashed commit.
    • However, if the merge was done using rebase, you’d have to target all of the individual commits, creating a reversed commit for each.
  • Finally, you’d have to create a pull request from your new branch to the default branch.
  • After the pull request is accepted, you would have effectively reverted the changes included in the original PR.

The Destructive Way: Git Reset

Git revert is a safe, non-destructive command. When you use it, you don’t rewrite past history. Instead, you create new commits whose changes are the opposite of the ones you’re trying to undo. The new commits and the old ones cancel out, and the changes no longer affect the repository.

However, you might have a legitimate reason to rewrite history on the default branch. If that’s the case, and you understand the risks and have the privileges to overwrite the default branch, you could simply do:

git reset --hard <ID-OF-LAST-GOOD-COMMIT>

Then, you’d just have to force push the change:

git push --force

I can’t stress this enough: only do the above if you’re really sure of what you’re doing. Rewriting public history is a bad practice and you can harm your coworkers. No one will be able to look at the history of the codebase and rely upon the commit messages to see how the codebase has changed over time. Doing a hard reset is a risky operation and you can lose commits—and a codebase’s true history—for good.

Standardize Your Pull Request Process

Generally speaking, reverting a pull request isn’t something you should do often. It is often necessitated by causes that could be avoided. LinearB’s goal-setting frameworks, metrics, and WorkerB automations can help your team successfully adopt a robust code review process that will enable you to consistently ship better code faster.

But it is nice to know that, if the need arises, reverting a pull request is quite easy to do. As you’ve seen, both GitHub and GitLab offer user-friendly ways to perform this operation, which, under the hood, rely on the git revert command.

Even if your favorite source code hosting service doesn’t offer an option to revert pull requests, you can always use the git revert command yourself. As a last possible resort, if you really know what you’re doing, you could also perform a hard reset to “get rid” of the offending commits.