My first question is the case (0, 0, 1)
Some version control systems like darcs consider that doing the same change (in your case, deletion) in two branches and merging them should lead to a conflict. The typical example is when you have twice
-#define NUMBER_OF_WHATEVER 42
+#define NUMBER_OF_WHATEVER 43
The merge algorithm cannot know for you whether you want the merge to yield 43 (because this is the value both versions agree on) or 44 (because 42 should be incremented twice).
However, considering this case as a conflict causes a lot of spurious conflicts. For example, if one cherry-picks a merge from the master branch to a maintainance branch and later merges the maintainance branch into master, then each line modified by the cherry-pick would lead to a conflict. And the conflict markers would be weird, because they would show the same content on both sides of the conflict marker, like
<<<<<<< HEAD
Hello world
=======
Hello world
>>>>>>> 77976da35a11db4580b80ae27e8d65caf5208086
So, most version-control systems, including Git, chose to consider no conflict when both sides of the merge introduce the same change.
My second question is about deletion cases— (0, 1, 1) and (1, 0, 1).
What you are describing is semantic conflicts. They do exist in theory, and you can even find corner-cases where the merge is compilable but has different semantics compared to the branches being merged. There's no magic, no textual merge algorithm can detect or resolve semantic conflicts. You have to live with them, or work alone.
In practice, they are rare enough. There are probably millions of people using a version control system daily and living with it. The majority probably never thought the problem could exist.
Still, a good organization considerably reduces the risk of semantic conflicts. If you check that your code still compiles after merges, you avoid ~90% of semantic conflicts, and if you have an automatic testsuite, then you'd have to find a semantic conflicts that creates a bug not covered by your testsuite for it to be problematic.
And actually, semantic conflicts are not specific to version-control systems. Another scenario not using merge is
- I read the code and see a function
f()
- My coworker removes function
f()
- Working on the latest version, which doesn't have
f()
anymore, I still remember that there's a function f()
and I try to use it.
In short, don't be afraid of semantic conflicts.