Researching distributed source control management (specifically mercurial). My question is more or less what is the best practice for rejecting entire sets of code that fail testing?


A team is working on a hello world program. They have testers and a scheduled release coming up with specific features planned.

Upcoming Release:
   Add feature A
   Add feature B
   Add feature C

So, the developers make their clones for their features, do the work and merge them into a QA repo for the testers to scrutinize.

Let's say the testers report back that "Feature B is incomplete and in fact dangerous", and they would like to retest A and C.

Repo Doodle

End example.

What's the best way to do all this so that feature B can easily be removed and you end up with a new repo that contains only feature A and C merged together?

Recreate the test repo? Back out B? Other magic?

  • 2
    The real solution is to never allow multiple features to be merged without having them independently tested first.
    – James
    Jun 12, 2012 at 17:13
  • To the OP: you're clearly on this site reasonably regularly. Is there any reason why you seem to ask questions but accept no answers? It's usually good practice on these sites to reward good answers with feedback in recognition for the time they've invested in your question. You've got a few very good answers below... (nudge nudge) Sep 16, 2012 at 22:05
  • @AKE Because I feel my questions are subjective enough to not warrant any one answer to be above the rest or because I haven't found an answer suitable enough. It's just been coincidence on Programmers that all my asked questions have been one of the two. On other stack exchange sites I accept many answers. Sep 25, 2012 at 19:02

3 Answers 3


The key here is to come up with a workflow that avoids the situation where "bad" code is ever exposed to developers or teams other than those who created it. If this were to occur, good code would be mixed with bad, and "unmerging" or detangling them will be difficult. So, prevent this from happening in the first place.

I'm assuming that HelloWorld in this example is the mainline repository, that contains known good code. Developers A, B, and C all clone from this repo and develop their changes against it. In the model I'm describing, HelloWorld-test is a transient repo solely used by QA to test merged changes before moving them into the mainline. Developers never look at HelloWorld-test. Here's how it works.

  • A, B, and C all clone good code from mainline (HelloWorld).

  • A makes changes and tells QA she's ready (or A pushes her changes to a staging repo). QA clones mainline and pulls and merges A's changes, and then builds and tests. Assuming this is all successful, QA then merges these changes into the mainline.

  • B now makes his changes available. QA clones mainline and then pulls and merges B's changes into HelloWorld-test. Continuing with your example, let's say these changes are bad. So QA's merge fails, or the build fails, or the tests fail, or something. At this point QA declares the changes to be bad, notifies B, and simply throws away HelloWorld-test. It's now B's responsibility to pull and merge from mainline, fix test failures, or whatever.

  • QA can then perform the process with C, starting from a fresh clone of mainline, and merging in C's changes. Note that B's bad changes have never reached the mainline and so C's changes (or anybody else's) will never be mixed with them.

  • At some point B has fixed up his changes and asks QA to do another pull/merge/build/test. QA can do this next, or they can just go around the cycle of different developers or teams until they come back to B.

This is often called a "pull model" of development. I believe Linux kernel changes are managed this way.

In many cases it's not "QA" who does the pull/merge/build/test cycle, but instead it's done by a continuous integration system such as Hudson or Jenkins.

Of course, there are many variations of this, whether individual developers or teams have staging repos, whether changes are propagated via pushing or pulling, etc. But they should all share these key characteristics:

  1. Only known good changes make it into the mainline.

  2. Developers only pull/clone from mainline, thus they never base their work on bad changes.

  3. New changes are merged, built, and tested in isolation from everything else and are verified good before being merged into the mainline.

  • (+1) very clear description -- and very helpful. Thanks for this! (It's a pity the OP hasn't returned to officially review the responses.) Sep 16, 2012 at 22:00

You can use patch queues to cherry-pick stuff coming in, or you could just use hg backout to remove the changes of just a changeset (see the hg book and look for "hg backout" here).

The difference is that patch queues will allow B from never appearing in the history.

OTOH, you might be better off by encouraging "feature branches" for both features and bug fixes, then select what branches to integrate to the baseline.


Your best bet is to have the coded tested before it's committed. Backing out B is your best bet, if you can't do that.

Backing out changeset is the process of applying the inverse patch of that changeset. By extension, you can backout a range of changesets by applying the inverse of patch of all the changesets. This should be the default methodology of "reverting" a change or set of changes as it will maintain the consistency and completeness of the repository.

hg pull
hg up # Now your working directory and local repo are up to date
hg up -r revLast # Update to the latest revision you want to backout
hg revert -a -r revFirst-1 # Creates an inverse patch of revFirst to revLast
hg ci -m "Backed out revFirst - revLast" # Commit inverse patch
hg merge # Merge inverse patch to tip in my working directory
hg ci -m "Merged change back into the tip" # Commit inverse patch to tip in local repo
hg push # Push to master
  • This seems ok if you know the feature is going away completely. If that's not true though, you may have problems: the backout looks like "i don't want this anymore" -- so if you go back to the original feature branch and fix the problems and then re-merge, you run a high risk of a bad merge because the backout looks like a "delete" that occurred after the original "add" in the feature. Jun 12, 2012 at 19:21
  • They can always apply the inverse of the delete and their fix. It just requires a little more due diligence in dealing with the repository and merges. However, the best bet is to have the merged code tested before it's committed.
    – snakehiss
    Jun 12, 2012 at 23:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.