* [PATCH 0/2] Improve P4Merge mergetool invocation @ 2013-03-06 20:32 Kevin Bracey 2013-03-06 20:32 ` [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool Kevin Bracey ` (3 more replies) 0 siblings, 4 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-06 20:32 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon Two changes to the same piece of code that have greatly improved the behaviour of P4Merge for me. Some of it may also be applicable to other mergetools. I've put probably overly-long-winded explanations in the commit messages. Comments welcome. In particular, I know almost nothing of sh, so I may have made some blunder there. Kevin Bracey (2): p4merge: swap LOCAL and REMOTE for mergetool p4merge: create a virtual base if none available git-mergetool--lib.sh | 14 ++++++++++++++ mergetools/p4merge | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) -- 1.8.2.rc2.5.g1a80410.dirty ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-06 20:32 [PATCH 0/2] Improve P4Merge mergetool invocation Kevin Bracey @ 2013-03-06 20:32 ` Kevin Bracey 2013-03-07 0:36 ` Junio C Hamano 2013-03-06 20:32 ` [PATCH 2/2] p4merge: create a virtual base if none available Kevin Bracey ` (2 subsequent siblings) 3 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-06 20:32 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that the incoming branch is now in the left-hand, blue triangle pane, and the current branch is in the right-hand, green circle pane. This change makes use of P4Merge consistent with its built-in help, its reference documentation, and Perforce itself. But most importantly, it makes merge results clearer. P4Merge is not totally symmetrical between left and right; despite changing a few text labels from "theirs/ours" to "left/right" when invoked manually, it still retains its original Perforce "theirs/ours" viewpoint. Most obviously, in the result pane P4Merge shows changes that are common to both branches in green. This is on the basis of the current branch being green, as it is when invoked from Perforce; it means that lines in the result are blue if and only if they are being changed by the merge, making the resulting diff clearer. Whereas if you use blue as the current branch, then there is no single colour highlighting changes - a green line in the result could be a change, but it could also be something already in the current branch that isn't changed by the merge. There is no need to swap LOCAL/REMOTE order for difftool; P4Merge is symmetrical in this case, and a 0- or 1-revision difftool invocation already gives the working tree ("ours") on the right in green, matching Perforce's equivalent "Diff Against Have Revision". And you couldn't swap it anyway, as it would make 2-revision difftool invocation back-to-front. Note that P4Merge now shows "ours" on the right for both diff and merge, unlike other diff/mergetools, which always have REMOTE on the right. But observe that REMOTE is the working tree (ie "ours") for a diff, while it's another branch (ie "theirs") for a merge. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- mergetools/p4merge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mergetools/p4merge b/mergetools/p4merge index 8a36916..46b3a5a 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -22,7 +22,7 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" $base_present || >"$BASE" - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc2.5.g1a80410.dirty ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-06 20:32 ` [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool Kevin Bracey @ 2013-03-07 0:36 ` Junio C Hamano 2013-03-07 6:16 ` Kevin Bracey 0 siblings, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-07 0:36 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon Kevin Bracey <kevin@bracey.fi> writes: > Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that > the incoming branch is now in the left-hand, blue triangle pane, and the > current branch is in the right-hand, green circle pane. Given that the ordering of the three variants has been the way it is since the very initial version by Scott, I'll sit on this patch until hearing from those Cc'ed (who presumably do use p4merge, unlike I who don't) that it is a good change. Thanks. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 0:36 ` Junio C Hamano @ 2013-03-07 6:16 ` Kevin Bracey 2013-03-07 7:23 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-07 6:16 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, David Aguilar, Ciaran Jessup, Scott Chacon On 07/03/2013 02:36, Junio C Hamano wrote: > Kevin Bracey <kevin@bracey.fi> writes: > >> Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that >> the incoming branch is now in the left-hand, blue triangle pane, and the >> current branch is in the right-hand, green circle pane. > Given that the ordering of the three variants has been the way it is > since the very initial version by Scott, I'll sit on this patch > until hearing from those Cc'ed (who presumably do use p4merge, > unlike I who don't) that it is a good change. > I agree that this is the controversial patch of the two. It's going to chuck away 3-4 years of what Git users are used to, albeit in favour of a decade of what Perforce users are used to. And it also makes it inconsistent with all the other mergetools (at least assuming their display matches their command line). I checked for any historical discussion from when this was added about the order, and there was none. So I'm assuming it was just done to match the other tools, maybe not realising P4Merge's "theirs/ours" convention. There was no explicit recognition at the time that they were breaking the Perforce convention, or that the order had an effect. I've used both Git and Perforce for quite a while, but have only just started using P4Merge with Git. It seemed weirdly off and unintuitive to me at first, until I suddenly realised that it was just backwards. I would have settled for just having to get used to driving on the other side of the road, and matching other mergetools, until I realised that it effectively broke display of common changes. That's a problem. On consistency, personally, I think there's an argument for reversing all the mergetools to match this way, as I find this orientation more intuitively aligns with difftool. But I'm not bold enough to suggest that. Yet. Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 6:16 ` Kevin Bracey @ 2013-03-07 7:23 ` Junio C Hamano 2013-03-07 17:14 ` Kevin Bracey 0 siblings, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-07 7:23 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon Kevin Bracey <kevin@bracey.fi> writes: > I agree that this is the controversial patch of the two. It's going to > chuck away 3-4 years of what Git users are used to, albeit in favour > of a decade of what Perforce users are used to. And it also makes it > inconsistent with all the other mergetools (at least assuming their > display matches their command line). If p4merge GUI labels one side clearly as "theirs" and the other "ours", and the way we feed the inputs to it makes the side that is actually "ours" appear in p4merge GUI labelled as "theirs", then I do not think backward compatibility argument does not hold water. It is just correcting a longstanding 3-4 year old bug in a tool that nobody noticed. For people who are very used to the way p4merge shows the merged contents by theirs-base-yours order in side-by-side view, I do not think it is unreasonable to introduce the "mergetool.$name.reverse" configuration variable and teach the mergetool frontend to pay attention to it. That will allow them to see their merge in reverse order even when they are using a backend other than p4merge. With such a mechanism in place, by default, we can just declare that mergetool.p4merge.reverse is "true" when unset, while making mergetool.$name.reverse for all the other tools default to "false". People who are already used to the way our p4merge integration works can set mergetool.p4merge.reverse to "false" explicitly to retain the historical behaviour that you are declaring "buggy" with such a change. How does that sound? David? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 7:23 ` Junio C Hamano @ 2013-03-07 17:14 ` Kevin Bracey 2013-03-07 19:10 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-07 17:14 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, David Aguilar, Ciaran Jessup, Scott Chacon On 07/03/2013 09:23, Junio C Hamano wrote: > If p4merge GUI labels one side clearly as "theirs" and the other > "ours", and the way we feed the inputs to it makes the side that is > actually "ours" appear in p4merge GUI labelled as "theirs", then I do > not think backward compatibility argument does not hold water. It is > just correcting a longstanding 3-4 year old bug in a tool that nobody > noticed. It's not quite that clear-cut. Some years ago, and before p4merge was added as a Git mergetool, P4Merge was changed so its main GUI text says "left" and "right" instead of "theirs" and "ours" when invoked manually. But it appears that's as far as they went. It doesn't seem any of its asymmetric diff display logic was changed; it works better with ours on the right, and the built-in help all remains written on the theirs/ours basis. And even little details like the icons imply it (a square for the base, a downward-pointing triangle for their incoming stuff, and a circle for the version we hold). > For people who are very used to the way p4merge shows the merged > contents by theirs-base-yours order in side-by-side view, I do not > think it is unreasonable to introduce the "mergetool.$name.reverse" > configuration variable and teach the mergetool frontend to pay > attention to it. That will allow them to see their merge in reverse > order even when they are using a backend other than p4merge. > > With such a mechanism in place, by default, we can just declare that > mergetool.p4merge.reverse is "true" when unset, while making > mergetool.$name.reverse for all the other tools default to "false". > People who are already used to the way our p4merge integration works > can set mergetool.p4merge.reverse to "false" explicitly to retain > the historical behaviour that you are declaring "buggy" with such a > change. I like this idea as a user - having made this change to p4merge, it does throw me when I decide to attempt a particularly tricky merge with bc3 instead, and get the other order. The user config options you suggest sound good to me. For completion on this idea, I'd suggest difftool.xxx.reverse, to allow the orientation for 0- and 1-revision diffs to be chosen - allow the implied working tree version to be on the left or right. That would allow "ours-theirs" order, which some would view as being more consistent with the "ours-base-theirs" default for mergetool. Would it be going too far to also have "xxxtool.reverse" to choose the global default? Then the choice hierarchy would be "xxxtool.xxx.reverse if set" > "optional inbuilt tool preference" > "xxxtool.reverse if set" > "false". So the user could request a global swap, except that they'd have to explicitly override any tools that have a preferred orientation. My only reservation is that I assume it would be implemented by swapping what's passed in $LOCAL and $REMOTE. Which seems a bit icky: $LOCAL="a.REMOTE.1234.c". On the other hand, $LOCAL and $REMOTE are already not very meaningful names for difftool... Maybe we should change to using $LEFT and $RIGHT, acknowledging the existing difftool situation, and that the user can now swap merges too. I'd be happy to prepare a fuller patch on this sort of basis. Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 17:14 ` Kevin Bracey @ 2013-03-07 19:10 ` Junio C Hamano 2013-03-07 19:50 ` David Aguilar 0 siblings, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-07 19:10 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon Kevin Bracey <kevin@bracey.fi> writes: > On 07/03/2013 09:23, Junio C Hamano wrote: >> If p4merge GUI labels one side clearly as "theirs" and the other >> "ours", and the way we feed the inputs to it makes the side that is >> actually "ours" appear in p4merge GUI labelled as "theirs", then I >> do not think backward compatibility argument does not hold water. It >> is just correcting a longstanding 3-4 year old bug in a tool that >> nobody noticed. > > It's not quite that clear-cut. Some years ago, and before p4merge was > added as a Git mergetool, P4Merge was changed so its main GUI text > says "left" and "right" instead of "theirs" and "ours" when invoked > manually. > > But it appears that's as far as they went. It doesn't seem any of its > asymmetric diff display logic was changed; it works better with ours > on the right, and the built-in help all remains written on the > theirs/ours basis. And even little details like the icons imply it (a > square for the base, a downward-pointing triangle for their incoming > stuff, and a circle for the version we hold). So in short, a user of p4merge can see that left side is intended as "theirs", even though recent p4merge sometimes calls it "left". And your description on the coloring (green vs blue) makes it clear that "left" and "theirs" are still intended to be synonyms. If that is the case I would think you can still argue such a change as "correcting a 3-4-year old bug". > Would it be going too far to also have "xxxtool.reverse" to choose the > global default? It would be a natural thing to do. I left it out because I thought it would go without saying, given that precedences already exist, e.g. mergetool.keepBackup etc. > My only reservation is that I assume it would be implemented by > swapping what's passed in $LOCAL and $REMOTE. Which seems a bit icky: > $LOCAL="a.REMOTE.1234.c". Doesn't the UI show the actual temporary filename? When merging my version of hello.c with your version, showing them as hello.LOCAL.c and hello.REMOTE.c is an integral part of the UI experience, I think, even if the GUI tool does not give its own labels (and behaviour differences as you mentioned for p4merge) to mark which side is theirs and which side is ours. The temporary file that holds their version should still be named with REMOTE, even when the mergetool.reverse option is in effect. As to the name of the variable, I do not care too deeply about it myself, but I think keeping the current LOCAL and REMOTE would help people following the code, especially given the option is called "reverse", meaning that there is an internal convention that the order is "LOCAL and then REMOTE". One thing to watch out for is from which temporary file we take the merged results. You can present the two sides swapped, but if the tool always writes the results out by updating the second file, the caller needs to be prepared to read from the one that gets changed. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 19:10 ` Junio C Hamano @ 2013-03-07 19:50 ` David Aguilar 2013-03-07 20:31 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: David Aguilar @ 2013-03-07 19:50 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kevin Bracey, git, Ciaran Jessup, Scott Chacon On Thu, Mar 7, 2013 at 11:10 AM, Junio C Hamano <gitster@pobox.com> wrote: > Kevin Bracey <kevin@bracey.fi> writes: > >> On 07/03/2013 09:23, Junio C Hamano wrote: >>> If p4merge GUI labels one side clearly as "theirs" and the other >>> "ours", and the way we feed the inputs to it makes the side that is >>> actually "ours" appear in p4merge GUI labelled as "theirs", then I >>> do not think backward compatibility argument does not hold water. It >>> is just correcting a longstanding 3-4 year old bug in a tool that >>> nobody noticed. >> >> It's not quite that clear-cut. Some years ago, and before p4merge was >> added as a Git mergetool, P4Merge was changed so its main GUI text >> says "left" and "right" instead of "theirs" and "ours" when invoked >> manually. >> >> But it appears that's as far as they went. It doesn't seem any of its >> asymmetric diff display logic was changed; it works better with ours >> on the right, and the built-in help all remains written on the >> theirs/ours basis. And even little details like the icons imply it (a >> square for the base, a downward-pointing triangle for their incoming >> stuff, and a circle for the version we hold). > > So in short, a user of p4merge can see that left side is intended as > "theirs", even though recent p4merge sometimes calls it "left". And > your description on the coloring (green vs blue) makes it clear that > "left" and "theirs" are still intended to be synonyms. > > If that is the case I would think you can still argue such a change > as "correcting a 3-4-year old bug". I would prefer to treat this as a bugfix rather than introducing a new set of configuration knobs if possible. It really does seem like a correction. Users that want the traditional behavior can get that by configuring a custom mergetool.p4merge.cmd, so we're not completely losing the ability to get at the old behavior. Users that want to see a reverse diff with difftool can already say "--reverse", so there's even less reason to have it there (though I know we're talking about mergetool only). >> Would it be going too far to also have "xxxtool.reverse" to choose the >> global default? > > It would be a natural thing to do. I left it out because I thought > it would go without saying, given that precedences already exist, > e.g. mergetool.keepBackup etc. Medium NACK. If we can do without configuration all the better. I would much rather prefer to have the default/mainstream behavior be the best out-of-the-box sans configuration. The reasoning behind swapping them for p4merge makes sense for p4merge only. I don't think we're quite ready to declare that all the merge tools need to be swapped or that we need a mechanism for swapping the order. >> My only reservation is that I assume it would be implemented by >> swapping what's passed in $LOCAL and $REMOTE. Which seems a bit icky: >> $LOCAL="a.REMOTE.1234.c". > > Doesn't the UI show the actual temporary filename? When merging my > version of hello.c with your version, showing them as hello.LOCAL.c > and hello.REMOTE.c is an integral part of the UI experience, I > think, even if the GUI tool does not give its own labels (and > behaviour differences as you mentioned for p4merge) to mark which > side is theirs and which side is ours. The temporary file that > holds their version should still be named with REMOTE, even when the > mergetool.reverse option is in effect. > > As to the name of the variable, I do not care too deeply about it > myself, but I think keeping the current LOCAL and REMOTE would help > people following the code, especially given the option is called > "reverse", meaning that there is an internal convention that the > order is "LOCAL and then REMOTE". > > One thing to watch out for is from which temporary file we take the > merged results. You can present the two sides swapped, but if the > tool always writes the results out by updating the second file, the > caller needs to be prepared to read from the one that gets changed. -- David ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool 2013-03-07 19:50 ` David Aguilar @ 2013-03-07 20:31 ` Junio C Hamano 0 siblings, 0 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-07 20:31 UTC (permalink / raw) To: David Aguilar; +Cc: Kevin Bracey, git, Ciaran Jessup, Scott Chacon David Aguilar <davvid@gmail.com> writes: > I would prefer to treat this as a bugfix rather than introducing > a new set of configuration knobs if possible. It really does > seem like a correction. > > Users that want the traditional behavior can get that by > configuring a custom mergetool.p4merge.cmd, so we're not > completely losing the ability to get at the old behavior. > > Users that want to see a reverse diff with difftool can > already say "--reverse", so there's even less reason to > have it there (though I know we're talking about mergetool only). > ... > I would much rather prefer to have the default/mainstream > behavior be the best out-of-the-box sans configuration. > > The reasoning behind swapping them for p4merge makes sense > for p4merge only. I don't think we're quite ready to declare > that all the merge tools need to be swapped or that we need a > mechanism for swapping the order. Thanks for an injection of sanity. ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH 2/2] p4merge: create a virtual base if none available 2013-03-06 20:32 [PATCH 0/2] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-06 20:32 ` [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool Kevin Bracey @ 2013-03-06 20:32 ` Kevin Bracey 2013-03-07 2:23 ` David Aguilar 2013-03-07 3:33 ` David Aguilar 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 3 siblings, 2 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-06 20:32 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon Originally, with no base, Git gave P4Merge $LOCAL as a dummy base: p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" Commit 0a0ec7bd changed this to: p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED" to avoid the problem of being unable to save in some circumstances. Unfortunately this approach does not produce good results at all on differing inputs. P4Merge really regards the blank file as the base, and once you have just a couple of differences between the two branches you end up with one a massive full-file conflict. The diff is not readable, and you have to invoke "difftool MERGE_HEAD HEAD" manually to see a 2-way diff. The original form appears to have invoked special 2-way comparison behaviour that occurs only if the base filename is "" or equal to the left input. You get a good diff, and it does not auto-resolve in one direction or the other. (Normally if one branch equals the base, it would autoresolve to the other branch). But there appears to be no way of getting this 2-way behaviour and being able to reliably save. Having base=left appears to be triggering other assumptions. There are tricks the user can use to force the save icon on, but it's not intuitive. So we now follow a suggestion given in the original patch's discussion: generate a virtual base, consisting of the lines common to the two branches. It produces a much nicer 3-way diff view than either of the original forms, and than I suspect other mergetools are managing. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-mergetool--lib.sh | 14 ++++++++++++++ mergetools/p4merge | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh index e338be5..5b60cf5 100644 --- a/git-mergetool--lib.sh +++ b/git-mergetool--lib.sh @@ -108,6 +108,20 @@ check_unchanged () { fi } +make_virtual_base() { + # Copied from git-merge-one-file.sh. + # This starts with $LOCAL, and uses git apply to + # remove lines that are not in $REMOTE. + cp -- "$LOCAL" "$BASE" + sz0=`wc -c <"$BASE"` + @@DIFF@@ -u -L"a/$BASE" -L"b/$BASE" "$BASE" "$REMOTE" | git apply --no-add + sz1=`wc -c <"$BASE"` + + # If we do not have enough common material, it is not + # worth trying two-file merge using common subsections. + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$BASE" +} + valid_tool () { setup_tool "$1" && return 0 cmd=$(get_merge_tool_cmd "$1") diff --git a/mergetools/p4merge b/mergetools/p4merge index 46b3a5a..f0a893b 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -21,7 +21,7 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" - $base_present || >"$BASE" + $base_present || make_virtual_base "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc2.5.g1a80410.dirty ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH 2/2] p4merge: create a virtual base if none available 2013-03-06 20:32 ` [PATCH 2/2] p4merge: create a virtual base if none available Kevin Bracey @ 2013-03-07 2:23 ` David Aguilar 2013-03-07 6:28 ` Kevin Bracey 2013-03-07 7:25 ` Junio C Hamano 2013-03-07 3:33 ` David Aguilar 1 sibling, 2 replies; 40+ messages in thread From: David Aguilar @ 2013-03-07 2:23 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, Ciaran Jessup, Scott Chacon On Wed, Mar 6, 2013 at 12:32 PM, Kevin Bracey <kevin@bracey.fi> wrote: > Originally, with no base, Git gave P4Merge $LOCAL as a dummy base: > > p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" > > Commit 0a0ec7bd changed this to: > > p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED" > > to avoid the problem of being unable to save in some circumstances. > > Unfortunately this approach does not produce good results at all on > differing inputs. P4Merge really regards the blank file as the base, and > once you have just a couple of differences between the two branches you > end up with one a massive full-file conflict. The diff is not readable, > and you have to invoke "difftool MERGE_HEAD HEAD" manually to see a > 2-way diff. > > The original form appears to have invoked special 2-way comparison > behaviour that occurs only if the base filename is "" or equal to the > left input. You get a good diff, and it does not auto-resolve in one > direction or the other. (Normally if one branch equals the base, it > would autoresolve to the other branch). > > But there appears to be no way of getting this 2-way behaviour and being > able to reliably save. Having base=left appears to be triggering other > assumptions. There are tricks the user can use to force the save icon > on, but it's not intuitive. > > So we now follow a suggestion given in the original patch's discussion: > generate a virtual base, consisting of the lines common to the two > branches. It produces a much nicer 3-way diff view than either of the > original forms, and than I suspect other mergetools are managing. > > Signed-off-by: Kevin Bracey <kevin@bracey.fi> > --- > git-mergetool--lib.sh | 14 ++++++++++++++ > mergetools/p4merge | 2 +- > 2 files changed, 15 insertions(+), 1 deletion(-) > > diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh > index e338be5..5b60cf5 100644 > --- a/git-mergetool--lib.sh > +++ b/git-mergetool--lib.sh > @@ -108,6 +108,20 @@ check_unchanged () { > fi > } > > +make_virtual_base() { > + # Copied from git-merge-one-file.sh. I think the reasoning behind these patches is good. How do we feel about this duplication? Should we make a common function in the git-sh-setup.sh, or is it okay to have a slightly modified version of this function in two places? > + # This starts with $LOCAL, and uses git apply to > + # remove lines that are not in $REMOTE. > + cp -- "$LOCAL" "$BASE" > + sz0=`wc -c <"$BASE"` > + @@DIFF@@ -u -L"a/$BASE" -L"b/$BASE" "$BASE" "$REMOTE" | git apply --no-add > + sz1=`wc -c <"$BASE"` > + > + # If we do not have enough common material, it is not > + # worth trying two-file merge using common subsections. > + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$BASE" > +} > + > valid_tool () { > setup_tool "$1" && return 0 > cmd=$(get_merge_tool_cmd "$1") > diff --git a/mergetools/p4merge b/mergetools/p4merge > index 46b3a5a..f0a893b 100644 > --- a/mergetools/p4merge > +++ b/mergetools/p4merge > @@ -21,7 +21,7 @@ diff_cmd () { > > merge_cmd () { > touch "$BACKUP" > - $base_present || >"$BASE" > + $base_present || make_virtual_base > "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" > check_unchanged > } > -- > 1.8.2.rc2.5.g1a80410.dirty > -- David ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 2/2] p4merge: create a virtual base if none available 2013-03-07 2:23 ` David Aguilar @ 2013-03-07 6:28 ` Kevin Bracey 2013-03-07 7:25 ` Junio C Hamano 1 sibling, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-07 6:28 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon On 07/03/2013 04:23, David Aguilar wrote: > On Wed, Mar 6, 2013 at 12:32 PM, Kevin Bracey <kevin@bracey.fi> wrote: >> +make_virtual_base() { >> + # Copied from git-merge-one-file.sh. > I think the reasoning behind these patches is good. > > How do we feel about this duplication? Bad. > Should we make a common function in the git-sh-setup.sh, > or is it okay to have a slightly modified version of this > function in two places? I'd prefer to have a common function, I just didn't know if there was somewhere appropriate to place it, available from both files. And I'm going to have to learn a bit more sh to get it right. > Also, the "@@DIFF@@" string may not work here. > This is a template string that is replaced by the Makefile. It does work in git-mergetool--lib.sh, but not in mergetools/p4merge. > We prefer $(command) instead of `command`. > These should be adjusted. > > Can the same thing be accomplished using "git diff --no-index" > so that we do not need a dependency on an external "diff" command here? Do these comments still apply if it's a common function in git-sh-setup.sh that git-one-merge-file.sh will use? I'm wary of layering violations. Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 2/2] p4merge: create a virtual base if none available 2013-03-07 2:23 ` David Aguilar 2013-03-07 6:28 ` Kevin Bracey @ 2013-03-07 7:25 ` Junio C Hamano 1 sibling, 0 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-07 7:25 UTC (permalink / raw) To: David Aguilar; +Cc: Kevin Bracey, git, Ciaran Jessup, Scott Chacon David Aguilar <davvid@gmail.com> writes: > How do we feel about this duplication? > Should we make a common function in the git-sh-setup.sh, > or is it okay to have a slightly modified version of this > function in two places? It probably is a good idea to have it in one place. That would also solve the @@DIFF@@ replacement issue you noticed at the same time. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH 2/2] p4merge: create a virtual base if none available 2013-03-06 20:32 ` [PATCH 2/2] p4merge: create a virtual base if none available Kevin Bracey 2013-03-07 2:23 ` David Aguilar @ 2013-03-07 3:33 ` David Aguilar 1 sibling, 0 replies; 40+ messages in thread From: David Aguilar @ 2013-03-07 3:33 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, Ciaran Jessup, Scott Chacon On Wed, Mar 6, 2013 at 12:32 PM, Kevin Bracey <kevin@bracey.fi> wrote: > +make_virtual_base() { > + # Copied from git-merge-one-file.sh. > + # This starts with $LOCAL, and uses git apply to > + # remove lines that are not in $REMOTE. > + cp -- "$LOCAL" "$BASE" > + sz0=`wc -c <"$BASE"` > + @@DIFF@@ -u -L"a/$BASE" -L"b/$BASE" "$BASE" "$REMOTE" | git apply --no-add > + sz1=`wc -c <"$BASE"` > + > + # If we do not have enough common material, it is not > + # worth trying two-file merge using common subsections. > + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$BASE" > +} This seems to be indented deeper then the other functions (or gmail is whitespace damaging my view). Please use one hard tab to indent here. We prefer $(command) instead of `command`. These should be adjusted. Also, the "@@DIFF@@" string may not work here. This is a template string that is replaced by the Makefile. I don't think the tools in the mergetools/ directory go through cmd_munge_script so this is not going to work as-is. Can the same thing be accomplished using "git diff --no-index" so that we do not need a dependency on an external "diff" command here? I am not a regular p4merge user myself so I'll defer to others on the cc: list for their thoughts. It does seem like a good idea, though. -- David ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v2 0/3] Improve P4Merge mergetool invocation 2013-03-06 20:32 [PATCH 0/2] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-06 20:32 ` [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool Kevin Bracey 2013-03-06 20:32 ` [PATCH 2/2] p4merge: create a virtual base if none available Kevin Bracey @ 2013-03-09 19:20 ` Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey ` (2 more replies) 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 3 siblings, 3 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-09 19:20 UTC (permalink / raw) To: git; +Cc: Kevin Bracey, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Incorporated comments on the previous patches, and one new patch addressing a problem I spotted while testing git-merge-one-file. I couldn't figure out how to use git diff to achieve the effect of the external diff here - we'd need some alternative to achieve what it does with the -L option, and I failed to come up with anything remotely elegant. Kevin Bracey (3): mergetools/p4merge: swap LOCAL and REMOTE mergetools/p4merge: create a base if none available git-merge-one-file: revise merge error reporting git-merge-one-file.sh | 38 ++++++++++++-------------------------- git-sh-setup.sh | 13 +++++++++++++ mergetools/p4merge | 8 ++++++-- 3 files changed, 31 insertions(+), 28 deletions(-) -- 1.8.2.rc3.7.g77aeedb ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v2 1/3] mergetools/p4merge: swap LOCAL and REMOTE 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey @ 2013-03-09 19:20 ` Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 2/3] mergetools/p4merge: create a base if none available Kevin Bracey 2013-03-09 19:21 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-09 19:20 UTC (permalink / raw) To: git; +Cc: Kevin Bracey, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that the incoming branch is now in the left-hand, blue triangle pane, and the current branch is in the right-hand, green circle pane. This change makes use of P4Merge consistent with its built-in help, its reference documentation, and Perforce itself. But most importantly, it makes merge results clearer. P4Merge is not totally symmetrical between left and right; despite changing a few text labels from "theirs/ours" to "left/right" when invoked manually, it still retains its original Perforce "theirs/ours" viewpoint. Most obviously, in the result pane P4Merge shows changes that are common to both branches in green. This is on the basis of the current branch being green, as it is when invoked from Perforce; it means that lines in the result are blue if and only if they are being changed by the merge, making the resulting diff clearer. Note that P4Merge now shows "ours" on the right for both diff and merge, unlike other diff/mergetools, which always have REMOTE on the right. But observe that REMOTE is the working tree (ie "ours") for a diff, while it's another branch (ie "theirs") for a merge. Ours and theirs are reversed for a rebase - see "git help rebase". However, this does produce the desired "show the results of this commit" effect in P4Merge - changes that remain in the rebased commit (in your branch, but not in the new base) appear in blue; changes that do not appear in the rebased commit (from the new base, or common to both) are in green. If Perforce had rebase, they'd probably not swap ours/theirs, but make P4Merge show common changes in blue, picking out our changes in green. We can't do that, so this is next best. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- mergetools/p4merge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mergetools/p4merge b/mergetools/p4merge index 8a36916..46b3a5a 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -22,7 +22,7 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" $base_present || >"$BASE" - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.7.g77aeedb ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v2 2/3] mergetools/p4merge: create a base if none available 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey @ 2013-03-09 19:20 ` Kevin Bracey 2013-03-10 4:55 ` Junio C Hamano 2013-03-09 19:21 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-09 19:20 UTC (permalink / raw) To: git; +Cc: Kevin Bracey, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Originally, with no base, Git gave P4Merge $LOCAL as a dummy base: p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" Commit 0a0ec7bd changed this to: p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED" to avoid the problem of being unable to save in some circumstances with similar inputs. Unfortunately this approach produces much worse results on differing inputs. P4Merge really regards the blank file as the base, and once you have just a couple of differences between the two branches you end up with one a massive full-file conflict. The 3-way diff is not readable, and you have to invoke "difftool MERGE_HEAD HEAD" manually to get a useful view. The original approach appears to have invoked special 2-way merge behaviour in P4Merge that occurs only if the base filename is "" or equal to the left input. You get a good visual comparison, and it does not auto-resolve differences. (Normally if one branch matched the base, it would autoresolve to the other branch). But there appears to be no way of getting this 2-way behaviour and being able to reliably save. Having base==left appears to be triggering other assumptions. There are tricks the user can use to force the save icon on, but it's not intuitive. So we now follow a suggestion given in the original patch's discussion: generate a virtual base, consisting of the lines common to the two branches. This is the same as the technique used in resolve and octopus merges, so we relocate that code to a shared function. Note that if there are no differences at the same location, this technique can lead to automatic resolution without conflict, combining everything from the 2 files. As with the other merges using this technique, we assume the user will inspect the result before saving. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 18 +++++------------- git-sh-setup.sh | 13 +++++++++++++ mergetools/p4merge | 6 +++++- 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index f612cb8..1236fbf 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -104,30 +104,22 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac - src2=`git-unpack-file $3` + src1=$(git-unpack-file $2) + src2=$(git-unpack-file $3) case "$1" in '') echo "Added $4 in both, but differently." - # This extracts OUR file in $orig, and uses git apply to - # remove lines that are unique to ours. - orig=`git-unpack-file $2` - sz0=`wc -c <"$orig"` - @@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add - sz1=`wc -c <"$orig"` - - # If we do not have enough common material, it is not - # worth trying two-file merge using common subsections. - expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig + orig=$(git-unpack-file $2) + create_virtual_base "$orig" "$src1" "$src2" ;; *) echo "Auto-merging $4" - orig=`git-unpack-file $1` + orig=$(git-unpack-file $1) ;; esac # Be careful for funny filename such as "-L" in "$4", which # would confuse "merge" greatly. - src1=`git-unpack-file $2` git merge-file "$src1" "$orig" "$src2" ret=$? msg= diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 795edd2..aa9a732 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -249,6 +249,19 @@ clear_local_git_env() { unset $(git rev-parse --local-env-vars) } +# Generate a virtual base file for a two-file merge. On entry the +# base file $1 should be a copy of $2. Uses git apply to remove +# lines from $1 that are not in $3, leaving only common lines. +create_virtual_base() { + sz0=$(wc -c <"$1") + @@DIFF@@ -u -La/"$1" -Lb/"$1" "$2" "$3" | git apply --no-add + sz1=$(wc -c <"$1") + + # If we do not have enough common material, it is not + # worth trying two-file merge using common subsections. + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1" +} + # Platform specific tweaks to work around some commands case $(uname -s) in diff --git a/mergetools/p4merge b/mergetools/p4merge index 46b3a5a..16ae0cc 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -21,7 +21,11 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" - $base_present || >"$BASE" + if ! $base_present + then + cp -- "$LOCAL" "$BASE" + create_virtual_base "$BASE" "$LOCAL" "$REMOTE" + fi "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.7.g77aeedb ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v2 2/3] mergetools/p4merge: create a base if none available 2013-03-09 19:20 ` [PATCH v2 2/3] mergetools/p4merge: create a base if none available Kevin Bracey @ 2013-03-10 4:55 ` Junio C Hamano 0 siblings, 0 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-10 4:55 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Kevin Bracey <kevin@bracey.fi> writes: > diff --git a/git-sh-setup.sh b/git-sh-setup.sh > index 795edd2..aa9a732 100644 > --- a/git-sh-setup.sh > +++ b/git-sh-setup.sh > @@ -249,6 +249,19 @@ clear_local_git_env() { > unset $(git rev-parse --local-env-vars) > } > > +# Generate a virtual base file for a two-file merge. On entry the > +# base file $1 should be a copy of $2. Uses git apply to remove > +# lines from $1 that are not in $3, leaving only common lines. > +create_virtual_base() { > + sz0=$(wc -c <"$1") > + @@DIFF@@ -u -La/"$1" -Lb/"$1" "$2" "$3" | git apply --no-add > + sz1=$(wc -c <"$1") > + > + # If we do not have enough common material, it is not > + # worth trying two-file merge using common subsections. > + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1" > +} > + This rewrite is wrong. It should be > + sz0=$(wc -c <"$1") > + @@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$3" | git apply --no-add > + sz1=$(wc -c <"$1") for it to make sense. "diff $1 $3" is a change to go from $1 to $3; with "-La/$1 -Lb/$1", we declare that the change is to be applied to $1, and use --no-add to only use the removal from the diff when we edit $1 using this mechanism. The end effect is to in-place edit "$1" to remove what is not common with "$3", and sz0/sz1 computation is done on "$1" for this reason. Does it (i.e. "$1") shrink sufficiently when we remove the material that is not common in it (i.e. "$1") and "$3"? This part is a two-file operation between $1 and $3; there is nothing you would want to pass $2 to influence what the above three lines do. It may happen that the caller has two copies of the same thing, $orig and $src1, and uses one for $1 and the other for $2, so you won't observe the damage from the incorrect rewriting of the above logic, but it invites the next caller to incorrectly feed something totally unrelated to $1 and $2. Please fix it to a function that takes two temporary paths, not three. ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 2/3] mergetools/p4merge: create a base if none available Kevin Bracey @ 2013-03-09 19:21 ` Kevin Bracey 2 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-09 19:21 UTC (permalink / raw) To: git; +Cc: Kevin Bracey, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Commit 718135e improved the merge error reporting for the resolve strategy's merge conflict and permission conflict cases, but led to a malformed "ERROR: in myfile.c" message in the case of a file added differently. This commit reverts that change, and uses an alternative approach without this flaw. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 1236fbf..70f36f1 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -104,11 +104,13 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac + ret=0 src1=$(git-unpack-file $2) src2=$(git-unpack-file $3) case "$1" in '') - echo "Added $4 in both, but differently." + echo "ERROR: Added $4 in both, but differently." + ret=1 orig=$(git-unpack-file $2) create_virtual_base "$orig" "$src1" "$src2" ;; @@ -121,10 +123,9 @@ case "${1:-.}${2:-.}${3:-.}" in # Be careful for funny filename such as "-L" in "$4", which # would confuse "merge" greatly. git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if [ $ret -ne 0 ]; then - msg='content conflict' + if [ $? -ne 0 ]; then + echo "ERROR: Content conflict in $4" + ret=1 fi # Create the working tree file, using "our tree" version from the @@ -133,18 +134,11 @@ case "${1:-.}${2:-.}${3:-.}" in rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then - if [ -n "$msg" ]; then - msg="$msg, " - fi - msg="${msg}permissions conflict: $5->$6,$7" - ret=1 - fi - if [ "$1" = '' ]; then + echo "ERROR: Permissions conflict: $5->$6,$7" ret=1 fi if [ $ret -ne 0 ]; then - echo "ERROR: $msg in $4" exit 1 fi exec git update-index -- "$4" -- 1.8.2.rc3.7.g77aeedb ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE 2013-03-06 20:32 [PATCH 0/2] Improve P4Merge mergetool invocation Kevin Bracey ` (2 preceding siblings ...) 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey @ 2013-03-13 1:12 ` Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 2/3] mergetools/p4merge: create a base if none available Kevin Bracey ` (3 more replies) 3 siblings, 4 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-13 1:12 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen, Kevin Bracey Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that the incoming branch is now in the left-hand, blue triangle pane, and the current branch is in the right-hand, green circle pane. This change makes use of P4Merge consistent with its built-in help, its reference documentation, and Perforce itself. But most importantly, it makes merge results clearer. P4Merge is not totally symmetrical between left and right; despite changing a few text labels from "theirs/ours" to "left/right" when invoked manually, it still retains its original Perforce "theirs/ours" viewpoint. Most obviously, in the result pane P4Merge shows changes that are common to both branches in green. This is on the basis of the current branch being green, as it is when invoked from Perforce; it means that lines in the result are blue if and only if they are being changed by the merge, making the resulting diff clearer. Note that P4Merge now shows "ours" on the right for both diff and merge, unlike other diff/mergetools, which always have REMOTE on the right. But observe that REMOTE is the working tree (ie "ours") for a diff, while it's another branch (ie "theirs") for a merge. Ours and theirs are reversed for a rebase - see "git help rebase". However, this does produce the desired "show the results of this commit" effect in P4Merge - changes that remain in the rebased commit (in your branch, but not in the new base) appear in blue; changes that do not appear in the rebased commit (from the new base, or common to both) are in green. If Perforce had rebase, they'd probably not swap ours/theirs, but make P4Merge show common changes in blue, picking out our changes in green. We can't do that, so this is next best. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- mergetools/p4merge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mergetools/p4merge b/mergetools/p4merge index 8a36916..46b3a5a 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -22,7 +22,7 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" $base_present || >"$BASE" - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.7.g1100d09.dirty ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v3 2/3] mergetools/p4merge: create a base if none available 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey @ 2013-03-13 1:12 ` Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey ` (2 subsequent siblings) 3 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-13 1:12 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen, Kevin Bracey Originally, with no base, Git gave P4Merge $LOCAL as a dummy base: p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" Commit 0a0ec7bd changed this to: p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED" to avoid the problem of being unable to save in some circumstances with similar inputs. Unfortunately this approach produces much worse results on differing inputs. P4Merge really regards the blank file as the base, and once you have just a couple of differences between the two branches you end up with one a massive full-file conflict. The 3-way diff is not readable, and you have to invoke "difftool MERGE_HEAD HEAD" manually to get a useful view. The original approach appears to have invoked special 2-way merge behaviour in P4Merge that occurs only if the base filename is "" or equal to the left input. You get a good visual comparison, and it does not auto-resolve differences. (Normally if one branch matched the base, it would autoresolve to the other branch). But there appears to be no way of getting this 2-way behaviour and being able to reliably save. Having base==left appears to be triggering other assumptions. There are tricks the user can use to force the save icon on, but it's not intuitive. So we now follow a suggestion given in the original patch's discussion: generate a virtual base, consisting of the lines common to the two branches. This is the same as the technique used in resolve and octopus merges, so we relocate that code to a shared function. Note that if there are no differences at the same location, this technique can lead to automatic resolution without conflict, combining everything from the 2 files. As with the other merges using this technique, we assume the user will inspect the result before saving. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- Documentation/git-sh-setup.txt | 6 ++++++ git-merge-one-file.sh | 18 +++++------------- git-sh-setup.sh | 12 ++++++++++++ mergetools/p4merge | 6 +++++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt index 6a9f66d..5d709d0 100644 --- a/Documentation/git-sh-setup.txt +++ b/Documentation/git-sh-setup.txt @@ -82,6 +82,12 @@ get_author_ident_from_commit:: outputs code for use with eval to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit. +create_virtual_base:: + modifies the first file so only lines in common with the + second file remain. If there is insufficient common material, + then the first file is left empty. The result is suitable + as a virtual base input for a 3-way merge. + GIT --- Part of the linkgit:git[1] suite diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index f612cb8..0f164e5 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -104,30 +104,22 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac - src2=`git-unpack-file $3` + src1=$(git-unpack-file $2) + src2=$(git-unpack-file $3) case "$1" in '') echo "Added $4 in both, but differently." - # This extracts OUR file in $orig, and uses git apply to - # remove lines that are unique to ours. - orig=`git-unpack-file $2` - sz0=`wc -c <"$orig"` - @@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add - sz1=`wc -c <"$orig"` - - # If we do not have enough common material, it is not - # worth trying two-file merge using common subsections. - expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig + orig=$(git-unpack-file $2) + create_virtual_base "$orig" "$src2" ;; *) echo "Auto-merging $4" - orig=`git-unpack-file $1` + orig=$(git-unpack-file $1) ;; esac # Be careful for funny filename such as "-L" in "$4", which # would confuse "merge" greatly. - src1=`git-unpack-file $2` git merge-file "$src1" "$orig" "$src2" ret=$? msg= diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 795edd2..349a5d4 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -249,6 +249,18 @@ clear_local_git_env() { unset $(git rev-parse --local-env-vars) } +# Generate a virtual base file for a two-file merge. Uses git apply to +# remove lines from $1 that are not in $2, leaving only common lines. +create_virtual_base() { + sz0=$(wc -c <"$1") + @@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add + sz1=$(wc -c <"$1") + + # If we do not have enough common material, it is not + # worth trying two-file merge using common subsections. + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1" +} + # Platform specific tweaks to work around some commands case $(uname -s) in diff --git a/mergetools/p4merge b/mergetools/p4merge index 46b3a5a..5a608ab 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -21,7 +21,11 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" - $base_present || >"$BASE" + if ! $base_present + then + cp -- "$LOCAL" "$BASE" + create_virtual_base "$BASE" "$REMOTE" + fi "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.7.g1100d09.dirty ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 2/3] mergetools/p4merge: create a base if none available Kevin Bracey @ 2013-03-13 1:12 ` Kevin Bracey 2013-03-13 9:03 ` David Aguilar 2013-03-13 17:57 ` [PATCH v3 " Junio C Hamano 2013-03-13 2:05 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE David Aguilar 2013-03-24 11:54 ` [PATCH v4 1/2] " Kevin Bracey 3 siblings, 2 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-13 1:12 UTC (permalink / raw) To: git; +Cc: David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen, Kevin Bracey Commit 718135e improved the merge error reporting for the resolve strategy's merge conflict and permission conflict cases, but led to a malformed "ERROR: in myfile.c" message in the case of a file added differently. This commit reverts that change, and uses an alternative approach without this flaw. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 0f164e5..78b07a8 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -104,11 +104,13 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac + ret=0 src1=$(git-unpack-file $2) src2=$(git-unpack-file $3) case "$1" in '') - echo "Added $4 in both, but differently." + echo "ERROR: Added $4 in both, but differently." + ret=1 orig=$(git-unpack-file $2) create_virtual_base "$orig" "$src2" ;; @@ -121,10 +123,9 @@ case "${1:-.}${2:-.}${3:-.}" in # Be careful for funny filename such as "-L" in "$4", which # would confuse "merge" greatly. git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if [ $ret -ne 0 ]; then - msg='content conflict' + if [ $? -ne 0 ]; then + echo "ERROR: Content conflict in $4" + ret=1 fi # Create the working tree file, using "our tree" version from the @@ -133,18 +134,11 @@ case "${1:-.}${2:-.}${3:-.}" in rm -f -- "$orig" "$src1" "$src2" if [ "$6" != "$7" ]; then - if [ -n "$msg" ]; then - msg="$msg, " - fi - msg="${msg}permissions conflict: $5->$6,$7" - ret=1 - fi - if [ "$1" = '' ]; then + echo "ERROR: Permissions conflict: $5->$6,$7" ret=1 fi if [ $ret -ne 0 ]; then - echo "ERROR: $msg in $4" exit 1 fi exec git update-index -- "$4" -- 1.8.2.rc3.7.g1100d09.dirty ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-13 1:12 ` [PATCH v3 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey @ 2013-03-13 9:03 ` David Aguilar 2013-03-24 12:26 ` [PATCH v2 0/3] git-merge-one-file " Kevin Bracey 2013-03-13 17:57 ` [PATCH v3 " Junio C Hamano 1 sibling, 1 reply; 40+ messages in thread From: David Aguilar @ 2013-03-13 9:03 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, Ciaran Jessup, Scott Chacon, Alex Riesen On Tue, Mar 12, 2013 at 6:12 PM, Kevin Bracey <kevin@bracey.fi> wrote: > Commit 718135e improved the merge error reporting for the resolve > strategy's merge conflict and permission conflict cases, but led to a > malformed "ERROR: in myfile.c" message in the case of a file added > differently. > > This commit reverts that change, and uses an alternative approach without > this flaw. > > Signed-off-by: Kevin Bracey <kevin@bracey.fi> > --- I wonder whether before these changes we should update the style in this file to follow Documentation/CodingGuidelines. Not in this patch, but in the file right now there's this part that stands out: if [ "$2" ]; then echo "Removing $4" I think that expression would read more clearly as: if test -n "$2" then echo "Removing $4" Ditto `if [ "$1" = '' ]` is better written as `test -z "$1"`. Can you please send a patch to true these up? It'd be especially nice if the style patch could come first, followed by the fixes/features ;-) > git-merge-one-file.sh | 20 +++++++------------- > 1 file changed, 7 insertions(+), 13 deletions(-) > > diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh > index 0f164e5..78b07a8 100755 > --- a/git-merge-one-file.sh > +++ b/git-merge-one-file.sh > @@ -104,11 +104,13 @@ case "${1:-.}${2:-.}${3:-.}" in > ;; > esac > > + ret=0 > src1=$(git-unpack-file $2) > src2=$(git-unpack-file $3) > case "$1" in > '') > - echo "Added $4 in both, but differently." > + echo "ERROR: Added $4 in both, but differently." > + ret=1 > orig=$(git-unpack-file $2) > create_virtual_base "$orig" "$src2" > ;; > @@ -121,10 +123,9 @@ case "${1:-.}${2:-.}${3:-.}" in > # Be careful for funny filename such as "-L" in "$4", which > # would confuse "merge" greatly. > git merge-file "$src1" "$orig" "$src2" > - ret=$? > - msg= > - if [ $ret -ne 0 ]; then > - msg='content conflict' > + if [ $? -ne 0 ]; then > + echo "ERROR: Content conflict in $4" > + ret=1 if test $? != 0 then Also.. should this error not go to stderr? I guess the existing script was not doing that, but it seems like anything that says "ERROR" should go there. > fi > > # Create the working tree file, using "our tree" version from the > @@ -133,18 +134,11 @@ case "${1:-.}${2:-.}${3:-.}" in > rm -f -- "$orig" "$src1" "$src2" > > if [ "$6" != "$7" ]; then > - if [ -n "$msg" ]; then > - msg="$msg, " > - fi > - msg="${msg}permissions conflict: $5->$6,$7" > - ret=1 > - fi > - if [ "$1" = '' ]; then > + echo "ERROR: Permissions conflict: $5->$6,$7" > ret=1 > fi > > if [ $ret -ne 0 ]; then > - echo "ERROR: $msg in $4" > exit 1 > fi > exec git update-index -- "$4" same notes as above. I think a style patch should come first. -- David ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v2 0/3] git-merge-one-file error reporting 2013-03-13 9:03 ` David Aguilar @ 2013-03-24 12:26 ` Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 1/3] git-merge-one-file: style cleanup Kevin Bracey ` (2 more replies) 0 siblings, 3 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 12:26 UTC (permalink / raw) To: git; +Cc: David Aguilar, Kevin Bracey Style clean up, as requested, followed by the fix to the "both sides added" handling for git-merge-one-file. This is based on v4 of my p4merge series, as they touch the same area. Kevin Bracey (3): git-merge-one-file: style cleanup git-merge-one-file: send "ERROR:" messages to stderr git-merge-one-file: revise merge error reporting git-merge-one-file.sh | 50 +++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 25 deletions(-) -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v2 1/3] git-merge-one-file: style cleanup 2013-03-24 12:26 ` [PATCH v2 0/3] git-merge-one-file " Kevin Bracey @ 2013-03-24 12:26 ` Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 2/3] git-merge-one-file: send "ERROR:" messages to stderr Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 12:26 UTC (permalink / raw) To: git; +Cc: David Aguilar, Kevin Bracey Update style to match Documentation/CodingGuidelines. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 255c07a..2382b1f 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -27,7 +27,7 @@ SUBDIRECTORY_OK=Yes cd_to_toplevel require_work_tree -if ! test "$#" -eq 7 +if test $# != 7 then echo "$LONG_USAGE" exit 1 @@ -38,7 +38,8 @@ case "${1:-.}${2:-.}${3:-.}" in # Deleted in both or deleted in one and unchanged in the other # "$1.." | "$1.$1" | "$1$1.") - if [ "$2" ]; then + if test -n "$2" + then echo "Removing $4" else # read-tree checked that index matches HEAD already, @@ -48,7 +49,8 @@ case "${1:-.}${2:-.}${3:-.}" in # we do not have it in the index, though. exec git update-index --remove -- "$4" fi - if test -f "$4"; then + if test -f "$4" + then rm -f -- "$4" && rmdir -p "$(expr "z$4" : 'z\(.*\)/')" 2>/dev/null || : fi && @@ -78,7 +80,8 @@ case "${1:-.}${2:-.}${3:-.}" in # Added in both, identically (check for same permissions). # ".$3$2") - if [ "$6" != "$7" ]; then + if test "$6" != "$7" + then echo "ERROR: File $4 added identically in both branches," echo "ERROR: but permissions conflict $6->$7." exit 1 @@ -123,7 +126,8 @@ case "${1:-.}${2:-.}${3:-.}" in git merge-file "$src1" "$orig" "$src2" ret=$? msg= - if [ $ret -ne 0 ]; then + if test $ret != 0 + then msg='content conflict' fi @@ -132,18 +136,22 @@ case "${1:-.}${2:-.}${3:-.}" in git checkout-index -f --stage=2 -- "$4" && cat "$src1" >"$4" || exit 1 rm -f -- "$orig" "$src1" "$src2" - if [ "$6" != "$7" ]; then - if [ -n "$msg" ]; then + if test "$6" != "$7" + then + if test -n "$msg" + then msg="$msg, " fi msg="${msg}permissions conflict: $5->$6,$7" ret=1 fi - if [ "$1" = '' ]; then + if test -z "$1" + then ret=1 fi - if [ $ret -ne 0 ]; then + if test $ret != 0 + then echo "ERROR: $msg in $4" exit 1 fi -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v2 2/3] git-merge-one-file: send "ERROR:" messages to stderr 2013-03-24 12:26 ` [PATCH v2 0/3] git-merge-one-file " Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 1/3] git-merge-one-file: style cleanup Kevin Bracey @ 2013-03-24 12:26 ` Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 12:26 UTC (permalink / raw) To: git; +Cc: David Aguilar, Kevin Bracey Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 2382b1f..39b7799 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -69,7 +69,7 @@ case "${1:-.}${2:-.}${3:-.}" in echo "Adding $4" if test -f "$4" then - echo "ERROR: untracked $4 is overwritten by the merge." + echo "ERROR: untracked $4 is overwritten by the merge." >&2 exit 1 fi git update-index --add --cacheinfo "$7" "$3" "$4" && @@ -82,8 +82,8 @@ case "${1:-.}${2:-.}${3:-.}" in ".$3$2") if test "$6" != "$7" then - echo "ERROR: File $4 added identically in both branches," - echo "ERROR: but permissions conflict $6->$7." + echo "ERROR: File $4 added identically in both branches," >&2 + echo "ERROR: but permissions conflict $6->$7." >&2 exit 1 fi echo "Adding $4" @@ -98,11 +98,11 @@ case "${1:-.}${2:-.}${3:-.}" in case ",$6,$7," in *,120000,*) - echo "ERROR: $4: Not merging symbolic link changes." + echo "ERROR: $4: Not merging symbolic link changes." >&2 exit 1 ;; *,160000,*) - echo "ERROR: $4: Not merging conflicting submodule changes." + echo "ERROR: $4: Not merging conflicting submodule changes." >&2 exit 1 ;; esac @@ -152,14 +152,14 @@ case "${1:-.}${2:-.}${3:-.}" in if test $ret != 0 then - echo "ERROR: $msg in $4" + echo "ERROR: $msg in $4" >&2 exit 1 fi exec git update-index -- "$4" ;; *) - echo "ERROR: $4: Not handling case $1 -> $2 -> $3" + echo "ERROR: $4: Not handling case $1 -> $2 -> $3" >&2 ;; esac exit 1 -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-24 12:26 ` [PATCH v2 0/3] git-merge-one-file " Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 1/3] git-merge-one-file: style cleanup Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 2/3] git-merge-one-file: send "ERROR:" messages to stderr Kevin Bracey @ 2013-03-24 12:26 ` Kevin Bracey 2013-03-25 17:04 ` Junio C Hamano 2 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 12:26 UTC (permalink / raw) To: git; +Cc: David Aguilar, Kevin Bracey Commit 718135e improved the merge error reporting for the resolve strategy's merge conflict and permission conflict cases, but led to a malformed "ERROR: in myfile.c" message in the case of a file added differently. This commit reverts that change, and uses an alternative approach without this flaw. Signed-off-by: Kevin Bracey <kevin@bracey.fi> --- git-merge-one-file.sh | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 39b7799..e231d20 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -107,10 +107,12 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac + ret=0 src2=$(git-unpack-file $3) case "$1" in '') - echo "Added $4 in both, but differently." + echo "ERROR: Added $4 in both, but differently." >&2 + ret=1 orig=$(git-unpack-file $2) create_virtual_base "$orig" "$src2" ;; @@ -124,11 +126,10 @@ case "${1:-.}${2:-.}${3:-.}" in # would confuse "merge" greatly. src1=$(git-unpack-file $2) git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if test $ret != 0 + if test $? != 0 then - msg='content conflict' + echo "ERROR: Content conflict in $4" >&2 + ret=1 fi # Create the working tree file, using "our tree" version from the @@ -138,21 +139,12 @@ case "${1:-.}${2:-.}${3:-.}" in if test "$6" != "$7" then - if test -n "$msg" - then - msg="$msg, " - fi - msg="${msg}permissions conflict: $5->$6,$7" - ret=1 - fi - if test -z "$1" - then + echo "ERROR: Permissions conflict: $5->$6,$7" >&2 ret=1 fi if test $ret != 0 then - echo "ERROR: $msg in $4" >&2 exit 1 fi exec git update-index -- "$4" -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-24 12:26 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey @ 2013-03-25 17:04 ` Junio C Hamano 2013-03-25 17:17 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-25 17:04 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar Kevin Bracey <kevin@bracey.fi> writes: > Commit 718135e improved the merge error reporting for the resolve > strategy's merge conflict and permission conflict cases, but led to a > malformed "ERROR: in myfile.c" message in the case of a file added > differently. > > This commit reverts that change, and uses an alternative approach without > this flaw. > > Signed-off-by: Kevin Bracey <kevin@bracey.fi> We used to treat "Both added differently" as a separate "info" message, just like the "Auto-merging" message, and let "content conflict" that is an "error" to happen naturally by doing such a merge, possibly followed by permission conflict which is another kind of "error". We coalesced these two into a single message. And this patch breaks them into separate messages. I am not sure if that aspect of the change is desirable. The source of "malformed" message seems suspicious. Isn't the root cause of $msg being empty that merge-file can (sometimes) cleanly merge two files using the phoney base in the "both added differently" codepath? If you resolve that issue by forcing a "conflicted" failure when we handle "add/add" conflict, I think the behaviour of the remainder of the code is better in the original than the updated one. Perhaps something like this (I am applying these on 'maint')? git-merge-one-file.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 25d7714..aa06282 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -107,6 +107,7 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac + add_add_conflict= src2=`git-unpack-file $3` case "$1" in '') @@ -121,6 +122,7 @@ case "${1:-.}${2:-.}${3:-.}" in # If we do not have enough common material, it is not # worth trying two-file merge using common subsections. expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig + add_add_conflict=yes ;; *) echo "Auto-merging $4" @@ -128,15 +130,13 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac - # Be careful for funny filename such as "-L" in "$4", which - # would confuse "merge" greatly. src1=`git-unpack-file $2` - git merge-file "$src1" "$orig" "$src2" - ret=$? - msg= - if test $ret != 0 + + ret=0 msg= + if git merge-file "$src1" "$orig" "$src2" || test -n "$add_add_conflict" then msg='content conflict' + ret=1 fi # Create the working tree file, using "our tree" version from the ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-25 17:04 ` Junio C Hamano @ 2013-03-25 17:17 ` Junio C Hamano 2013-03-25 17:20 ` Junio C Hamano 2013-03-25 19:24 ` Eric Sunshine 0 siblings, 2 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-25 17:17 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar Junio C Hamano <gitster@pobox.com> writes: > Kevin Bracey <kevin@bracey.fi> writes: > >> Commit 718135e improved the merge error reporting for the resolve >> strategy's merge conflict and permission conflict cases, but led to a >> malformed "ERROR: in myfile.c" message in the case of a file added >> differently. >> >> This commit reverts that change, and uses an alternative approach without >> this flaw. >> >> Signed-off-by: Kevin Bracey <kevin@bracey.fi> > > We used to treat "Both added differently" as a separate "info" > message, just like the "Auto-merging" message, and let "content > conflict" that is an "error" to happen naturally by doing such a > merge, possibly followed by permission conflict which is another > kind of "error". We coalesced these two into a single message. > > And this patch breaks them into separate messages. I am not sure if > that aspect of the change is desirable. > > The source of "malformed" message seems suspicious. Isn't the root > cause of $msg being empty that merge-file can (sometimes) cleanly > merge two files using the phoney base in the "both added > differently" codepath? > > If you resolve that issue by forcing a "conflicted" failure when we > handle "add/add" conflict, I think the behaviour of the remainder of > the code is better in the original than the updated one. > > Perhaps something like this (I am applying these on 'maint')? Actually, this one is even better, I think. Again on top of your two patches applied on 'maint'. Alternatively, we can remove the whole "if $1 is empty, error the merge out" logic, which would be more in line with the spirit of f7d24bbefb06 (merge with /dev/null as base, instead of punting O==empty case, 2005-11-07), but that will be a change in behaviour (a "both side added, slightly differently" case that can cleanly merge will no longer fail), so I am not sure if it is worth it. -- >8 -- Subject: [PATCH] merge-one-file: force content conflict for "both side added" case Historically, we tried to be lenient to "both side added, slightly differently" case and as long as the files can be merged using a made-up common ancestor cleanly, since f7d24bbefb06 (merge with /dev/null as base, instead of punting O==empty case, 2005-11-07). This was later further refined to use a better made-up common file with fd66dbf5297a (merge-one-file: use empty- or common-base condintionally in two-stage merge., 2005-11-10), but the spirit has been the same. But the original fix in f7d24bbefb06 to avoid punging on "both sides added" case had a code to unconditionally error out the merge. When this triggers, even though the content-level merge can be done cleanly, we end up not saying "content conflict" in the message, but still issue the error message, showing "ERROR: in <pathname>". Signed-off-by: Junio C Hamano <gitster@pobox.com> --- git-merge-one-file.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 25d7714..62016f4 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -155,6 +155,7 @@ case "${1:-.}${2:-.}${3:-.}" in fi if test -z "$1" then + msg='content conflict' ret=1 fi -- 1.8.2-297-g51e0fcd ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-25 17:17 ` Junio C Hamano @ 2013-03-25 17:20 ` Junio C Hamano 2013-03-25 19:24 ` Eric Sunshine 1 sibling, 0 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-25 17:20 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar Junio C Hamano <gitster@pobox.com> writes: > Actually, this one is even better, I think. Again on top of your > two patches applied on 'maint'. Scratch that one. The "if test -z "$1"" block needs to be moved a bit higher, like this (the log message can stay the same): diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 62016f4..a4ecf33 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -134,9 +134,10 @@ case "${1:-.}${2:-.}${3:-.}" in git merge-file "$src1" "$orig" "$src2" ret=$? msg= - if test $ret != 0 + if test $ret != 0 || test -z "$1" then msg='content conflict' + ret=1 fi # Create the working tree file, using "our tree" version from the @@ -153,11 +154,6 @@ case "${1:-.}${2:-.}${3:-.}" in msg="${msg}permissions conflict: $5->$6,$7" ret=1 fi - if test -z "$1" - then - msg='content conflict' - ret=1 - fi if test $ret != 0 then ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v2 3/3] git-merge-one-file: revise merge error reporting 2013-03-25 17:17 ` Junio C Hamano 2013-03-25 17:20 ` Junio C Hamano @ 2013-03-25 19:24 ` Eric Sunshine 1 sibling, 0 replies; 40+ messages in thread From: Eric Sunshine @ 2013-03-25 19:24 UTC (permalink / raw) To: Junio C Hamano; +Cc: Kevin Bracey, Git List, David Aguilar On Mon, Mar 25, 2013 at 1:17 PM, Junio C Hamano <gitster@pobox.com> wrote: > Subject: [PATCH] merge-one-file: force content conflict for "both side added" case s/both side/both sides/ > Historically, we tried to be lenient to "both side added, slightly Ditto. > differently" case and as long as the files can be merged using a > made-up common ancestor cleanly, since f7d24bbefb06 (merge with > /dev/null as base, instead of punting O==empty case, 2005-11-07). > This was later further refined to use a better made-up common file > with fd66dbf5297a (merge-one-file: use empty- or common-base > condintionally in two-stage merge., 2005-11-10), but the spirit has > been the same. > > But the original fix in f7d24bbefb06 to avoid punging on "both sides s/punging/punting/ > added" case had a code to unconditionally error out the merge. When > this triggers, even though the content-level merge can be done > cleanly, we end up not saying "content conflict" in the message, but > still issue the error message, showing "ERROR: in <pathname>". > > Signed-off-by: Junio C Hamano <gitster@pobox.com> ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-13 1:12 ` [PATCH v3 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2013-03-13 9:03 ` David Aguilar @ 2013-03-13 17:57 ` Junio C Hamano 2013-03-14 6:27 ` Kevin Bracey 1 sibling, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-13 17:57 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Kevin Bracey <kevin@bracey.fi> writes: > Commit 718135e improved the merge error reporting for the resolve > strategy's merge conflict and permission conflict cases, but led to a > malformed "ERROR: in myfile.c" message in the case of a file added > differently. > > This commit reverts that change, and uses an alternative approach without > this flaw. > > Signed-off-by: Kevin Bracey <kevin@bracey.fi> > --- > git-merge-one-file.sh | 20 +++++++------------- > 1 file changed, 7 insertions(+), 13 deletions(-) > > diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh > index 0f164e5..78b07a8 100755 > --- a/git-merge-one-file.sh > +++ b/git-merge-one-file.sh > @@ -104,11 +104,13 @@ case "${1:-.}${2:-.}${3:-.}" in > ;; > esac > > + ret=0 > src1=$(git-unpack-file $2) > src2=$(git-unpack-file $3) > case "$1" in > '') > - echo "Added $4 in both, but differently." > + echo "ERROR: Added $4 in both, but differently." > + ret=1 The problem you identified may be worth fixing, but I do not think this change is correct. This message is at the same severity level as the message on the other arm of this case that says "Auto-merging $4". In that other case arm, we are attempting a true three-way merge, and in this case arm, we are attempting a similar three-way merge using your "virtual base". Neither has found any error in this case arm yet. The messages are both "informational", not an error. I do not think you would want to set ret=1 until you see content conflict. ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-13 17:57 ` [PATCH v3 " Junio C Hamano @ 2013-03-14 6:27 ` Kevin Bracey 2013-03-14 14:56 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-14 6:27 UTC (permalink / raw) To: Junio C Hamano Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen On 13/03/2013 19:57, Junio C Hamano wrote: > Kevin Bracey <kevin@bracey.fi> writes: > >> - echo "Added $4 in both, but differently." >> + echo "ERROR: Added $4 in both, but differently." >> + ret=1 > The problem you identified may be worth fixing, but I do not think > this change is correct. > > This message is at the same severity level as the message on the > other arm of this case that says "Auto-merging $4". In that other > case arm, we are attempting a true three-way merge, and in this case > arm, we are attempting a similar three-way merge using your "virtual > base". > > Neither has found any error in this case arm yet. The messages are > both "informational", not an error. I do not think you would want > to set ret=1 until you see content conflict. I disagree here. At the minute, it does set ret to 1 (but further down the code - bringing it up here next to the "ERROR" print clarifies that), and will report the merge as failed, conflict in the 3-way merge or not. Which I think is correct. We have to stop for user inspection here. We do have a fake base; we can't trust the 3-way merge with it. The virtual 3-way merge will take ABCDE and ABDE and produce ABCDE without conflict. That's flat wrong if the real base they failed to tell Git about was ABCDE. Despite being useful, I'm still slightly uncomfortable that it can produce something without any conflict markers. The user really needs to look at properly. (And one interesting related glitch, or at least thing that puzzled me when it happened. This is from memory, so may be slightly mistaken, but what seemed to happen was that if you have rerere enabled, then mergetool tends to say "nothing to merge", because it relies on "rerere remaining", which relies on conflict markers. I think you could still force a mergetool up by specifying the specific file though.) Maybe the virtual base itself should be different. Maybe it should put a ??????? marker in place of every unique line. So you get: Left ABCEFGH Right XABCDEFJH -> Merge result <|X>ABC<|D>EF<G|J>H VBase ?ABC?EF??H That actually feels like it may be the correct answer here. And it's effectively what P4Merge does in its "2-way" mode I failed to invoke. (At least for the result view). Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-14 6:27 ` Kevin Bracey @ 2013-03-14 14:56 ` Junio C Hamano 2013-03-14 17:31 ` Kevin Bracey 0 siblings, 1 reply; 40+ messages in thread From: Junio C Hamano @ 2013-03-14 14:56 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar, Ciaran Jessup, Scott Chacon, Alex Riesen Kevin Bracey <kevin@bracey.fi> writes: > I disagree here. At the minute, it does set ret to 1 (but further down > the code - bringing it up here next to the "ERROR" print clarifies > that), and will report the merge as failed, conflict in the 3-way > merge or not. Which I think is correct. OK. I agree that forcing users to always inspect the result of "both side added" resolution sounds like a good safety measure. > Maybe the virtual base itself should be different. Maybe it should put > a ??????? marker in place of every unique line. So you get: > > Left ABCEFGH > Right XABCDEFJH -> Merge result <|X>ABC<|D>EF<G|J>H > VBase ?ABC?EF??H > > That actually feels like it may be the correct answer here. Interesting, though the approach has downsides with the diff3 conflict style, no? ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-14 14:56 ` Junio C Hamano @ 2013-03-14 17:31 ` Kevin Bracey 2013-03-14 17:39 ` Kevin Bracey 0 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-14 17:31 UTC (permalink / raw) To: Junio C Hamano Cc: git, David Aguilar <davvid@gmail.com>l Antoine Pelisse, Ciaran Jessup, Jeff King, Uwe Kleine-König, Scott Chacon, Alex Riesen On 14/03/2013 16:56, Junio C Hamano wrote: > Kevin Bracey <kevin@bracey.fi> writes: > >> Maybe the virtual base itself should be different. Maybe it should put >> a ??????? marker in place of every unique line. So you get: >> >> Left ABCEFGH >> Right XABCDEFJH -> Merge result <|X>ABC<|D>EF<G|J>H >> VBase ?ABC?EF??H >> >> That actually feels like it may be the correct answer here. > Interesting, though the approach has downsides with the diff3 > conflict style, no? > Well, yes, but I would assume that we would forcibly select normal diff here somehow, if we aren't already. We should be - turning ABCDEFGH vs ABCD into ABCD<EFGH|EFGH=> is silly. This topic has a lot in common with the zdiff3 discussion going on. The concern there is about large chunks of similar code appearing on two sides, and not being in the base, leading to useless diff3. This is just the special case of the base being totally empty. The thought on zdiff3 philosophy was that common additions should be treated as resolved, and not appear inside conflict markers. That's exactly what we'd be doing. So, same conflict as above, but this time embedded in a larger file, using zdiff3 logic: Left aaaaaabaacaaABCEFGHeee Base aaaaaaaaaaaaeee -> zdiff3 aaada<b|a=f>aacaaABC<|D>EF<G|J>Heee Right aaadaafaaaaaABCDEFJHeee Note that I've chosen to suppress the = marker if the lines surrounding the conflict are not in the base. I think that helps highlight the fact that we're in a diff2 section. EF<G|=J>H reads like an assertion that the base has EFH. Whereas EF<G|J>H avoids that. So, anyway, commonality with zdiff3 would be good. Even if we can't share code, we should at least share the general style of result. Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 3/3] git-merge-one-file: revise merge error reporting 2013-03-14 17:31 ` Kevin Bracey @ 2013-03-14 17:39 ` Kevin Bracey 0 siblings, 0 replies; 40+ messages in thread From: Kevin Bracey @ 2013-03-14 17:39 UTC (permalink / raw) To: Junio C Hamano Cc: git, David Aguilar <davvid@gmail.com>l Antoine Pelisse, Ciaran Jessup, Jeff King, Uwe Kleine-König, Scott Chacon, Alex Riesen On 14/03/2013 19:31, Kevin Bracey wrote: > On 14/03/2013 16:56, Junio C Hamano wrote: >> > Well, yes, but I would assume that we would forcibly select normal > diff here somehow, if we aren't already. We should be - turning > ABCDEFGH vs ABCD into ABCD<EFGH|EFGH=> is silly. Doh. But anyway, we don't want to waste space with |= markers, and make the same "surrounding code is in the base" suggestion. So we should be selecting diff. Kevin ^ permalink raw reply [flat|nested] 40+ messages in thread
* Re: [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 2/3] mergetools/p4merge: create a base if none available Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey @ 2013-03-13 2:05 ` David Aguilar 2013-03-24 11:54 ` [PATCH v4 1/2] " Kevin Bracey 3 siblings, 0 replies; 40+ messages in thread From: David Aguilar @ 2013-03-13 2:05 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, Ciaran Jessup, Scott Chacon, Alex Riesen On Tue, Mar 12, 2013 at 6:12 PM, Kevin Bracey <kevin@bracey.fi> wrote: > Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that > the incoming branch is now in the left-hand, blue triangle pane, and the > current branch is in the right-hand, green circle pane. > > This change makes use of P4Merge consistent with its built-in help, its > reference documentation, and Perforce itself. But most importantly, it > makes merge results clearer. P4Merge is not totally symmetrical between > left and right; despite changing a few text labels from "theirs/ours" to > "left/right" when invoked manually, it still retains its original > Perforce "theirs/ours" viewpoint. > > Most obviously, in the result pane P4Merge shows changes that are common > to both branches in green. This is on the basis of the current branch > being green, as it is when invoked from Perforce; it means that lines in > the result are blue if and only if they are being changed by the merge, > making the resulting diff clearer. > > Note that P4Merge now shows "ours" on the right for both diff and merge, > unlike other diff/mergetools, which always have REMOTE on the right. > But observe that REMOTE is the working tree (ie "ours") for a diff, > while it's another branch (ie "theirs") for a merge. > > Ours and theirs are reversed for a rebase - see "git help rebase". > However, this does produce the desired "show the results of this commit" > effect in P4Merge - changes that remain in the rebased commit (in your > branch, but not in the new base) appear in blue; changes that do not > appear in the rebased commit (from the new base, or common to both) are > in green. If Perforce had rebase, they'd probably not swap ours/theirs, > but make P4Merge show common changes in blue, picking out our changes in > green. We can't do that, so this is next best. > > Signed-off-by: Kevin Bracey <kevin@bracey.fi> > --- This seems sensible to apply. The commit message is a bit long, but I think it's justified since this is exactly the kind of thing I would tend to forget after enough time has passed. Ditto on the create_virtual_base patch. Your latest patch addressed Junio's note about making it take 2 args. FWIW, please feel free to add: Reviewed-by: David Aguilar <davvid@gmail.com> Thanks. > mergetools/p4merge | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/mergetools/p4merge b/mergetools/p4merge > index 8a36916..46b3a5a 100644 > --- a/mergetools/p4merge > +++ b/mergetools/p4merge > @@ -22,7 +22,7 @@ diff_cmd () { > merge_cmd () { > touch "$BACKUP" > $base_present || >"$BASE" > - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" > + "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" > check_unchanged > } > > -- > 1.8.2.rc3.7.g1100d09.dirty > -- David ^ permalink raw reply [flat|nested] 40+ messages in thread
* [PATCH v4 1/2] mergetools/p4merge: swap LOCAL and REMOTE 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey ` (2 preceding siblings ...) 2013-03-13 2:05 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE David Aguilar @ 2013-03-24 11:54 ` Kevin Bracey 2013-03-24 11:54 ` [PATCH v4 2/2] mergetools/p4merge: create a base if none available Kevin Bracey 3 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 11:54 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, David Aguilar, Kevin Bracey Reverse LOCAL and REMOTE when invoking P4Merge as a mergetool, so that the incoming branch is now in the left-hand, blue triangle pane, and the current branch is in the right-hand, green circle pane. This change makes use of P4Merge consistent with its built-in help, its reference documentation, and Perforce itself. But most importantly, it makes merge results clearer. P4Merge is not totally symmetrical between left and right; despite changing a few text labels from "theirs/ours" to "left/right" when invoked manually, it still retains its original Perforce "theirs/ours" viewpoint. Most obviously, in the result pane P4Merge shows changes that are common to both branches in green. This is on the basis of the current branch being green, as it is when invoked from Perforce; it means that lines in the result are blue if and only if they are being changed by the merge, making the resulting diff clearer. Note that P4Merge now shows "ours" on the right for both diff and merge, unlike other diff/mergetools, which always have REMOTE on the right. But observe that REMOTE is the working tree (ie "ours") for a diff, while it's another branch (ie "theirs") for a merge. Ours and theirs are reversed for a rebase - see "git help rebase". However, this does produce the desired "show the results of this commit" effect in P4Merge - changes that remain in the rebased commit (in your branch, but not in the new base) appear in blue; changes that do not appear in the rebased commit (from the new base, or common to both) are in green. If Perforce had rebase, they'd probably not swap ours/theirs, but make P4Merge show common changes in blue, picking out our changes in green. We can't do that, so this is next best. Signed-off-by: Kevin Bracey <kevin@bracey.fi> Reviewed-by: David Aguilar <davvid@gmail.com> --- No change to part 1/2 from previous version, apart from Reviewed-by. Part 2/2 is modified. mergetools/p4merge | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mergetools/p4merge b/mergetools/p4merge index 8a36916..46b3a5a 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -22,7 +22,7 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" $base_present || >"$BASE" - "$merge_tool_path" "$BASE" "$LOCAL" "$REMOTE" "$MERGED" + "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* [PATCH v4 2/2] mergetools/p4merge: create a base if none available 2013-03-24 11:54 ` [PATCH v4 1/2] " Kevin Bracey @ 2013-03-24 11:54 ` Kevin Bracey 2013-03-25 17:47 ` Junio C Hamano 0 siblings, 1 reply; 40+ messages in thread From: Kevin Bracey @ 2013-03-24 11:54 UTC (permalink / raw) To: git; +Cc: Junio C Hamano, David Aguilar, Kevin Bracey Originally, with no base, Git gave P4Merge $LOCAL as a dummy base: p4merge "$LOCAL" "$LOCAL" "$REMOTE" "$MERGED" Commit 0a0ec7bd changed this to: p4merge "empty file" "$LOCAL" "$REMOTE" "$MERGED" to avoid the problem of being unable to save in some circumstances with similar inputs. Unfortunately this approach produces much worse results on differing inputs. P4Merge really regards the blank file as the base, and once you have just a couple of differences between the two branches you end up with one a massive full-file conflict. The 3-way diff is not readable, and you have to invoke "difftool MERGE_HEAD HEAD" manually to get a useful view. The original approach appears to have invoked special 2-way merge behaviour in P4Merge that occurs only if the base filename is "" or equal to the left input. You get a good visual comparison, and it does not auto-resolve differences. (Normally if one branch matched the base, it would autoresolve to the other branch). But there appears to be no way of getting this 2-way behaviour and being able to reliably save. Having base==left appears to be triggering other assumptions. There are tricks the user can use to force the save icon on, but it's not intuitive. So we now follow a suggestion given in the original patch's discussion: generate a virtual base, consisting of the lines common to the two branches. This is the same as the technique used in resolve and octopus merges, so we relocate that code to a shared function. Note that if there are no differences at the same location, this technique can lead to automatic resolution without conflict, combining everything from the 2 files. As with the other merges using this technique, we assume the user will inspect the result before saving. Signed-off-by: Kevin Bracey <kevin@bracey.fi> Reviewed-by: David Aguilar <davvid@gmail.com> --- Minor change from v3: that version moved initialisation of src1 higher up, detaching it from its associated comment. This move was only required by earlier versions, so v4 leaves src1 in its original position. Added Reviewed-by footer. Documentation/git-sh-setup.txt | 6 ++++++ git-merge-one-file.sh | 18 +++++------------- git-sh-setup.sh | 12 ++++++++++++ mergetools/p4merge | 6 +++++- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/Documentation/git-sh-setup.txt b/Documentation/git-sh-setup.txt index 6a9f66d..5d709d0 100644 --- a/Documentation/git-sh-setup.txt +++ b/Documentation/git-sh-setup.txt @@ -82,6 +82,12 @@ get_author_ident_from_commit:: outputs code for use with eval to set the GIT_AUTHOR_NAME, GIT_AUTHOR_EMAIL and GIT_AUTHOR_DATE variables for a given commit. +create_virtual_base:: + modifies the first file so only lines in common with the + second file remain. If there is insufficient common material, + then the first file is left empty. The result is suitable + as a virtual base input for a 3-way merge. + GIT --- Part of the linkgit:git[1] suite diff --git a/git-merge-one-file.sh b/git-merge-one-file.sh index 3373c04..255c07a 100755 --- a/git-merge-one-file.sh +++ b/git-merge-one-file.sh @@ -104,30 +104,22 @@ case "${1:-.}${2:-.}${3:-.}" in ;; esac - src2=`git-unpack-file $3` + src2=$(git-unpack-file $3) case "$1" in '') echo "Added $4 in both, but differently." - # This extracts OUR file in $orig, and uses git apply to - # remove lines that are unique to ours. - orig=`git-unpack-file $2` - sz0=`wc -c <"$orig"` - @@DIFF@@ -u -La/$orig -Lb/$orig $orig $src2 | git apply --no-add - sz1=`wc -c <"$orig"` - - # If we do not have enough common material, it is not - # worth trying two-file merge using common subsections. - expr $sz0 \< $sz1 \* 2 >/dev/null || : >$orig + orig=$(git-unpack-file $2) + create_virtual_base "$orig" "$src2" ;; *) echo "Auto-merging $4" - orig=`git-unpack-file $1` + orig=$(git-unpack-file $1) ;; esac # Be careful for funny filename such as "-L" in "$4", which # would confuse "merge" greatly. - src1=`git-unpack-file $2` + src1=$(git-unpack-file $2) git merge-file "$src1" "$orig" "$src2" ret=$? msg= diff --git a/git-sh-setup.sh b/git-sh-setup.sh index 9cfbe7f..2f78359 100644 --- a/git-sh-setup.sh +++ b/git-sh-setup.sh @@ -249,6 +249,18 @@ clear_local_git_env() { unset $(git rev-parse --local-env-vars) } +# Generate a virtual base file for a two-file merge. Uses git apply to +# remove lines from $1 that are not in $2, leaving only common lines. +create_virtual_base() { + sz0=$(wc -c <"$1") + @@DIFF@@ -u -La/"$1" -Lb/"$1" "$1" "$2" | git apply --no-add + sz1=$(wc -c <"$1") + + # If we do not have enough common material, it is not + # worth trying two-file merge using common subsections. + expr $sz0 \< $sz1 \* 2 >/dev/null || : >"$1" +} + # Platform specific tweaks to work around some commands case $(uname -s) in diff --git a/mergetools/p4merge b/mergetools/p4merge index 46b3a5a..5a608ab 100644 --- a/mergetools/p4merge +++ b/mergetools/p4merge @@ -21,7 +21,11 @@ diff_cmd () { merge_cmd () { touch "$BACKUP" - $base_present || >"$BASE" + if ! $base_present + then + cp -- "$LOCAL" "$BASE" + create_virtual_base "$BASE" "$REMOTE" + fi "$merge_tool_path" "$BASE" "$REMOTE" "$LOCAL" "$MERGED" check_unchanged } -- 1.8.2.rc3.21.g744ac65 ^ permalink raw reply related [flat|nested] 40+ messages in thread
* Re: [PATCH v4 2/2] mergetools/p4merge: create a base if none available 2013-03-24 11:54 ` [PATCH v4 2/2] mergetools/p4merge: create a base if none available Kevin Bracey @ 2013-03-25 17:47 ` Junio C Hamano 0 siblings, 0 replies; 40+ messages in thread From: Junio C Hamano @ 2013-03-25 17:47 UTC (permalink / raw) To: Kevin Bracey; +Cc: git, David Aguilar Kevin Bracey <kevin@bracey.fi> writes: > Minor change from v3: that version moved initialisation of src1 higher up, > detaching it from its associated comment. This move was only required by > earlier versions, so v4 leaves src1 in its original position. The "funny filename" comment was from b539c5e8fbd3 (git-merge-one: new merge world order., 2005-12-07) where the removed code just before that new comment ended with: merge "$4" "$orig" "$src2" (yes, we used to use "merge" program from the RCS suite). The comment refers to one of the bad side effect the old code used to have and warns against such a practice, i.e. it was talking about the code that no longer existed. I think the two-line comment should simply go. Given that, I _think_ it is OK to move the initialization of src1 next to that of src2; that may make the result easier to read. Thanks. ^ permalink raw reply [flat|nested] 40+ messages in thread
end of thread, other threads:[~2013-03-25 19:24 UTC | newest] Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-03-06 20:32 [PATCH 0/2] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-06 20:32 ` [PATCH 1/2] p4merge: swap LOCAL and REMOTE for mergetool Kevin Bracey 2013-03-07 0:36 ` Junio C Hamano 2013-03-07 6:16 ` Kevin Bracey 2013-03-07 7:23 ` Junio C Hamano 2013-03-07 17:14 ` Kevin Bracey 2013-03-07 19:10 ` Junio C Hamano 2013-03-07 19:50 ` David Aguilar 2013-03-07 20:31 ` Junio C Hamano 2013-03-06 20:32 ` [PATCH 2/2] p4merge: create a virtual base if none available Kevin Bracey 2013-03-07 2:23 ` David Aguilar 2013-03-07 6:28 ` Kevin Bracey 2013-03-07 7:25 ` Junio C Hamano 2013-03-07 3:33 ` David Aguilar 2013-03-09 19:20 ` [PATCH v2 0/3] Improve P4Merge mergetool invocation Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 2013-03-09 19:20 ` [PATCH v2 2/3] mergetools/p4merge: create a base if none available Kevin Bracey 2013-03-10 4:55 ` Junio C Hamano 2013-03-09 19:21 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 2/3] mergetools/p4merge: create a base if none available Kevin Bracey 2013-03-13 1:12 ` [PATCH v3 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2013-03-13 9:03 ` David Aguilar 2013-03-24 12:26 ` [PATCH v2 0/3] git-merge-one-file " Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 1/3] git-merge-one-file: style cleanup Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 2/3] git-merge-one-file: send "ERROR:" messages to stderr Kevin Bracey 2013-03-24 12:26 ` [PATCH v2 3/3] git-merge-one-file: revise merge error reporting Kevin Bracey 2013-03-25 17:04 ` Junio C Hamano 2013-03-25 17:17 ` Junio C Hamano 2013-03-25 17:20 ` Junio C Hamano 2013-03-25 19:24 ` Eric Sunshine 2013-03-13 17:57 ` [PATCH v3 " Junio C Hamano 2013-03-14 6:27 ` Kevin Bracey 2013-03-14 14:56 ` Junio C Hamano 2013-03-14 17:31 ` Kevin Bracey 2013-03-14 17:39 ` Kevin Bracey 2013-03-13 2:05 ` [PATCH v3 1/3] mergetools/p4merge: swap LOCAL and REMOTE David Aguilar 2013-03-24 11:54 ` [PATCH v4 1/2] " Kevin Bracey 2013-03-24 11:54 ` [PATCH v4 2/2] mergetools/p4merge: create a base if none available Kevin Bracey 2013-03-25 17:47 ` Junio C Hamano
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.