git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Junio C Hamano <gitster@pobox.com>
To: Daniel Barkalow <barkalow@iabervon.org>
Cc: Stephan Beyer <s-beyer@gmx.net>,
	Miklos Vajna <vmiklos@frugalware.org>,
	git@vger.kernel.org
Subject: Re: [PATCH (1b)] merge-recursive.c: Add more generic merge_recursive_generic()
Date: Wed, 13 Aug 2008 14:45:22 -0700	[thread overview]
Message-ID: <7vljz0lhcd.fsf@gitster.siamese.dyndns.org> (raw)
In-Reply-To: <alpine.LNX.1.00.0808131559060.19665@iabervon.org> (Daniel Barkalow's message of "Wed, 13 Aug 2008 16:36:36 -0400 (EDT)")

Daniel Barkalow <barkalow@iabervon.org> writes:

> Maybe merge_trees should get the two sides as structs with a struct tree * 
> and a char * branch name, and the struct could someday get optional struct 
> commit *s for the lineage of the side if somebody comes up with a method 
> for merging that makes use of the component changes.

I do agree with you that with some ancestry-based hinting the "find
renames" part of merge_trees() postprocessing can do a better job than the
current code.  Contrary to a widespread misconception we often hear on
this list and on #git, merge-recursive detects renames solely by looking
at the three endpoints.  Some people incorrectly recommend "commit a pure
rename, then commit modifications to the renamed path"; such an artificial
split would not at all help merging histories with renames if the
modification made after renames are too great.

Suppose you have this history, where upper branch renames a path and
modifies the contents in the renamed path in commits X, Y and Z.  You
would want to merge the history leading to B to your HEAD, A, to create a
merge M:

            X---Y---Z---B              X---Y---Z---B  
           /                ===>      /             \
       ---O---o---o---A           ---O---o---o---A---M    

Maybe the rename done between O and X were pure enough that "diff-tree -M
O X" would have found it, but commits Y, Z, or B changed the contents of
the renamed path too greatly for "diff-tree -M O B" to notice the rename
anymore.  "git merge B" when you are at A will not find such a rename, but
if we allowed rename detection stepwise to look at "diff-tree -M" for
(O,X), (X,Y), (Y,Z), (Z,B), (and the same for history between O and A), we
might be able to find renames better [*1*].

Suppose instead of merging the whole history leading to B, you would want
to apply the small fix made with Y on top of A:

            X---Y---Z---B              X---Y---Z---B   
           /                ===>      /                
       ---O---o---o---A           ---O---o---o---A---Y'

You would "checkout A && cherry-pick Y" which amounts to three-way merge
using X as "common", A as "mine" and Y as "his", which is the moral
equivalent of:

	read-tree -m -u X A Y

but with rename detection.  merge_trees(A, Y, X) could traverse ancestry
between X and A to find O and figure out where in A the paths that are
affected in diff(X,Y) appear by making pairwise "diff-tree -M" to go from
X back to O and then forward to A to find out that where the paths touched
by Y were originally in O and where they are in A.

But you are assuming that "common" and "ours" have any ancestry
relationship.  You generally cannot.

The most extreme case is "am -3" where both "common" and "theirs" are pure
trees without any ancestry relationship to anything else.  They are built
by looking at the "index" lines contained in the patch and contain only
those paths that are affected by the patch, and the merge machinery merges
that change into arbitrary "ours".

You can cherry-pick a change C from history that does not have any common
ancestor with your history leading to "ours" ("common"=C^ and "theirs"=C
in this case), and the same applies to revert of C ("common"=C and
"theirs"=C^).  "rebase --onto A C^ C" works the same way.

So this "extra ancestry information to help rename discovery" can at most
be a hint.

More importantly, all of the above does not have anything to do with the
"recursiveness" of merge-recursive (which is the difference between
merge_trees() and merge_recursive()) at all.  So I am still correct to say
that "cherry-pick", "revert", "checkout -m", "am -3" and "stash apply"
should use the merge_trees() interface, not the recursive one.

[Footnote]

*1* But that would be quite more expensive than what we currently do, and
it only deals with an uninteresting special case of wholesale file rename.

I suspect if we ever do the stepwise thing, we would be better off doing
not "diff-tree -M" but "blame -C" to really find where the lines affected
between O and B ended up in A, and apply the change there.

  reply	other threads:[~2008-08-13 21:46 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-08-10 13:20 [PATCH 0/2] Avoid run_command() for recursive in builtin-merge Miklos Vajna
2008-08-10 13:20 ` [PATCH 1/2] merge-recursive: prepare merge_recursive() to be called from builtins Miklos Vajna
2008-08-10 13:20   ` [PATCH 2/2] builtin-merge: avoid run_command_v_opt() for recursive Miklos Vajna
2008-08-11 18:47     ` Junio C Hamano
2008-08-11 19:07       ` Miklos Vajna
2008-08-11 20:03         ` Junio C Hamano
2008-08-11 20:45           ` Miklos Vajna
2008-08-11 20:48             ` [PATCH] Add a new test to ensure merging a submodule is handled properly Miklos Vajna
2008-08-11 15:13   ` [PATCH 1/2] merge-recursive: prepare merge_recursive() to be called from builtins Stephan Beyer
2008-08-11 16:46     ` Miklos Vajna
2008-08-11 19:53     ` Junio C Hamano
2008-08-11 20:46       ` Stephan Beyer
2008-08-11 15:03 ` [PATCH] builtin-revert.c: Make use of merge_recursive() Stephan Beyer
2008-08-11 15:47   ` Johannes Schindelin
2008-08-11 19:01     ` Stephan Beyer
2008-08-11 19:09       ` Miklos Vajna
2008-08-11 21:44         ` [PATCH] builtin-revert: " Stephan Beyer
2008-08-11 21:46           ` Stephan Beyer
2008-08-11 22:33             ` Junio C Hamano
2008-08-11 23:27           ` Junio C Hamano
2008-08-11 23:47             ` Stephan Beyer
2008-08-11 23:52               ` Junio C Hamano
2008-08-12 16:45             ` [PATCH] Split out merge_recursive() to merge-recursive.c Miklos Vajna
2008-08-12 17:56               ` Stephan Beyer
2008-08-12 21:40                 ` Miklos Vajna
2008-08-12 20:13               ` [PATCH (1b)] merge-recursive.c: Add more generic merge_recursive_generic() Stephan Beyer
2008-08-12 20:14                 ` [PATCH (2)] Make builtin-revert.c use merge_recursive_generic() Stephan Beyer
2008-08-12 21:44                 ` [PATCH (1b)] merge-recursive.c: Add more generic merge_recursive_generic() Miklos Vajna
2008-08-13 17:26                   ` Stephan Beyer
2008-08-13 20:13                     ` Miklos Vajna
2008-08-13  3:17                 ` Daniel Barkalow
2008-08-13 17:29                   ` Stephan Beyer
2008-08-13 17:54                     ` Daniel Barkalow
2008-08-13 19:55                       ` Junio C Hamano
2008-08-13 20:05                         ` Stephan Beyer
2008-08-13 20:36                         ` Daniel Barkalow
2008-08-13 21:45                           ` Junio C Hamano [this message]
2008-08-14  3:17               ` [PATCH] Split out merge_recursive() to merge-recursive.c Junio C Hamano

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=7vljz0lhcd.fsf@gitster.siamese.dyndns.org \
    --to=gitster@pobox.com \
    --cc=barkalow@iabervon.org \
    --cc=git@vger.kernel.org \
    --cc=s-beyer@gmx.net \
    --cc=vmiklos@frugalware.org \
    /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).