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:
Only known good changes make it into the mainline.
Developers only pull/clone from mainline, thus they never base their work on bad changes.
New changes are merged, built, and tested in isolation from everything else and are verified good before being merged into the mainline.