mbox series

[0/3] rebase: learn --keep-base

Message ID cover.1553354374.git.liu.denton@gmail.com (mailing list archive)
Headers show
Series rebase: learn --keep-base | expand

Message

Denton Liu March 23, 2019, 3:25 p.m. UTC
This series teaches rebase the --keep-base option.

'git rebase --keep-base <upstream>' is equivalent to
'git rebase --onto <upstream>... <upstream>' or
'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .

This seems to be a common case that people (including myself!) run into; I was
able to find these StackOverflow posts about this use case:

* https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
* https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
* https://stackoverflow.com/a/4207357


Denton Liu (3):
  rebase: teach rebase --keep-base
  t3416: test rebase --keep-base
  git-rebase.txt: document --keep-base option

 Documentation/git-rebase.txt     | 12 +++++--
 builtin/rebase.c                 | 25 ++++++++++++--
 t/t3416-rebase-onto-threedots.sh | 57 ++++++++++++++++++++++++++++++++
 3 files changed, 88 insertions(+), 6 deletions(-)

Comments

Junio C Hamano March 24, 2019, 1:15 p.m. UTC | #1
Denton Liu <liu.denton@gmail.com> writes:

> This series teaches rebase the --keep-base option.
>
> 'git rebase --keep-base <upstream>' is equivalent to
> 'git rebase --onto <upstream>... <upstream>' or
> 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
>
> This seems to be a common case that people (including myself!) run
> into; I was able to find these StackOverflow posts about this use
> case:

Since this is 0/3 I won't complain too loudly, but read the above
again while pretending that you didn't know what your initial
motivating example was.  The last three lines does not explain
anything useful to such a reader, and the reader needs to decipher
the two sample commands to guess what you wanted to achieve.

Before "teaches rebase the --keep-base option", you must tell what
you wanted to do with that new feature to attract readers---convince
them your new contribution is worth their time to read over.

If I understand correctly, what "--onto $(git merge-base @{u} HEAD) @{u}"
lets you express is:

	no matter how much progress the upstream has made while I
	was away from the keyboard, I want to rebase the current
	topic on top of the same commit from the upstream, on which
	I based the current iteration of the topic.

I suspect that such a rebase will become no-op without "-i".  Am I
mistaken?  I am not sure if "--keep-base" is useful without "-i".

But of course, it would be useful with "-i", i.e. when you want to
further polish the topic.  You need to give <upstream> to the command
to let it know where their work stops and your work begins,
i.e. letting the command figure out what commits to replay.  But in
such a workflow, you do not want <upstream> to affect on top of what
commit the replayed history is built.  And "keep base" would be a
very direct way to achieve that.
Denton Liu March 25, 2019, 12:04 a.m. UTC | #2
Hi Junio,

On Sun, Mar 24, 2019 at 10:15:31PM +0900, Junio C Hamano wrote:
> Denton Liu <liu.denton@gmail.com> writes:
> 
> > This series teaches rebase the --keep-base option.
> >
> > 'git rebase --keep-base <upstream>' is equivalent to
> > 'git rebase --onto <upstream>... <upstream>' or
> > 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
> >
> > This seems to be a common case that people (including myself!) run
> > into; I was able to find these StackOverflow posts about this use
> > case:
> 
> Since this is 0/3 I won't complain too loudly, but read the above
> again while pretending that you didn't know what your initial
> motivating example was.  The last three lines does not explain
> anything useful to such a reader, and the reader needs to decipher
> the two sample commands to guess what you wanted to achieve.
> 
> Before "teaches rebase the --keep-base option", you must tell what
> you wanted to do with that new feature to attract readers---convince
> them your new contribution is worth their time to read over.
> 
> If I understand correctly, what "--onto $(git merge-base @{u} HEAD) @{u}"
> lets you express is:
> 
> 	no matter how much progress the upstream has made while I
> 	was away from the keyboard, I want to rebase the current
> 	topic on top of the same commit from the upstream, on which
> 	I based the current iteration of the topic.

Thanks for the clarification. I'll try my best to write future cover
letters more clearly.

> 
> I suspect that such a rebase will become no-op without "-i".  Am I
> mistaken?  I am not sure if "--keep-base" is useful without "-i".

It's useful in the case of "-x", although that is a grey area since "-x"
uses interactive machinery internally. Aside from "-x", I can't really
think of a situation where we would use "--keep-base" without "-i".

> 
> But of course, it would be useful with "-i", i.e. when you want to
> further polish the topic.  You need to give <upstream> to the command
> to let it know where their work stops and your work begins,
> i.e. letting the command figure out what commits to replay.  But in
> such a workflow, you do not want <upstream> to affect on top of what
> commit the replayed history is built.  And "keep base" would be a
> very direct way to achieve that.
> 
> 
> 

Thanks,

Denton
Ævar Arnfjörð Bjarmason March 26, 2019, 2:35 p.m. UTC | #3
On Sat, Mar 23 2019, Denton Liu wrote:

> This series teaches rebase the --keep-base option.
>
> 'git rebase --keep-base <upstream>' is equivalent to
> 'git rebase --onto <upstream>... <upstream>' or
> 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
>
> This seems to be a common case that people (including myself!) run into; I was
> able to find these StackOverflow posts about this use case:
>
> * https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
> * https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
> * https://stackoverflow.com/a/4207357

Like with another series of yours I think this would be best squashed
into one patch.

Maybe I've misunderstood this but isn't this like --fork-point except
with just plain "git merge-base" instead of "git merge-base
--fork-point", but then again 2/3 shows multiple base aren't supported,
but merge-base supports that.

I'd find something like the "DISCUSSION ON FORK-POINT MODE" in
git-merge-base helpful with examples of what we'd pick in the various
scenarios, and also if whatever commit this picks was something you
could have "git merge-base" spew out, so you could get what rebase would
do here from other tooling (which maybe is possible, but I'm confused by
the "no multiple bases"...).
Denton Liu March 26, 2019, 5:50 p.m. UTC | #4
Hi Ævar,

On Tue, Mar 26, 2019 at 03:35:34PM +0100, Ævar Arnfjörð Bjarmason wrote:
> 
> On Sat, Mar 23 2019, Denton Liu wrote:
> 
> > This series teaches rebase the --keep-base option.
> >
> > 'git rebase --keep-base <upstream>' is equivalent to
> > 'git rebase --onto <upstream>... <upstream>' or
> > 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
> >
> > This seems to be a common case that people (including myself!) run into; I was
> > able to find these StackOverflow posts about this use case:
> >
> > * https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
> > * https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
> > * https://stackoverflow.com/a/4207357
> 
> Like with another series of yours I think this would be best squashed
> into one patch.

Will do.

> 
> Maybe I've misunderstood this but isn't this like --fork-point except
> with just plain "git merge-base" instead of "git merge-base
> --fork-point", but then again 2/3 shows multiple base aren't supported,
> but merge-base supports that.
> 

--fork-point gets used to determine the _set of_ commits which are to be
rebased, whereas --keep-base (and --onto) determine the base where that
set of commits will be spliced. As a result, these two options cover
orthogonal use-cases.

The reason why --keep-base doesn't support multiple bases for the same
reason that --onto already disallows multiple bases. If we have multiple
bases, how do we determine which one is the "true base" to use? It makes
more sense to error out and let the user manually specify it.

> I'd find something like the "DISCUSSION ON FORK-POINT MODE" in
> git-merge-base helpful with examples of what we'd pick in the various
> scenarios, and also if whatever commit this picks was something you
> could have "git merge-base" spew out, so you could get what rebase would
> do here from other tooling (which maybe is possible, but I'm confused by
> the "no multiple bases"...).

If I'm understanding you correctly then yes, this could be done with
other tooling. See the 0/3 for equivalent commands.

Perhaps I should update the rebase documentation to mention that
--fork-point and --keep-base are orthogonal because it's unclear for
you, it's probably unclear for other users as well.

Thanks,

Denton
Ævar Arnfjörð Bjarmason March 26, 2019, 8:35 p.m. UTC | #5
On Tue, Mar 26 2019, Denton Liu wrote:

> Hi Ævar,
>
> On Tue, Mar 26, 2019 at 03:35:34PM +0100, Ævar Arnfjörð Bjarmason wrote:
>>
>> On Sat, Mar 23 2019, Denton Liu wrote:
>>
>> > This series teaches rebase the --keep-base option.
>> >
>> > 'git rebase --keep-base <upstream>' is equivalent to
>> > 'git rebase --onto <upstream>... <upstream>' or
>> > 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
>> >
>> > This seems to be a common case that people (including myself!) run into; I was
>> > able to find these StackOverflow posts about this use case:
>> >
>> > * https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
>> > * https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
>> > * https://stackoverflow.com/a/4207357
>>
>> Like with another series of yours I think this would be best squashed
>> into one patch.
>
> Will do.
>
>>
>> Maybe I've misunderstood this but isn't this like --fork-point except
>> with just plain "git merge-base" instead of "git merge-base
>> --fork-point", but then again 2/3 shows multiple base aren't supported,
>> but merge-base supports that.
>>
>
> --fork-point gets used to determine the _set of_ commits which are to be
> rebased, whereas --keep-base (and --onto) determine the base where that
> set of commits will be spliced. As a result, these two options cover
> orthogonal use-cases.

Right. After playing with this a bit more though --fork-point is mostly
there, it it does find the same fork point, as evidenced all your tests
(that aren't asserting incompatibility with other options) passing with
this:

    diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh
    index 9c2548423b..ab2d50e69a 100755
    --- a/t/t3416-rebase-onto-threedots.sh
    +++ b/t/t3416-rebase-onto-threedots.sh
    @@ -116,7 +116,7 @@ test_expect_success 'rebase --keep-base master from topic' '
            git checkout topic &&
            git reset --hard G &&

    -       git rebase --keep-base master &&
    +       git rebase $(git merge-base --fork-point master HEAD) &&
            git rev-parse C >base.expect &&
            git merge-base master HEAD >base.actual &&
            test_cmp base.expect base.actual &&
    @@ -140,7 +140,7 @@ test_expect_success 'rebase -i --keep-base master from topic' '
            git reset --hard G &&

            set_fake_editor &&
    -       EXPECT_COUNT=2 git rebase -i --keep-base master &&
    +       EXPECT_COUNT=2 git rebase -i $(git merge-base --fork-point master HEAD) &&
            git rev-parse C >base.expect &&
            git merge-base master HEAD >base.actual &&
            test_cmp base.expect base.actual &&

I've poked at some of this recently in
https://public-inbox.org/git/20190221214059.9195-3-avarab@gmail.com/ as
noted in the feedback there (I haven't gotten around to v2 yet) it's
entirely possible that I haven't understood this at all :)

But it seems to me that this patch/implementation conflates two
unrelated things.

Once is that we use --fork-point to mean that we're going to find the
divergence point with "merge-base --fork-point". This gets you halfway
to where you want to be, i.e. AFAICT the --keep-base and --fork-point
will always find the same commit for "git rebase" and "git rebase
--keep-base". See the "options.restrict_revision = get_fork_point(...)"
part of the code.

The other, which you want to disable, is that --fork-point *also* says
"OK, once we've found the divergence point, let's then rebase it on the
latest upstream. Or in the example above the "master" part of "git
merge-base --fork-point master HEAD".

Shouldn't --keep-base just be implemented in terms of skipping *that*
part, i.e. we find the fork point using the upstream info, but then
don't rebase *on* upstream.

The reason the distinction matters is because with your patch these two
act differently:

    git rebase --keep-base
    git rebase $(git merge-base @{u} HEAD)

The latter will skip work ("Current branch master is up to date"), but
--keep-base will always re-rebase things. There's some cases where
--fork-point does that, which I was trying to address with my linked WIP
patch above.

Whereas the thing you actually want to work is:

    git rebase -i --keep-base
    git rebase -i $(git merge-base @{u} HEAD)

I.e. to have both of those allow you to re-arrange/fixup whatever and
still rebase on the same divergence point with @{u}, and won't run
rebase when there's no work to do unless you give it --force-rebase.

> reason that --onto already disallows multiple bases. If we have multiple
> bases, how do we determine which one is the "true base" to use? It makes
> more sense to error out and let the user manually specify it.

Ah, makes sense.

>> I'd find something like the "DISCUSSION ON FORK-POINT MODE" in
>> git-merge-base helpful with examples of what we'd pick in the various
>> scenarios, and also if whatever commit this picks was something you
>> could have "git merge-base" spew out, so you could get what rebase would
>> do here from other tooling (which maybe is possible, but I'm confused by
>> the "no multiple bases"...).
>
> If I'm understanding you correctly then yes, this could be done with
> other tooling. See the 0/3 for equivalent commands.
>
> Perhaps I should update the rebase documentation to mention that
> --fork-point and --keep-base are orthogonal because it's unclear for
> you, it's probably unclear for other users as well.
>
> Thanks,
>
> Denton
Denton Liu March 26, 2019, 9:30 p.m. UTC | #6
Hi Ævar,

On Tue, Mar 26, 2019 at 09:35:48PM +0100, Ævar Arnfjörð Bjarmason wrote:
> 
> On Tue, Mar 26 2019, Denton Liu wrote:
> 
> > Hi Ævar,
> >
> > On Tue, Mar 26, 2019 at 03:35:34PM +0100, Ævar Arnfjörð Bjarmason wrote:
> >>
> >> On Sat, Mar 23 2019, Denton Liu wrote:
> >>
> >> > This series teaches rebase the --keep-base option.
> >> >
> >> > 'git rebase --keep-base <upstream>' is equivalent to
> >> > 'git rebase --onto <upstream>... <upstream>' or
> >> > 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
> >> >
> >> > This seems to be a common case that people (including myself!) run into; I was
> >> > able to find these StackOverflow posts about this use case:
> >> >
> >> > * https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
> >> > * https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
> >> > * https://stackoverflow.com/a/4207357
> >>
> >> Like with another series of yours I think this would be best squashed
> >> into one patch.
> >
> > Will do.
> >
> >>
> >> Maybe I've misunderstood this but isn't this like --fork-point except
> >> with just plain "git merge-base" instead of "git merge-base
> >> --fork-point", but then again 2/3 shows multiple base aren't supported,
> >> but merge-base supports that.
> >>
> >
> > --fork-point gets used to determine the _set of_ commits which are to be
> > rebased, whereas --keep-base (and --onto) determine the base where that
> > set of commits will be spliced. As a result, these two options cover
> > orthogonal use-cases.
> 
> Right. After playing with this a bit more though --fork-point is mostly
> there, it it does find the same fork point, as evidenced all your tests
> (that aren't asserting incompatibility with other options) passing with
> this:
> 
>     diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh
>     index 9c2548423b..ab2d50e69a 100755
>     --- a/t/t3416-rebase-onto-threedots.sh
>     +++ b/t/t3416-rebase-onto-threedots.sh
>     @@ -116,7 +116,7 @@ test_expect_success 'rebase --keep-base master from topic' '
>             git checkout topic &&
>             git reset --hard G &&
> 
>     -       git rebase --keep-base master &&
>     +       git rebase $(git merge-base --fork-point master HEAD) &&
>             git rev-parse C >base.expect &&
>             git merge-base master HEAD >base.actual &&
>             test_cmp base.expect base.actual &&
>     @@ -140,7 +140,7 @@ test_expect_success 'rebase -i --keep-base master from topic' '
>             git reset --hard G &&
> 
>             set_fake_editor &&
>     -       EXPECT_COUNT=2 git rebase -i --keep-base master &&
>     +       EXPECT_COUNT=2 git rebase -i $(git merge-base --fork-point master HEAD) &&
>             git rev-parse C >base.expect &&
>             git merge-base master HEAD >base.actual &&
>             test_cmp base.expect base.actual &&
> 
> I've poked at some of this recently in
> https://public-inbox.org/git/20190221214059.9195-3-avarab@gmail.com/ as
> noted in the feedback there (I haven't gotten around to v2 yet) it's
> entirely possible that I haven't understood this at all :)
> 
> But it seems to me that this patch/implementation conflates two
> unrelated things.
> 
> Once is that we use --fork-point to mean that we're going to find the
> divergence point with "merge-base --fork-point". This gets you halfway
> to where you want to be, i.e. AFAICT the --keep-base and --fork-point
> will always find the same commit for "git rebase" and "git rebase
> --keep-base". See the "options.restrict_revision = get_fork_point(...)"
> part of the code.

I don't think this is true. The code that --keep-base uses to find the
merge base is get_oid_mb, see the relevant snippet

	if (strstr(options.onto_name, "...")) {
		if (get_oid_mb(options.onto_name, &merge_base) < 0)

whereas the --fork-point code uses get_fork_point, as you mentioned
above. As a result, they don't necessarily refer to the same commit in
the case where upstream is rewound.

> 
> The other, which you want to disable, is that --fork-point *also* says
> "OK, once we've found the divergence point, let's then rebase it on the
> latest upstream. Or in the example above the "master" part of "git
> merge-base --fork-point master HEAD".

Correct, I guess in essence this is what I'm doing.

> 
> Shouldn't --keep-base just be implemented in terms of skipping *that*
> part, i.e. we find the fork point using the upstream info, but then
> don't rebase *on* upstream.
> 
> The reason the distinction matters is because with your patch these two
> act differently:
> 
>     git rebase --keep-base
>     git rebase $(git merge-base @{u} HEAD)
> 
> The latter will skip work ("Current branch master is up to date"), but
> --keep-base will always re-rebase things. There's some cases where
> --fork-point does that, which I was trying to address with my linked WIP
> patch above.

I believe this is desired behaviour. Suppose we have this (modified)
graph from the git-merge-base docs, where B3 was formerly part of
origin/master but it was then rewound:

           ---o---o---B2--o---o---o---B (origin/master)
                   \
                    B3
                     \
                      Derived (local master)

If we run "git rebase --keep-base", we'll get the following graph:

           ---o---o---B2--o---o---o---B (origin/master)
                   \
                    Derived (local master)

which I believe is the desired behaviour (we're abandoning B3 since
upstream abandoned it).

I hope I'm understanding you correctly. Please let me know if I've
misinterpreted anything you've said or if anything I've said is unclear.

Thanks,

Denton

> 
> Whereas the thing you actually want to work is:
> 
>     git rebase -i --keep-base
>     git rebase -i $(git merge-base @{u} HEAD)
> 
> I.e. to have both of those allow you to re-arrange/fixup whatever and
> still rebase on the same divergence point with @{u}, and won't run
> rebase when there's no work to do unless you give it --force-rebase.
> 
> > reason that --onto already disallows multiple bases. If we have multiple
> > bases, how do we determine which one is the "true base" to use? It makes
> > more sense to error out and let the user manually specify it.
> 
> Ah, makes sense.
> 
> >> I'd find something like the "DISCUSSION ON FORK-POINT MODE" in
> >> git-merge-base helpful with examples of what we'd pick in the various
> >> scenarios, and also if whatever commit this picks was something you
> >> could have "git merge-base" spew out, so you could get what rebase would
> >> do here from other tooling (which maybe is possible, but I'm confused by
> >> the "no multiple bases"...).
> >
> > If I'm understanding you correctly then yes, this could be done with
> > other tooling. See the 0/3 for equivalent commands.
> >
> > Perhaps I should update the rebase documentation to mention that
> > --fork-point and --keep-base are orthogonal because it's unclear for
> > you, it's probably unclear for other users as well.
> >
> > Thanks,
> >
> > Denton
Ævar Arnfjörð Bjarmason March 27, 2019, 3:39 p.m. UTC | #7
On Tue, Mar 26 2019, Denton Liu wrote:

> Hi Ævar,
>
> On Tue, Mar 26, 2019 at 09:35:48PM +0100, Ævar Arnfjörð Bjarmason wrote:
>>
>> On Tue, Mar 26 2019, Denton Liu wrote:
>>
>> > Hi Ævar,
>> >
>> > On Tue, Mar 26, 2019 at 03:35:34PM +0100, Ævar Arnfjörð Bjarmason wrote:
>> >>
>> >> On Sat, Mar 23 2019, Denton Liu wrote:
>> >>
>> >> > This series teaches rebase the --keep-base option.
>> >> >
>> >> > 'git rebase --keep-base <upstream>' is equivalent to
>> >> > 'git rebase --onto <upstream>... <upstream>' or
>> >> > 'git rebase --onto $(git merge-base <upstream> HEAD) <upstream>' .
>> >> >
>> >> > This seems to be a common case that people (including myself!) run into; I was
>> >> > able to find these StackOverflow posts about this use case:
>> >> >
>> >> > * https://stackoverflow.com/questions/53234798/can-i-rebase-on-a-branchs-fork-point-without-explicitly-specifying-the-parent
>> >> > * https://stackoverflow.com/questions/41529128/how-do-you-rebase-only-changes-between-two-branches-into-another-branch
>> >> > * https://stackoverflow.com/a/4207357
>> >>
>> >> Like with another series of yours I think this would be best squashed
>> >> into one patch.
>> >
>> > Will do.
>> >
>> >>
>> >> Maybe I've misunderstood this but isn't this like --fork-point except
>> >> with just plain "git merge-base" instead of "git merge-base
>> >> --fork-point", but then again 2/3 shows multiple base aren't supported,
>> >> but merge-base supports that.
>> >>
>> >
>> > --fork-point gets used to determine the _set of_ commits which are to be
>> > rebased, whereas --keep-base (and --onto) determine the base where that
>> > set of commits will be spliced. As a result, these two options cover
>> > orthogonal use-cases.
>>
>> Right. After playing with this a bit more though --fork-point is mostly
>> there, it it does find the same fork point, as evidenced all your tests
>> (that aren't asserting incompatibility with other options) passing with
>> this:
>>
>>     diff --git a/t/t3416-rebase-onto-threedots.sh b/t/t3416-rebase-onto-threedots.sh
>>     index 9c2548423b..ab2d50e69a 100755
>>     --- a/t/t3416-rebase-onto-threedots.sh
>>     +++ b/t/t3416-rebase-onto-threedots.sh
>>     @@ -116,7 +116,7 @@ test_expect_success 'rebase --keep-base master from topic' '
>>             git checkout topic &&
>>             git reset --hard G &&
>>
>>     -       git rebase --keep-base master &&
>>     +       git rebase $(git merge-base --fork-point master HEAD) &&
>>             git rev-parse C >base.expect &&
>>             git merge-base master HEAD >base.actual &&
>>             test_cmp base.expect base.actual &&
>>     @@ -140,7 +140,7 @@ test_expect_success 'rebase -i --keep-base master from topic' '
>>             git reset --hard G &&
>>
>>             set_fake_editor &&
>>     -       EXPECT_COUNT=2 git rebase -i --keep-base master &&
>>     +       EXPECT_COUNT=2 git rebase -i $(git merge-base --fork-point master HEAD) &&
>>             git rev-parse C >base.expect &&
>>             git merge-base master HEAD >base.actual &&
>>             test_cmp base.expect base.actual &&
>>
>> I've poked at some of this recently in
>> https://public-inbox.org/git/20190221214059.9195-3-avarab@gmail.com/ as
>> noted in the feedback there (I haven't gotten around to v2 yet) it's
>> entirely possible that I haven't understood this at all :)
>>
>> But it seems to me that this patch/implementation conflates two
>> unrelated things.
>>
>> Once is that we use --fork-point to mean that we're going to find the
>> divergence point with "merge-base --fork-point". This gets you halfway
>> to where you want to be, i.e. AFAICT the --keep-base and --fork-point
>> will always find the same commit for "git rebase" and "git rebase
>> --keep-base". See the "options.restrict_revision = get_fork_point(...)"
>> part of the code.
>
> I don't think this is true. The code that --keep-base uses to find the
> merge base is get_oid_mb, see the relevant snippet
>
> 	if (strstr(options.onto_name, "...")) {
> 		if (get_oid_mb(options.onto_name, &merge_base) < 0)
>
> whereas the --fork-point code uses get_fork_point, as you mentioned
> above. As a result, they don't necessarily refer to the same commit in
> the case where upstream is rewound.
>
>>
>> The other, which you want to disable, is that --fork-point *also* says
>> "OK, once we've found the divergence point, let's then rebase it on the
>> latest upstream. Or in the example above the "master" part of "git
>> merge-base --fork-point master HEAD".
>
> Correct, I guess in essence this is what I'm doing.
>
>>
>> Shouldn't --keep-base just be implemented in terms of skipping *that*
>> part, i.e. we find the fork point using the upstream info, but then
>> don't rebase *on* upstream.
>>
>> The reason the distinction matters is because with your patch these two
>> act differently:
>>
>>     git rebase --keep-base
>>     git rebase $(git merge-base @{u} HEAD)
>>
>> The latter will skip work ("Current branch master is up to date"), but
>> --keep-base will always re-rebase things. There's some cases where
>> --fork-point does that, which I was trying to address with my linked WIP
>> patch above.
>
> I believe this is desired behaviour. Suppose we have this (modified)
> graph from the git-merge-base docs, where B3 was formerly part of
> origin/master but it was then rewound:
>
>            ---o---o---B2--o---o---o---B (origin/master)
>                    \
>                     B3
>                      \
>                       Derived (local master)
>
> If we run "git rebase --keep-base", we'll get the following graph:
>
>            ---o---o---B2--o---o---o---B (origin/master)
>                    \
>                     Derived (local master)
>
> which I believe is the desired behaviour (we're abandoning B3 since
> upstream abandoned it).
>
> I hope I'm understanding you correctly. Please let me know if I've
> misinterpreted anything you've said or if anything I've said is unclear.

Yeah. I'm still confused, but mainly because I haven't allocated enough
brainpower to try to understand it :)

So yeah, I can believe it's subtly different, would be great to have a
v2 whose docs/tests cover those subtleties, right now (as seen in my
discussion upthread) the tests that are there can identically use the
fork point.

I also wonder if we can holistically think about this UI / how we can
expose different things. E.g. for the times I've needed this and have
manually dug up the fork point I haven't wanted to handle the case of
upstream rewinding, just re-rebase-i on some old base, while still
having upstream tracking info, and for rebase to exit early if there's
nothing to do (similar to if I feed it the fork point as a rev).

>>
>> Whereas the thing you actually want to work is:
>>
>>     git rebase -i --keep-base
>>     git rebase -i $(git merge-base @{u} HEAD)
>>
>> I.e. to have both of those allow you to re-arrange/fixup whatever and
>> still rebase on the same divergence point with @{u}, and won't run
>> rebase when there's no work to do unless you give it --force-rebase.
>>
>> > reason that --onto already disallows multiple bases. If we have multiple
>> > bases, how do we determine which one is the "true base" to use? It makes
>> > more sense to error out and let the user manually specify it.
>>
>> Ah, makes sense.
>>
>> >> I'd find something like the "DISCUSSION ON FORK-POINT MODE" in
>> >> git-merge-base helpful with examples of what we'd pick in the various
>> >> scenarios, and also if whatever commit this picks was something you
>> >> could have "git merge-base" spew out, so you could get what rebase would
>> >> do here from other tooling (which maybe is possible, but I'm confused by
>> >> the "no multiple bases"...).
>> >
>> > If I'm understanding you correctly then yes, this could be done with
>> > other tooling. See the 0/3 for equivalent commands.
>> >
>> > Perhaps I should update the rebase documentation to mention that
>> > --fork-point and --keep-base are orthogonal because it's unclear for
>> > you, it's probably unclear for other users as well.
>> >
>> > Thanks,
>> >
>> > Denton
Junio C Hamano April 1, 2019, 10:45 a.m. UTC | #8
Denton Liu <liu.denton@gmail.com> writes:

>> I suspect that such a rebase will become no-op without "-i".  Am I
>> mistaken?  I am not sure if "--keep-base" is useful without "-i".
>
> It's useful in the case of "-x", although that is a grey area since "-x"
> uses interactive machinery internally. Aside from "-x", I can't really
> think of a situation where we would use "--keep-base" without "-i".

I consider "-x" is a mere sugar-coat around "-i".  What I was
getting at was if we need some mention of the fact in the
documentation (e.g. "the option is accepted but fairly useless
unless you are doing the rebase '-i/-x'").