From: Jeff King <peff@peff.net>
To: Jay Soffian <jaysoffian@gmail.com>
Cc: git <git@vger.kernel.org>
Subject: Re: merge recursive and code movement
Date: Fri, 25 Mar 2011 07:12:25 -0400 [thread overview]
Message-ID: <20110325111225.GC9047@sigill.intra.peff.net> (raw)
In-Reply-To: <20110325101204.GB9047@sigill.intra.peff.net>
On Fri, Mar 25, 2011 at 06:12:04AM -0400, Jeff King wrote:
> 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
next prev parent reply other threads:[~2011-03-25 11:14 UTC|newest]
Thread overview: 14+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-03-24 21:18 merge recursive and code movement Jay Soffian
2011-03-25 9:37 ` Jeff King
2011-03-25 10:12 ` Jeff King
2011-03-25 11:12 ` Jeff King [this message]
2011-03-25 16:00 ` Jeff King
2011-03-25 16:03 ` [PATCH 1/3] t3030: fix accidental success in symlink rename Jeff King
2011-03-25 17:42 ` Junio C Hamano
2011-03-25 17:51 ` Jeff King
2011-03-25 18:25 ` Schalk, Ken
2011-03-25 16:06 ` [PATCH 2/3] merge: handle renames with replacement content Jeff King
2011-03-25 16:08 ` [PATCH 3/3] merge: turn on rewrite detection Jeff King
2011-03-25 17:32 ` merge recursive and code movement Jay Soffian
2012-07-16 0:17 ` Techlive Zheng
2012-07-16 12:26 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110325111225.GC9047@sigill.intra.peff.net \
--to=peff@peff.net \
--cc=git@vger.kernel.org \
--cc=jaysoffian@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).