How to undo a merge

Tuesday, July 08, 2014 6 Comments

Reasons to undo a merge

There’s no software free of bugs which means you’ll deal, sooner or later, with a branch that introduces a bug.

Hopefully your automatic test suite will detect it. Otherwise an unhappy customer will do it for you. In either case you will need to revert a merge to remove the functionality that is causing the issue and then you’ll have make the release stable again.

There’s also another reason to undo a merge that doesn’t mean you’ve a nasty bug: sometimes you simply need to remove a task branch because the team changed their mind and decided to postpone it to a future release.

How to undo a merge (subtract a merge) with Plastic

Plastic SCM provides an easy way to revert a merge operation while keeping the code history. We call it “subtractive merge” and it is way much easier than it sounds.

I’ll explain how it works with an example. Consider the following scenario displayed in the image below: I've just merged the “/main/issue32” and the “/main/issue33” task branches into the “/main/Release_500” integration branch.

We strongly recommend you run your testsuite (at least part of it depending on how fast it is) after each task branch is merged. This way you can check that everything still works once merged together.

Sadly it wasn’t that easy with the “issue32” branch; this branch introduced an issue that only showed up when it was combined with the branch “issue33”.

Now that we know where the issue is coming from, we need to move forward with the release. The whole “main/Release_500 branch” is affected by the issue so we need to take “issue32” out of release being built.

In order to do that we will subtract changeset 178, the one introducing the changes of “issue32” into the “Release_500” branch.

A subtractive merge from the changeset #178 does the job (red merge link), returning the branch to a stable status.

The changeset #180 is now ready to be integrated into the “/main” branch in order to generate a new release.

Merging back from a branch that has been subtracted

Sometimes the release can’t continue once the faulty bugfix has been removed. Sometimes we can proceed with the release and simply merge the “reopened” task later on.

In both cases we’ll need to merge “issue32” again.

The developer continued working on “issue32” and created a new changeset to solve the problem.

Once the “issue32” task branch is ready again to be reintegrated you will need to perform the following actions:

  • Cherry-pick (ignoring traceability) the subtracted changeset (purple merge link).
  • Merge from the task branch again (green merge link).

You’ll need the cherry-pick operation to bring back all the changes removed by the subtractive merge and then the second merge from the “issue32” branch will work as the antidote of the issue. The cherry-pick has to ignore the traceability due the source and destination changesets are already connected so a regular cherry-pick will find nothing.

Finally the release branch is fully tested and it needs to be merged into “main” to label the new “BL500” release.


Steps summary

  • Subtractive merge from the failing changeset or branch.
  • That will remove the feature or bug from the destination branch. If you also want to later re-integrate the branch you will need to:

    • Cherry-pick (ignoring traceability) from the changeset of branch subtracted
    • Merge the source task branch again to get the latest changes

    Here you have a gif summarizing all the steps together:


    1. Very informative article. However, I wish you would explain why you would want to use subtractive merges over "Delete changeset" and the side effects that can cause. Also, can you explain what "Cherry-pick (ignoring traceability)" means?

    2. I'm also curious of why we would not want to just delete the faulty changesets?

    3. In this scenario after the "faulty" changeset you have done several checkins. So you can't simply remove the cset because even if you could do it (which you can't) the change will be included in the next csets.

      Subtractive is the way to get this done right :-)

    4. Why not do subtractive merge of 180, undoing the undo without needing to do a baseless cherry-pick. This would avoid having to redo any conflict resolution done in the first subtractive merge.

      Either way, your branch history now shows:
      Add issue32
      Add issue33
      Back out buggy issue32
      Re-add buggy issue32
      Merge fix for issue32

      It'd be nicer if those last two commits could be handled as one commit, "Re-add fixed issue32".

    5. Any comment on TBBle's suggestions? Would a subtractive from 180 work equally well? Also, I suppose you _could_ do the last two merges in one checkin...