merge: handle renames with replacement content
We generally think of a rename as removing one path entirely
and placing similar content at a new path. In other words,
after a rename, the original path is now empty. But that is
not necessarily the case with rewrite detection (which is
not currently possible to do for merge-recursive).
The current merge code blindly removes paths that are used
as rename sources; however, we should check to see if there
is useful content at that path. There are basically two
interesting cases:
1. One side renames a path, but also puts new content
(or a symlink) at the same path. We want to detect the
rename, and have changes from the other side applied to
the rename destination. The new content at the original
path should be left untouched.
The current code just calls remove_file, but that
ignores the concept that the renaming side may put
something else useful there. We should detect this case
and either remove (if no new content), or put the new
content in place at the original path.
2. Both sides renamed and installed new content at the
original path. If they didn't rename to the same
destination, it is a conflict, and we already mark it
as such. But if it's the same destination, then it's
not a conflict; the renamed content will be merged at
the new destination.
For the new content at the original path, we have to do
a 3-way merge. The base must be the null sha1, because
this "slot" for content didn't exist before (it was
taken up by the content which got renamed away). So if
only one side installed new content, that content
automatically wins. If both sides did, and it is the
same content, then that content is OK. But if the
content is different, then we have a conflict and
should do the usual conflict-markers thing.
This patch implements the semantics described above, which
lays the groundwork for turning on rewrite detection.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>