threads / rfc / 5552

[RFC] Merge strategy 'applyreject'

Subject: [RFC] Merge strategy 'applyreject'

## tl;dr

10 messages between Sep 13, 2006 and Sep 13, 2006.

replies: 9people: 4as markdown or json

Shawn Pearce· Sep 13, 2006, 21:08 UTC · lore
Any thoughts on something like the following?

I was talking with Jakub Narebski on #git today about using a diff/apply pipeline as a merge strategy.

I was talking about implementing this within the merge-recur driver as an alternative to invoking the RCS 'merge' program. The idea would be to take the current branch's file and try to apply the diff of merge_base and the other branch to it. If that has any rejects then try the other direction (apply diff of merge_base and current to other) and leave the user with whichever one resulted in the smallest number of rejected lines.

But that's a little bit more work, this is a quick hack.  :-)  

-- >8 -- Create merge strategy 'applyreject'.

The applyreject merge strategy is a two head merge strategy which performs the merge by obtaining the diff between the common base and the branch being merged and applies it to the current branch using git-apply --reject. Consequently any failures are written to .rej files, rather than using the RCS <<<<<<< ======= >>>>>>> format.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .gitignore               |    1 +
 Makefile                 |    1 +
 git-merge-applyreject.sh |   26 ++++++++++++++++++++++++++
 git-merge.sh             |    2 +-
 4 files changed, 29 insertions(+), 1 deletions(-)
diff --git a/.gitignore b/.gitignore
index 0d608fe..0f43ece 100644
--- a/.gitignore
+++ b/.gitignore
@@ -56,6 +56,7 @@ git-ls-tree
 git-mailinfo
 git-mailsplit
 git-merge
+git-merge-applyreject
 git-merge-base
 git-merge-index
 git-merge-tree
diff --git a/Makefile b/Makefile
index 7b3114f..a57dab5 100644
--- a/Makefile
+++ b/Makefile
@@ -161,6 +161,7 @@ SCRIPT_SH = \
 	git-tag.sh git-verify-tag.sh \
 	git-applymbox.sh git-applypatch.sh git-am.sh \
 	git-merge.sh git-merge-stupid.sh git-merge-octopus.sh \
+	git-merge-applyreject.sh \
 	git-merge-resolve.sh git-merge-ours.sh \
 	git-lost-found.sh git-quiltimport.sh
 
diff --git a/git-merge-applyreject.sh b/git-merge-applyreject.sh
new file mode 100755
index 0000000..e4c8703
--- /dev/null
+++ b/git-merge-applyreject.sh
@@ -0,0 +1,26 @@
+#!/bin/sh
+#
+# Simple merge strategy which produces reject files on failed merges.
+# Only handles two heads and one merge base, thus the command line
+# parameters must be:  base -- head1 head2
+
+base="$1"; shift; [ -z "$base" ] && exit 2
+while [ $# -gt 2 -a "X$1" != "X--" ]
+do
+	shift
+done
+if [ "X$1" = "X--" ]
+then
+	shift
+else
+	exit 2
+fi
+current="$1"; shift; [ -z "$current" ] && exit 2
+incoming="$1"; shift; [ -z "$incoming" ] && exit 2
+[ $# -gt 0 ] && exit 2
+
+git-read-tree --reset $current || exit 2
+git-update-index --refresh 2>/dev/null
+git-diff --binary -M $base $incoming \
+	| git-apply --index --reject --verbose
+[ $? = 0 ] || exit 1
diff --git a/git-merge.sh b/git-merge.sh
index d049e16..e39de0a 100755
--- a/git-merge.sh
+++ b/git-merge.sh
@@ -9,7 +9,7 @@ USAGE='[-n] [--no-commit] [--squash] [-s
 LF='
 '
 
-all_strategies='recursive recur octopus resolve stupid ours'
+all_strategies='recursive recur octopus resolve stupid ours applyreject'
 case "${GIT_USE_RECUR_FOR_RECURSIVE}" in
 '')
 	default_twohead_strategies=recursive ;;
-- 
1.4.2.gc52f
Petr Baudis· Sep 13, 2006, 21:16 UTC · re: Shawn Pearce · lore

Re: [RFC] Merge strategy 'applyreject'

Dear diary, on Wed, Sep 13, 2006 at 11:08:17PM CEST, I got a letter where Shawn Pearce <spearce@spearce.org> said that...

Show 7 quoted lines
> Create merge strategy 'applyreject'.
> 
> The applyreject merge strategy is a two head merge strategy which performs
> the merge by obtaining the diff between the common base and the branch
> being merged and applies it to the current branch using git-apply --reject.
> Consequently any failures are written to .rej files, rather than using
> the RCS <<<<<<< ======= >>>>>>> format.

So, it's essentially the same as the classic resolve strategy, just handling rejects differently? I think that should be more obvious from its name, perhaps resolve-rej?

.rej files, what a nuisance to handle those... :)
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Snow falling on Perl. White noise covering line noise.
Hides all the bugs too. -- J. Putnam
Junio C Hamano· Sep 13, 2006, 21:43 UTC · re: Petr Baudis · lore

Re: [RFC] Merge strategy 'applyreject'

Petr Baudis <pasky@suse.cz> writes:
Show 15 quoted lines
> Dear diary, on Wed, Sep 13, 2006 at 11:08:17PM CEST, I got a letter
> where Shawn Pearce <spearce@spearce.org> said that...
>> Create merge strategy 'applyreject'.
>> 
>> The applyreject merge strategy is a two head merge strategy which performs
>> the merge by obtaining the diff between the common base and the branch
>> being merged and applies it to the current branch using git-apply --reject.
>> Consequently any failures are written to .rej files, rather than using
>> the RCS <<<<<<< ======= >>>>>>> format.
>
> So, it's essentially the same as the classic resolve strategy, just
> handling rejects differently? I think that should be more obvious from
> its name, perhaps resolve-rej?
>
> .rej files, what a nuisance to handle those... :)
You were who asked for "apply --reject", weren't you?

I am not interested in this merge strategy myself. Having said that, if it is cleanly done, I do not have much objection adding it for other people's use, at least in principle.

Shawn Pearce· Sep 13, 2006, 21:50 UTC · re: Junio C Hamano · lore

Re: [RFC] Merge strategy 'applyreject'

Junio C Hamano <junkio@cox.net> wrote:
Show 23 quoted lines
> Petr Baudis <pasky@suse.cz> writes:
> 
> > Dear diary, on Wed, Sep 13, 2006 at 11:08:17PM CEST, I got a letter
> > where Shawn Pearce <spearce@spearce.org> said that...
> >> Create merge strategy 'applyreject'.
> >> 
> >> The applyreject merge strategy is a two head merge strategy which performs
> >> the merge by obtaining the diff between the common base and the branch
> >> being merged and applies it to the current branch using git-apply --reject.
> >> Consequently any failures are written to .rej files, rather than using
> >> the RCS <<<<<<< ======= >>>>>>> format.
> >
> > So, it's essentially the same as the classic resolve strategy, just
> > handling rejects differently? I think that should be more obvious from
> > its name, perhaps resolve-rej?
> >
> > .rej files, what a nuisance to handle those... :)
> 
> You were who asked for "apply --reject", weren't you?
> 
> I am not interested in this merge strategy myself.  Having said
> that, if it is cleanly done, I do not have much objection adding
> it for other people's use, at least in principle.

I'll clean it up, document it and and resubmit the patch if others want it as a top-level merge strategy.

But I don't really want this as a merge strategy in its own right. I want it as part of merge-recur, so I can drop into my .git/config file:

	[merge-recursive]
		conflictFormat = rejects

(for example) and not deal with the RCS merge program. This however will require some hacking in merge-recursive.c and apply.c but I think its workable.

-- 
Shawn.
Jakub Narebski· Sep 13, 2006, 21:54 UTC · re: Shawn Pearce · lore

Re: [RFC] Merge strategy 'applyreject'

Shawn Pearce wrote:
> But I don't really want this as a merge strategy in its own right.
> I want it as part of merge-recur (...)

Wouldn't it be better to have pluggable way to deal with conflicts, be it diff3/merge with conflict markers, .rej files, or invoking graphical merge tool (vimdiff, Emacs Emerge, xxdiff, Meld, KDiff3)?

-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Shawn Pearce· Sep 13, 2006, 22:26 UTC · re: Jakub Narebski · lore

Re: [RFC] Merge strategy 'applyreject'

Jakub Narebski <jnareb@gmail.com> wrote:
Show 8 quoted lines
> Shawn Pearce wrote:
> 
> > But I don't really want this as a merge strategy in its own right.
> > I want it as part of merge-recur (...)
> 
> Wouldn't it be better to have pluggable way to deal with conflicts,
> be it diff3/merge with conflict markers, .rej files, or invoking
> graphical merge tool (vimdiff, Emacs Emerge, xxdiff, Meld, KDiff3)?
Yes.  :-)

Right now I think the user could just "plug in" their own "merge" program earlier in PATH than the real one. :-)

It would be nice to get the speed of being able to just run the xdiff code and the Git apply code directly on the file blobs in memory, without forking, but I think pluggable file content merging programs is a very good idea, for lots of different reasons.

-- 
Shawn.
Petr Baudis· Sep 13, 2006, 21:50 UTC · re: Junio C Hamano · lore

Re: [RFC] Merge strategy 'applyreject'

Dear diary, on Wed, Sep 13, 2006 at 11:43:04PM CEST, I got a letter where Junio C Hamano <junkio@cox.net> said that...

> Petr Baudis <pasky@suse.cz> writes:
> > .rej files, what a nuisance to handle those... :)
> 
> You were who asked for "apply --reject", weren't you?

Yes, but the point of that was obviously different. (It's a nuisance, but only when compared to the conflict markers (yes, a matter of opinion of course).)

Thanks for it, BTW!
-- 
				Petr "Pasky" Baudis
Stuff: http://pasky.or.cz/
Snow falling on Perl. White noise covering line noise.
Hides all the bugs too. -- J. Putnam
Shawn Pearce· Sep 13, 2006, 21:46 UTC · re: Petr Baudis · lore

Re: [RFC] Merge strategy 'applyreject'

Petr Baudis <pasky@suse.cz> wrote:
Show 13 quoted lines
> Dear diary, on Wed, Sep 13, 2006 at 11:08:17PM CEST, I got a letter
> where Shawn Pearce <spearce@spearce.org> said that...
> > Create merge strategy 'applyreject'.
> > 
> > The applyreject merge strategy is a two head merge strategy which performs
> > the merge by obtaining the diff between the common base and the branch
> > being merged and applies it to the current branch using git-apply --reject.
> > Consequently any failures are written to .rej files, rather than using
> > the RCS <<<<<<< ======= >>>>>>> format.
> 
> So, it's essentially the same as the classic resolve strategy, just
> handling rejects differently? I think that should be more obvious from
> its name, perhaps resolve-rej?

Unfortunately. More ideally it would be a configurable feature of merge-recur that gets used rather than invoking the RCS merge. This is just a quick and dirty 3 line shell script to propose the concept.

> .rej files, what a nuisance to handle those... :)
A matter of opinion. :)
-- 
Shawn.
Jakub Narebski· Sep 13, 2006, 21:22 UTC · re: Shawn Pearce · lore

Re: [RFC] Merge strategy 'applyreject'

Shawn Pearce wrote:
Show 8 quoted lines
> -- >8 --
> Create merge strategy 'applyreject'.
> 
> The applyreject merge strategy is a two head merge strategy which performs
> the merge by obtaining the diff between the common base and the branch
> being merged and applies it to the current branch using git-apply --reject.
> Consequently any failures are written to .rej files, rather than using
> the RCS <<<<<<< ======= >>>>>>> format.
Nice.
Show 6 quoted lines
> ---
>  .gitignore               |    1 +
>  Makefile                 |    1 +
>  git-merge-applyreject.sh |   26 ++++++++++++++++++++++++++
>  git-merge.sh             |    2 +-
>  4 files changed, 29 insertions(+), 1 deletions(-)
But where documentation (Documentation/merge-strategies.txt)? 
Show 5 quoted lines
> +#!/bin/sh
> +#
> +# Simple merge strategy which produces reject files on failed merges.
> +# Only handles two heads and one merge base, thus the command line
> +# parameters must be:  base -- head1 head2

We can always get the base using git-merge-base, so the arguments could be either "base -- head1 head2", or just "head1 head2".

Does "git pull -s applyreject . head2" works (when on head1) with this patch? Does the unified driver git-merge works correctly?

> +git-diff --binary -M $base $incoming \
> +     | git-apply --index --reject --verbose
--index or --cached?
-- 
Jakub Narebski
Warsaw, Poland
ShadeHawk on #git
Shawn Pearce· Sep 13, 2006, 21:38 UTC · re: Jakub Narebski · lore

Re: [RFC] Merge strategy 'applyreject'

Jakub Narebski <jnareb@gmail.com> wrote:
Show 8 quoted lines
> > ---
> >  .gitignore               |    1 +
> >  Makefile                 |    1 +
> >  git-merge-applyreject.sh |   26 ++++++++++++++++++++++++++
> >  git-merge.sh             |    2 +-
> >  4 files changed, 29 insertions(+), 1 deletions(-)
> 
> But where documentation (Documentation/merge-strategies.txt)? 
If its interesting I'll document it.  I just threw it together and
tossed it out there to see what others thought of the general idea.
 
Show 8 quoted lines
> > +#!/bin/sh
> > +#
> > +# Simple merge strategy which produces reject files on failed merges.
> > +# Only handles two heads and one merge base, thus the command line
> > +# parameters must be:  base -- head1 head2
> 
> We can always get the base using git-merge-base, so the arguments could
> be either "base -- head1 head2", or just "head1 head2".
Actually the merge driver (git-merge.sh) feeds us the arguments like
that.
 
> Does "git pull -s applyreject . head2" works (when on head1) with
> this patch? Does the unified driver git-merge works correctly?
Yes.  That's how I tested it.
> > +git-diff --binary -M $base $incoming \
> > +     | git-apply --index --reject --verbose
> 
> --index or --cached?

I believe that --index is correct. I want to patch the file in the working directory, not the one that's currently in the index. I also want to update the index if the patch applied cleanly.

-- 
Shawn.

← back to recent threads