Sean Whitton writes ("Re: Bug#720177: `git debrebase` UI"):
> Please excuse the limited extent to which I've grokked `git debrebase`.
> Hopefully the questions in this e-mail will help move me along.  If you
> want to see the extent of my understanding you might watch the recording
> of the "git and Debian packaging" BoF from DebConf17, where I attempt to
> explain `git debrebase` when someone asks me a question about it.

I will probably watch that at some other point, but not now because
I'm currently on a train from Stockholm to Goteburg.

> On Tue, Jul 18 2017, Ian Jackson wrote:
> > I think I had imagined to expose A, C and D to the user and to compute
> > the state B on demand during push.  That means that git-debrebase is
> > only required when starting a rebase, or before pushing.  (And if the
> > extra step is forgotten before pushing, the user is stopped by the
> > push ff check.)

I should have given these states names.  Let me pretend I did:

  A. Pushed
        equal to some pushed branch
        (might be in the archive or on a shared git server)

  B. Pushable
        ff of some pushed branch, with additional pseudomerge(s)

  C. Strippped
        pseudomerge stripped, and branch maybe rebased,
        but not currently in the middle of a `git rebase'
        (we might need to remember the old HEAD, at least
        the old HEAD from Pushed or Pushable)

  D. Rebasing
       in the middle of `git rebase'

> > I think I had imagined to expose Pushed, Stripped and Rebasing to
> > the user and to compute the state Pushable on demand during push.
> > That means that git-debrebase is only required when starting a
> > rebase, or before pushing.  (And if the extra step is forgotten
> > before pushing, the user is stopped by the push ff check.)
...
> debrebase needs to warn the user that they should expect to see non-ff
> push errors from git until they finish the debrebase.  It might even
> leave behind a hook so that after the non-ff push error, there could be
> a hint about finishing the debrebase, but that might be too unpleasant
> to implement.

By `finish the debrebase' you mean `turn the branch from Stripped to
Pushed or Pushable by adding a psuedomerge'.

By `during push' I meant `during dgit push'.  But of course in a
post-dsc world, there would only be `git push' so there would have to
be an invocation of `git-debrebase'.  The most natural implementation
seems to me to be `git-debrebase push'.

I don't know what potential hook you are talking about.  I don't think
there is a facility for extending `git push' in this way.

> > I think you are proposing to expose A, B and D to the user and to hide
> > C by somehow always reattaching a pseudomerge after each rebase.  But
> > I don't think git-rebase can do that.
> 
> Why not?

Suppose we are in state Rebasing.  Ie we are in the middle of
`git-rebase' (whether stopped due to -i or a conflict or something).
The user deals with whatever it is, and runs `git-rebase --continue'.

Suppose there are no further reasons to stop.  git-rebase will
generate the linear branch appropriately.  But I am not aware of any
way to cause git-rebase to make an appropriate pseudomerge before
returning control to the user.

git-rebase --preserve-merges is no good, because even aside from the
weirdness mentioned in the BUGS section of git-rebase(1), there is no
way to tell git how the pseudomerge should be generated.

(thoughts)

Hrm.  I guess we could feed git-rebase an `exec' thing in its
instruction list.  This might work, but there is another problem with
the model which tries to hide the state Stripped from the user.

> > Ie, the user might do
> >   git-debrebase -i --autosquash
> 
> I don't understand this command.  In my head, debrebase performs two
> atomic operations: (i) laundering the branch; and (ii) reattaching the
> pseudomerge before push.

I think you mean, it performs, in any one invocation, one of those two
operations.  (i) takes the branch from most states I discuss above to
Stripped and (ii) takes the branch from Stripped to Pushed or
Pushable.

But this is asking the user to do extra typing: they have to run
`git-debrebase launder' before running `git-rebase -i'.  Worse, if
they forget to do so they will get some kind of strange mess where
git-rebase tries to reapply the pseudomerge as a cherry pick.

Better to let the user get into the habit of always saying
`git-debrebase'.  Additionally, `git-debrebase' knows what the correct
rebase point is.  (Assuming the user does not want to rewrite changes
to debian/; if they do they need to take more manual control.)

So in my imagination, git-debrebase is usually a wrapper around
git-rebse which magically knows the right base.

>  So what can `git debrebase -i --autosquash` mean?  Does it mean
> "launder the branch, and then call `git rebase` with the options I
> passed?"

Yes, that is exactly what it means.


Also, as I say, a new upstream rebase needs to be started with
git-debrebase because git-debrebase knows how to construct the new
upstream baseline point, and that needs to be done (essentially)
atomically with starting the patch queue rebase.

So even in your world there is a third dgit operation related to new
upstream versions.  That necessarily has to take us from
Pushed/Pushable (and maybe Stripped) directly to Rebasing.  It only
goes on to Stripped if the rebase onto new upstream was both
noninteractive and 100% successful.


> I'm also confused about what `git debrebase --continue` could mean.
> (ii) will always end the debrebase, but `git rebase --continue` doesn't
> always end the rebase.  Is this another case where debrebase is wrapping
> a plain rebase?

`git-debrebase --continue' is a hypothetical wrapper around
`git-rebase --continue' which arranges to reattach the psuedomerge.
It is (perhaps) needed if we are trying to hide the Stripped state
from the user.

> If I'm on the right lines, it might be unwise to wrap `git rebase`.  Git
> users are pretty good at that command; if we leave them to invoke it,
> they stand a better chance of understanding the whole workflow.  But I'm
> not sure.

That is a plausible argument.  The problem is that git-rebase is a
bit of a footgun - more so in the presence of pseudomerges.


There is another reason why I think it is probably a good idea to keep
the state Stripped as long as possible, and to turn it into
Pushed/Pushable only at the last minute:

Ideally we do not want to generate a complete record of all the user's
rebases in the permanent history.  If we generate one pseudomerge for
each rebase, that is what would happen.

We could try to avoid that by looking to see "whether the previous
branch had been pushed".  But we don't know, of course, where it might
have been pushed.  It might even have been pushed using an ad-hoc rune
to a remote ref without a local tracking branch.  Conversely, it might
have been deliberately pushed, in Stripped state, to a rebasing public
branch.

It seems better to have `git-debrebase push' to combine `make the
psuedomerge and do the push'.  Then state `Pushable' occurs only if
the `git-debrebase push' fails between `git-fetch' and `git-push' and
can be remedied by repeating `git-debrebase push' (or by invoking
`git-push').  The worse case is that we contrive to fail to strip the
unpushed psuedomerge, before making a new pseudomerge on top and
pushing again.


Ian.

-- 
Ian Jackson <[email protected]>   These opinions are my own.

If I emailed you from an address @fyvzl.net or @evade.org.uk, that is
a private address which bypasses my fierce spamfilter.

Reply via email to