I see three options: return merge, reload, or filter.
Rollback
The “right” solution, as others say, is to get the merge back - which means that you are not “rewriting the story”, which is usually considered a good thing, not least because it means that everyone else working on this code will not need to change history.
You cannot just use git revert as-is, however, because it does not know which branch of the history to keep. The solution is to simply provide Git with an extra bit of information:
git revert -m 2 <sha-of-B>
That -m 2 indicates that you want to keep the second parent, i.e. the one that contains commit C; switch to -m 1 for an alternative.
One warning: if you want to merge this other branch into your main branch, you will run into a problem due to Git, believing that the branch is already in the main branch. There are several solutions for this, but the easiest (IMO) is to return the edge to the branch from the master and, as well as merge it into master, merge it into another branch. This branch is likely to be similar to any version of the master that it forks, and at that moment you can return the reverse, and everything will be fine when you merged in the future.
relocation
Rebasing is probably the easiest option: git rebase <sha-of-B> master --onto <sha-of-C> .
This will move all the commits from B until master on C. It will catch that it “linearizes” the merge history. The story of merging in an image is very simple, but it can be a problem if you want to keep the story or if you do it in a more complex repository.
It also has a catch that it “rewrites history” and everyone who uses this repository will find that they work with a completely different branch of code in the one that was returned, since each change from C will have a different sha1 hash.
Filtration
Using git filter-branch will allow you to get exactly what you are looking for in your image, that is, save the merge history, but this is the most difficult option and still includes rewriting history.
Effectively, you want to use git filter-branch to filter your commits in order to save everything but a single duff merge. This is complicated enough; I am not going to write instructions; you need to combine --commit-filter to remove the abusive merge and --tree-filter to discard the merge changes.
Contraction filtering
Well, here is the fourth method that I include for completeness. You could just check C, and then manually cherry-pick and merge each of the changes you want to have in your main branch one by one.
Further reading