Is there a way I can keep changes B and D, but skip C?
You're at state D. :w file.ext_D
Backtrack to state C. :w file_ext_C
Backtrack to state B. :w file.ext_B
:!kdiff3 file.ext_B file.ext_C file.ext_D
This gives a 3 way merge of the differences, but still you'd have to manually go in and choose every red line in D for each merge conflict. Not exactly an easy solution.
If instead you do
:!kdiff3 file.ext_C file.ext_B file.ext_D
Then the merge happens automatically (except for individual lines with multiple changes)
For more complicated scenarios it gets tougher.
Note: I'm not sure how a revision control tool is much help. You're basically doing something like creating a patch between B and D, and then subtracting the patch from C to D from it. It seems to me that revision control systems are usually designed to manage merges between different sources of changes, not changes along a single branch.
kdiff3 is available at: http://kdiff3.sourceforge.net/