Paolo Bonzini [off-list ref] writes:
quoted
Because original E' was an amend of E, its log message explained
everything E did and more. You cannot leave that same commit message in
E''. What you did in E was already explained in the history, so now you
would want to talk about the incremental change on top of it when you
desribe E''. For that, replaying of E' must stop to allow you to fix up
the log message.
Yes, I had suggested in the original thread to follow up with a "git
rebase -i" to fix the commit message, because "git-rebase--interactive
--help" did not show a -s option. However, I found out that it does
support it, so it is probably better to use "git rebase -i -s theirs
--onto ..." directly.
Yeah, but that is only about the commit log message. The issue of
recording a wrong tree when commits X and Y exist is not alleviated, is
it?
You mean that I should a) drop the example from git-rebase.1, b)
reword it to clarify it, c) drop the patch completely?
I have to say that the rebase example is too misleading --- unless it is
accompanied by a lot of disclaimers, its risk to give broken result to
people probably is worse than the benefit. I am afraid that we would need
a lot better use case to justify the use of "theirs" than what you wrote.
I have occasionally seen valid situations to use "ours", but I personally
haven't been in a situation that merge using "theirs" is a good solution.
Obviously if you start from a wrong branch, you should be in the situation
that you would want to merge using "theirs", just like when you started
from the right branch and would use "ours", but in practice that never
happened to me as far as I can recall. I am not sure where this asymmetry
comes from.
On the other hand, I've sometimes heard people say "when I get a merge
conflict, I'd want to discard what I did _only in the conflicted part_."
I am not sure if such a conflict resolution makes much sense in practice,
but perhaps people know that their changes are worthless crap anyway, and
do not even care about their work themselves, to the point that they would
rather discard what they did than spend more time to fix them up properly.
Whether that makes sense or not, what they want is different from "theirs"
(which is opposite of "ours"); they want to keep their own changes for
parts that did not conflict, and give up what they did only in the
conflicted part. Perhaps such a kind of mixed conflict resolution should
be supported under the name of "theirs", even though that would make
"ours" and "theirs" _not_ the opposite of each other. I dunno...
Yeah, but that is only about the commit log message. The issue of
recording a wrong tree when commits X and Y exist is not alleviated, is
it?
No, it's not.
On the other hand, I've sometimes heard people say "when I get a merge
conflict, I'd want to discard what I did _only in the conflicted part_."
I am not sure if such a conflict resolution makes much sense in practice,
but perhaps people know that their changes are worthless crap anyway, and
do not even care about their work themselves, to the point that they would
rather discard what they did than spend more time to fix them up properly.
Whether that makes sense or not, what they want is different from "theirs"
(which is opposite of "ours"); they want to keep their own changes for
parts that did not conflict, and give up what they did only in the
conflicted part. Perhaps such a kind of mixed conflict resolution should
be supported under the name of "theirs", even though that would make
"ours" and "theirs" _not_ the opposite of each other. I dunno...
Hmm, anyway you do want to test what this strategy would do --- before
merging. The point of "ours"/"theirs" is AFAICS that they *cannot*
produce broken trees (they can cause you to lose committed stuff if used
carelessly, but the resulting tree is already in some branch and
supposedly has already been tested). So breaking the symmetry would not
be good probably.
I guess I see the reason why "ours" is more useful than "theirs". The
reason is that rebase (and "rebase -i" in particular is in some sense
different from most other git operations. Git workflows are
merge-based, so your checked-out branch is the one where the interesting
stuff is happening; if you wanted a "theirs" merge, you would probably
do it as a "ours" merge in the other branch. Rebase instead is
cherrypicking basically, so "ours" makes no sense (it would just *not*
cherrypick).
(It also explains why I saw a use case for "theirs" -- as a former arch
user, I still tend to think in terms of cherrypicks more than merges).
The correct way to proceed would be something like "git rebase -i --onto
origin/master $(git merge-base origin/master master) master", and then
if you have
A--B--C--X--Y origin/master
\
--C'--D--E master
change
pick C'
pick D
pick E
into
reset C'^
pick --strategy=theirs C'
mark :1
reset origin/master
pick :1
pick D
pick E
Then I guess the correct way to go is to write a custom script that uses
the sequencer to make the rebase scenario less dangerous. You can do
#! /bin/sh
# git-merge-after-amend <branch>
#
# Makes it possible to do a fast-forward merge of <branch>
# into HEAD, assuming that the first diverging commit of <branch>
# is an --amend'ed version of the first diverging commit of HEAD.
us=$(git rev-parse HEAD)
them=$(git rev-parse $1)
base=$(git merge-base $us $them)
(echo reset $base
first=t
git rev-list --reverse $us..$them | while read i do
if test "$first" = t; then
first=
echo pick --strategy=theirs $i
echo mark :1
echo reset $us
echo pick --edit :1
else
echo pick $i
fi
done) | git-sequencer
This script could actually become a merge strategy, so that you could do
git reset --hard origin/master
git merge -s split-first HEAD@{1}
This is maybe a little contrived (what if there are conflits, ecc.), but
I like how it shows git's pluggability.
So, as a result of the discussion, I think that:
1) it can be useful to put the "theirs" strategy into git, especially as
the sequencer (which is cherrypick-based) becomes an important component
of some git porcelain; I would remove the rebase example from my patch
and make it just a power-user option (same as "-s ours").
2) user-defined merge strategies can be useful. So it would make sense
to modify "git-merge" so that it accepts arbitrary merge strategies
instead of just the predefined ones. These would default to disallowing
fast forward and trivial merges. (Possibly, as a safety net, "index",
"base", "file", "one-file", "tree" should be excluded... this in turn
means adding an interface to the commands array in git.c... again, I can
do this -- if it is considered interesting; I'd like to know that in
advance -- after the built-in merge is committed).
3) this scenario giveit would make sense to provide the strategy option
to "git cherry-pick". I can write a patch for "git cherry-pick" if you
are interested, though I'd like to have a hint about what to do with the
short option "-s", which is already taken by "--signoff". The same
thing could be done to the sequencer's pick command, so I'm also CCing
Stephan Beyer about this.
4) A useful option for the sequencer (and possibly for git-rebase) would
be "--batch", ensuring that a single execution of the sequencer does the
entire job. "--edit" would then be changed to mean "ask user to edit
commit message" instead of "stop and let the user amend the commit"; and
if a conflict was found, the sequencer would simply abort and exit with
a non-zero exit status.
Thanks,
Paolo
Paolo Bonzini [off-list ref] writes:
#! /bin/sh
# git-merge-after-amend <branch>
#
# Makes it possible to do a fast-forward merge of <branch>
# into HEAD, assuming that the first diverging commit of <branch>
# is an --amend'ed version of the first diverging commit of HEAD.
Can this strong special case limitation "only the first one can be the
amend" somehow be loosened? Otherwise I suspect it would not be useful as
a general solution.
Junio C Hamano wrote:
Paolo Bonzini [off-list ref] writes:
quoted
#! /bin/sh
# git-merge-after-amend <branch>
#
# Makes it possible to do a fast-forward merge of <branch>
# into HEAD, assuming that the first diverging commit of <branch>
# is an --amend'ed version of the first diverging commit of HEAD.
Can this strong special case limitation "only the first one can be the
amend" somehow be loosened?
Well, the point of the exercise is to split a *single* commit into a
"base" commit (already available, possibly on another branch) and a
"delta" (the amending, transformed into an independent commit whose
parent is the "base"). Indeed you can do that for any commit.
The script uses the "git-merge-base" to compute the "base", and takes
the following commit (on the path to HEAD) as the "delta". That's what
add the restriction. You can definitely make a two-argument variation
that, given arguments "B C" and history
o--B (it is irrelevant if B and C have common parents)
o--o--C--D--E HEAD
makes
A--B--C'--D--E
Even in that case, I would make the script (which anyway is obviously
not meant to be included in git, it's a commodity script) accept both
variations: one-argument to do the special case, and two-arguments to
generically split a commit into a base provided by the user + a delta.
Paolo