Who we are

We are the developers of Plastic SCM, a full version control stack (not a Git variant). We work on the strongest branching and merging you can find, and a core that doesn't cringe with huge binaries and repos. We also develop the GUIs, mergetools and everything needed to give you the full version control stack.

If you want to give it a try, download it from here.

We also code SemanticMerge, and the gmaster Git client.

How to undo a merge

Tuesday, July 08, 2014 Ma Nu 9 Comments

UPDATE January 14, 2020: Learn more about subtractive merges in the Plastic Book or in the Advanced version control pocket guide.

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:

    Manuel Lucio
    I'm in charge of the Customer Support area.
    I deal with complex setups, policies and working methodologies on a daily basis.
    Prior to taking full responsibility of support, I worked as software engineer. I have been in charge of load testing for quite some time, so if you want to know how well Plastic compares to SVN or P4 under a really heavy load, I'm your guy.
    I like to play with Arduino GPS devices, mountain biking and playing tennis.
    You can find me hooked to my iPhone, skate-boarding or learning Korean... and also here @mrcatacroquer.


    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...

      1. Yes, you can Cherrypick from 180 and then merge from 181. It's going to be the same.

    6. Cherry picking from the faulty branch seems not to work like expected in Plastic SCM Version

      I have a situation, where I had to subtractive merge a changeset interval, because the outcome had a bad performance. (It was not a bug, by the way.)
      But there were also some good changesets within the "bad" branch. So I tried to cherry pick only the "good" changeset, the cherry pick tab opened correctly, but it says "0 items to merge".

      It seems to me, that Plastic SCM thinks internally, I want to merge the changeset instead of cherry picking it. (As far as I know, the cherry pick operation should not care about any merging history. It should simply take the changes and merge these with the current workspace.)

      Could this be a bug?

      1. Are you selecting the "Ignore traceability" option for the cherry pick operation? Otherwise Plastic will see there's a path from the changeset to the destination and will conclude the merge is not needed (0 items to merge).