@@ -33,3 +33,9 @@ ours:: merge is always the current branch head. It is meant to be used to supersede old development history of side branches.++rebase::+ This rebases the current branch based on a single head.+ Commits are rewritten as with git-rebase. This doesn't+ produce a merge. The procedure for dealing with conflicts + is the same as with git-rebase.
This would give a handier shortcut iff the rebase goes well, but
the workflow after stopping would be entirely different from the
normal "merge". I am a bit worried about it giving confusion to
the end users.
@@ -0,0 +1,17 @@+#!/bin/sh+#+# Copyright (c) 2007 Tom Clarke+#+# Resolve two trees with rebase++# The first parameters up to -- are merge bases ignore them+whiletest$1!="--";doshift;done+shift++# ignore the first head, it's not needed in a rebase merge+shift++# Give up if we are given two or more remotes -- not handling octopus.+test$#=1||exit2++gitrebase$1||exit2
This code makes rebase strategy to signal the caller that rebase
it punted by exit status 2 when it spots conflicting changes.
At that point, what is the state of the branch tip, the index
and the work tree?
When a merge strategy exits with 1 ("I cannot handle this fully
but here is a partial attempt"), it is expected to leave
something that can be resolved in the working tree to be
committed (iow, do some edit, update-index and the a single
"commit" will conclude the whole "git merge" business).
When the strategy exits with 2 ("I cannot deal with this at
all"), git-merge will rewind the branch, index and the work tree
by calling restorestate to the pristine state (in order to clear
whatever mess the strategy may have created), say "Merge with
strategy rebase failed.", and exits with 2.
And at that point, what can the user do?
The user then can initiate the rebase process again from the
command line (perhaps even with "-i"):
$ git rebase FETCH_HEAD
and deal manually with the incremental conflict resolution.
This needs to be documented a bit more clearly, I think, than
your change in the Documentation/merge-strategies.txt.
But more importantly, the above recovery is possible only if you
abort that failed rebase you did in your strategy module, isn't
it?
Although I haven't tried, I suspect that you need to change the
final "git rebase $1 || exit 2" in your script with something
like:
git rebase "$1" || {
git rebase --abort
exit 2
}
Have you tested conflicting cases to see how well it works and
what the user experience would look like?
@@ -81,11 +82,18 @@ finish () { echo "No merge message -- not updating HEAD" ;; *)- git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1+ case " $wt_strategy " in+ *" $no_update_ref "*)+ ;;+ *)+ git update-ref -m "$rlogm" HEAD "$1" "$head" || exit 1+ ;;+ esac
Is this because a successful rebase strategy already updated the
ref? I would not object from the end user experience point of
view to allow "git merge -s rebase" command, but I suspect the
changes to the merge frontend could to be restructured a bit to
handle this easier to read.
;;
esac
;;
esac
+
case "$1" in
'')
;;
Probably this is a good readability improvement.
quoted hunk
@@ -418,6 +426,16 @@ do ;; esac+ # Check to see if there's a message in a merge type that won't produce a commit + if test $have_message = "t"+ then
That quoting is backwards, isn't it?
Literal "t" is not empty and you know you do not need to quote;
you instead need to quote $have_message, because that could be
empty and will not even be given as a separate token to "test"
command without quoting when empty.
+ case " $strategy " in
+ *" $no_update_ref "*)
You have an unnecessary extra indentation here.
+ echo >&2 "warning: Message is not used for $strategy merge strategy"
+ ;;
+ esac
I had to spend 3 minutes thinking about this; if you had a
comment like "A strategy that updates the ref by itself (iow,
bypassing git-merge) does not give git-merge to record the merge
commit using the given message." here, I did not have to.
From: Tom Clarke <hidden> Date: 2016-06-15 22:43:37
On 10/1/07, Junio C Hamano [off-list ref] wrote:
This would give a handier shortcut iff the rebase goes well, but
the workflow after stopping would be entirely different from the
normal "merge". I am a bit worried about it giving confusion to
the end users.
Thanks for the ample feedback, you raise a number of interesting
issues. I am wondering now if making rebase a merge strategy is really
a good idea. Rebasing is not merging, a difference that could perhaps
be overlooked in the no-conflict scenario, but as you point out, is
glaringly obvious as soon as you have conflicts.
I'm happy to try to address the issues you raised, but I wonder if we
would do better to look back at my original proposal which was to add
a --rebase option to git-pull. git-pull is the main place there I see
need for using a rebase instead of a merge, as anywhere where you
might use git-merge directly, if what you really want is a rebase, you
can just run git-rebase.
-Tom
From: Carl Worth <hidden> Date: 2016-06-15 22:43:37
On Mon, 1 Oct 2007 23:41:56 +0200, "Tom Clarke" wrote:
Thanks for the ample feedback, you raise a number of interesting
issues. I am wondering now if making rebase a merge strategy is really
a good idea. Rebasing is not merging, a difference that could perhaps
be overlooked in the no-conflict scenario, but as you point out, is
glaringly obvious as soon as you have conflicts.
What I think I've always wanted is something like the following
behavior for "git pull":
* Fast forward if possible
* Otherwise, rebase, but only if there are no conflicts at all
* Otherwise, do the merge as normal, (leave conflict markers in
place allowing the user to fix them up and then commit).
Would it be straightforward to turn your rebase merge strategy into
something like the above? And if so, would that address the primary
concerns that Junio raised?
-Carl
From: Tom Clarke <hidden> Date: 2016-06-15 22:43:37
On 10/2/07, Carl Worth [off-list ref] wrote:
What I think I've always wanted is something like the following
behavior for "git pull":
* Fast forward if possible
* Otherwise, rebase, but only if there are no conflicts at all
* Otherwise, do the merge as normal, (leave conflict markers in
place allowing the user to fix them up and then commit).
Would it be straightforward to turn your rebase merge strategy into
something like the above? And if so, would that address the primary
concerns that Junio raised?
Maybe we need a 'pull' strategy' - merge, rebase or <insert name for
strategy you describe above>.
-Tom
From: Shawn O. Pearce <hidden> Date: 2016-06-15 22:43:37
Tom Clarke [off-list ref] wrote:
On 10/2/07, Carl Worth [off-list ref] wrote:
quoted
What I think I've always wanted is something like the following
behavior for "git pull":
* Fast forward if possible
* Otherwise, rebase, but only if there are no conflicts at all
* Otherwise, do the merge as normal, (leave conflict markers in
place allowing the user to fix them up and then commit).
Would it be straightforward to turn your rebase merge strategy into
something like the above? And if so, would that address the primary
concerns that Junio raised?
Maybe we need a 'pull' strategy' - merge, rebase or <insert name for
strategy you describe above>.
`git pull -s <name>` takes any merge strategy that git-merge will
accept for its -s option. There is also the config option of
pull.twohead that indicates what the default merge/pull strategy
should be for a two head merge. Most people don't set this,
letting the code default to 'recursive'.
But I have to agree with (was it Junio who said this?) doing a rebase
in a merge strategy doesn't make sense when conflicts come into play.
It gets confusing fast for the end-user as the conflict resolution
process is different than for a merge. A long time ago I wrote a
git-merge-rebase strategy and gave up on it for basically the same
reason. I posted it to the mailing list and I think Linus said
"Why?!". That was the end of that thread as I wound up agreeing
with him.
Multiple merge strategies can be given (and attempted). A rebase
strategy could be attempted before recursive, and if the rebase
fails but the recursive succeeds then you get (roughly) what is
being described above by Carl. But that still requires a rebase
merge strategy. :-\
--
Shawn.
From: Carl Worth <hidden> Date: 2016-06-15 22:43:37
On Mon, 1 Oct 2007 18:30:50 -0400, "Shawn O. Pearce" wrote:
`git pull -s <name>` takes any merge strategy that git-merge will
accept for its -s option. There is also the config option of
pull.twohead that indicates what the default merge/pull strategy
should be for a two head merge. Most people don't set this,
letting the code default to 'recursive'.
Ah, "pull.twohead". I don't think I ever would have guessed that. (And
I was just about to ask if there was a nice place to find all these
options, but then found it myself on my first guess with "man
git-config". Thanks everyone for writing that!).
But I have to agree with (was it Junio who said this?) doing a rebase
in a merge strategy doesn't make sense when conflicts come into play.
Sure. Rebase alone isn't useful as a complete merge strategy. But a
rebase strategy that simply fails in the face of a conflict,
(deferring to a subsequent merge strategy), could be very useful.
It gets confusing fast for the end-user as the conflict resolution
process is different than for a merge. A long time ago I wrote a
git-merge-rebase strategy and gave up on it for basically the same
reason. I posted it to the mailing list and I think Linus said
"Why?!". That was the end of that thread as I wound up agreeing
with him.
Yes, I thought I recalled seeing a rebase strategy go by in the past,
but I had never gotten around to trying it out. I'll try to do better
on this try.
Multiple merge strategies can be given (and attempted). A rebase
strategy could be attempted before recursive, and if the rebase
fails but the recursive succeeds then you get (roughly) what is
being described above by Carl. But that still requires a rebase
merge strategy. :-\
Yes, this sounds exactly like what I want. So, I put "rebase
recursive" in place as the value for the pull.twohead configuration?
An then make sure that the rebase strategy aborts as "failed" instead
of "conflicted and left for user to resolve"? I saw Junio talking
about return values up above in the thread but didn't pay attention to
details, (2 vs. 1 or something)?
Has anyone tried this rebase then recursive strategy yet? I'm
definitely interested in trying it out, as I think I'd
find it quite nice as a default for pull in my usage.
Though actually I'd like it even more if there was some way to mark a
commit as having been "published" and the rebase strategy would refuse
to rebase published commits. Maybe that's a per-branch
"last-published" reference? I think I'd even like git-push to update
the last-published reference for each pushed branch by default, but
then perhaps have an option to mark a particular remote so that
pushing to that remote doesn't count as publishing.
-Carl
From: J. Bruce Fields <hidden> Date: 2016-06-15 22:43:37
On Mon, Oct 01, 2007 at 03:17:28PM -0700, Carl Worth wrote:
What I think I've always wanted is something like the following
behavior for "git pull":
* Fast forward if possible
* Otherwise, rebase, but only if there are no conflicts at all
* Otherwise, do the merge as normal, (leave conflict markers in
place allowing the user to fix them up and then commit).
Would it be straightforward to turn your rebase merge strategy into
something like the above? And if so, would that address the primary
concerns that Junio raised?
Surely the job of a merge strategy is to take two heads and produce a
single merge commit?
If it's worth automating the steps you describe above, I think it'd be
better to choose an entirely different name for the command.
--b.
From: Johannes Schindelin <hidden> Date: 2016-06-15 22:43:37
Hi,
On Mon, 1 Oct 2007, Shawn O. Pearce wrote:
But I have to agree with (was it Junio who said this?) doing a rebase
in a merge strategy doesn't make sense when conflicts come into play.
In contrast, I think that it makes sense, absolutely. If you asked for
"rebase", you _have_ to know what is coming.
It's all about convenience: in many repos, I just to "git pull", because
there is really only one upstream.
But in one repo, the upstream is svn, and I mistakenly checked in a merge.
Not wanting to know svn deeply, I have no nice way (as I would have with
git) to cover up my mistake. So in this repo, I would have liked to set
branch.master.mergeOptions to '-s rebase'.
Ciao,
Dscho
From: Tom Clarke <hidden> Date: 2016-06-15 22:43:37
On 10/2/07, Johannes Schindelin [off-list ref] wrote:
It's all about convenience: in many repos, I just to "git pull", because
there is really only one upstream.
But in one repo, the upstream is svn, and I mistakenly checked in a merge.
Not wanting to know svn deeply, I have no nice way (as I would have with
git) to cover up my mistake. So in this repo, I would have liked to set
branch.master.mergeOptions to '-s rebase'.
That's a good point, in addition to being able to do a git pull that
uses rebase, it would be useful make this configurable so you can
always safely do 'git pull'.
So it's perhaps the question is whether rebasing should be treated as
a kind of merging, or as an alternative to merging when pulling.
Incidentally, are there any other cases other than pulling where using
rebase as an alternative merge strategy is useful?
-Tom