git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: merge recursive and code movement

From
Jeff King <peff@peff.net>
Date
Mar 25, 2011, 11:12 UTC
Message-ID
<20110325111225.GC9047@sigill.intra.peff.net>
In-Reply-To
<20110325101204.GB9047@sigill.intra.peff.net>
On Fri, Mar 25, 2011 at 06:12:04AM -0400, Jeff King wrote:
Show 11 quoted lines
> Ah, found it. In process_renames, we explicitly call remove_file() on
> the source, which is assuming the rename did not come from a broken
> pair. What we actually want to do, I think, is to just take the changes
> from the renaming side literally. There's no point in doing a 3-way
> merge because the other side's changes will end up applied to the rename
> destination.  It just happens that without break_opt, the renaming sides
> change is _always_ a deletion, or else it would not have been a rename
> candidate. So the current code is a special case for that rule.
> 
> Now, as far as how to do that, I haven't a clue. I've been staring at
> merge-recursive code for 30 minutes. ;)
So this is what I ended up with:
diff --git a/merge-recursive.c b/merge-recursive.c
index 8e82a8b..af42530 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -426,6 +426,7 @@ static struct string_list *get_renames(struct merge_options *o,
 			    1000;
 	opts.rename_score = o->rename_score;
 	opts.show_rename_progress = o->show_rename_progress;
+	opts.break_opt = 0;
 	opts.output_format = DIFF_FORMAT_NO_OUTPUT;
 	if (diff_setup_done(&opts) < 0)
 		die("diff setup failed");
@@ -706,6 +707,17 @@ static void update_file(struct merge_options *o,
 	update_file_flags(o, sha, mode, path, o->call_depth || clean, !o->call_depth);
 }
 
+static int update_or_remove(struct merge_options *o,
+			    const unsigned char *sha1, unsigned mode,
+			    const char *path, int update_wd)
+{
+	if (is_null_sha1(sha1))
+		return remove_file(o, 1, path, !update_wd);
+
+	update_file_flags(o, sha1, mode, path, 1, update_wd);
+	return 0;
+}
+
 /* Low level file merging, update and removal */
 
 struct merge_file_info {
@@ -1049,7 +1061,10 @@ static int process_renames(struct merge_options *o,
 			int renamed_stage = a_renames == renames1 ? 2 : 3;
 			int other_stage =   a_renames == renames1 ? 3 : 2;
 
-			remove_file(o, 1, ren1_src, o->call_depth || renamed_stage == 2);
+			update_or_remove(o,
+				ren1->src_entry->stages[renamed_stage].sha,
+				ren1->src_entry->stages[renamed_stage].mode,
+				ren1_src, renamed_stage == 3);
 
 			hashcpy(src_other.sha1, ren1->src_entry->stages[other_stage].sha);
 			src_other.mode = ren1->src_entry->stages[other_stage].mode;

It passes my test, and it doesn't break anything in t/. Yay.

There's one other call to remove_file in process_renames. It's for the
case that both sides renamed the same file to the same destination.  I
think there we need to actually compare the two sides. If only one side
still has something at the source path, then we can take that side
(since the other side renamed away the file). But if they both have it
(i.e., they both installed a replacement), then we need to do the usual
3-way merge on that replacement. I'm not sure if we'd have to do that
ourselves, or if we can just punt and the rest of the merge machinery
will handle the entry. I'll have to write some tests, I think.

-Peff
Previous: Jeff KingNext: Jeff King
Message 4 of 14 in “merge recursive and code movement”
  1. Jay SoffianMar 24, 2011
  2. Jeff KingMar 25, 2011
  3. Jeff KingMar 25, 2011
  4. Jeff KingMar 25, 2011
  5. Jeff KingMar 25, 2011
  6. 1/3 t3030: fix accidental success in symlink renameJeff King, Mar 25, 2011
  7. Junio C HamanoMar 25, 2011
  8. Jeff KingMar 25, 2011
  9. Schalk, KenMar 25, 2011
  10. 2/3 merge: handle renames with replacement contentJeff King, Mar 25, 2011
  11. 3/3 merge: turn on rewrite detectionJeff King, Mar 25, 2011
  12. Jay SoffianMar 25, 2011
  13. Techlive ZhengJul 16, 2012
  14. Jeff KingJul 16, 2012

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.