]> git.ipfire.org Git - thirdparty/git.git/commit - git-rebase.sh
rebase: omit patch-identical commits with --fork-point
authorJohn Keeping <john@keeping.me.uk>
Wed, 16 Jul 2014 19:23:49 +0000 (20:23 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 16 Jul 2014 20:07:40 +0000 (13:07 -0700)
commit1e0dacdbdb751caa5936b6d1510f5e8db4d1ed5f
treeaaceab8c326f0e2b418d16a8e8c46230391db013
parentb6266dc88b1fcc91d084cc9c65e0b0805cf59d55
rebase: omit patch-identical commits with --fork-point

When the `--fork-point` argument was added to `git rebase`, we changed
the value of $upstream to be the fork point instead of the point from
which we want to rebase.  When $orig_head..$upstream is empty this does
not change the behaviour, but when there are new changes in the upstream
we are no longer checking if any of them are patch-identical with
changes in $upstream..$orig_head.

Fix this by introducing a new variable to hold the fork point and using
this to restrict the range as an extra (negative) revision argument so
that the set of desired revisions becomes (in fork-point mode):

git rev-list --cherry-pick --right-only \
$upstream...$orig_head ^$fork_point

This allows us to correctly handle the scenario where we have the
following topology:

    C --- D --- E  <- dev
   /
  B  <- master@{1}
 /
o --- B' --- C* --- D*  <- master

where:
- B' is a fixed-up version of B that is not patch-identical with B;
- C* and D* are patch-identical to C and D respectively and conflict
  textually if applied in the wrong order;
- E depends textually on D.

The correct result of `git rebase master dev` is that B is identified as
the fork-point of dev and master, so that C, D, E are the commits that
need to be replayed onto master; but C and D are patch-identical with C*
and D* and so can be dropped, so that the end result is:

o --- B' --- C* --- D* --- E  <- dev

If the fork-point is not identified, then picking B onto a branch
containing B' results in a conflict and if the patch-identical commits
are not correctly identified then picking C onto a branch containing D
(or equivalently D*) results in a conflict.

This change allows us to handle both of these cases, where previously we
either identified the fork-point (with `--fork-point`) but not the
patch-identical commits *or* (with `--no-fork-point`) identified the
patch-identical commits but not the fact that master had been rewritten.

Reported-by: Ted Felix <ted@tedfelix.com>
Signed-off-by: John Keeping <john@keeping.me.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
git-rebase--am.sh
git-rebase--interactive.sh
git-rebase.sh
t/t3400-rebase.sh