Bug#720177: `git debrebase` UI

2018-04-04 Thread Sean Whitton
Hello,

Just re-reading our older discussions about the UI, now that I
understand git-debrebase a lot better.

On Sat, Sep 02 2017, Sean Whitton wrote:

> I think that my concerns about failing to leverage user's existing
> understanding of git-rebase(1) can be answered by doing the following:
>
>   - state that git-debrebase(1) is ONLY: a wrapper around git-rebase(1)
> that magically knows the base
>   - have ALL arguments to git-debrebase(1) get passed straight to
> git-rebase(1), i.e., no subsubcommands
>   - move the other functionality (`git debrebase push`, new upstream
> version command) to other subcommands of `git`, e.g. `git
> debpush`, `git debnewupstream` etc.
>
> The point of this is to make it much easier to get a grip on exactly
> what `git debrebase` does.  That is a foundational piece of
> understanding of the workflows surrouding these tools.
>
> It might seem inelegant to have multiple subcommands (especially `git
> debpush` which sounds almost like `dgit push`) but I think that it's a
> price worth paying.  There's also a mnemonic at work: "ah, `git
> debrebase` is a wrapper around `git rebase`, and `git debpush` is a
> wrapper around `git push`".

I think there's still something to this argument against git-debrebase
having subcommands, but it's probably mitigated by the current content
of dgit-maint-debrebase(7).

If we find that users really struggle with grokking the workflow, we
might reconsider splitting out subcommands in the future, after talking
to them and trying to determine whether my hunch in the quoted message
is right.

-- 
Sean Whitton


signature.asc
Description: PGP signature


Bug#720177: `git debrebase` UI

2017-09-02 Thread Sean Whitton
Hello Ian,

Your explanations in the e-mail to which I'm replying helped me a lot --
thanks.

On Tue, Aug 22 2017, Ian Jackson wrote:

>> 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'.

Yes.

> 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.

.git/hooks/pre-push.sample seems to be the place.

>> > 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.
> [...]
>> 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.

I think that my concerns about failing to leverage user's existing
understanding of git-rebase(1) can be answered by doing the following:

  - state that git-debrebase(1) is ONLY: a wrapper around git-rebase(1)
that magically knows the base
  - have ALL arguments to git-debrebase(1) get passed straight to
git-rebase(1), i.e., no subsubcommands
  - move the other functionality (`git debrebase push`, new upstream
version command) to other subcommands of `git`, e.g. `git
debpush`, `git debnewupstream` etc.

The point of this is to make it much easier to get a grip on exactly
what `git debrebase` does.  That is a foundational piece of
understanding of the workflows surrouding these tools.

It might seem inelegant to have multiple subcommands (especially `git
debpush` which sounds almost like `dgit push`) but I think that it's a
price worth paying.  There's also a mnemonic at work: "ah, `git
debrebase` is a wrapper around `git rebase`, and `git debpush` is a
wrapper around `git push`".

>> 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 

Bug#720177: `git debrebase` UI

2017-08-22 Thread Ian Jackson
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 cal

Bug#720177: `git debrebase` UI

2017-08-19 Thread Sean Whitton
Hello Ian,

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.

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.)

Good point that they would be warned by git's standard checks.

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.

> 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?

> This means the user would have to use `git-debrebase --continue'.  If
> they ran `git-rebase --continue' instead they would end up in the
> to-them-anomalous state C.  This would not show up in `git status'
> (because `git status' is not extensible).
>
>> In the case of a debrebase, there will never be any conflicts to
>> resolve,
>
> This is not true for upstream changes.  It is also not true if the
> user used fixup! and --autosquash, or something.
>
> 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.  So what can `git debrebase -i --autosquash`
mean?  Does it mean "launder the branch, and then call `git rebase` with
the options I passed?"

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?

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.

> The other reason to expose this state to the user is that it is one
> that many other git tools already understand.  If the user wants to
> try to use stg or gbp pq or god-knows-what, they need a branch without
> merges.
>
>
> Also: there is more.
>
> Much of the code in git-debrebase will be useful for downstreams too.
> In particular, the automatic pseudomerge handling and perhaps the
> stripping of debian/patches.
>
> I have one person already trying to do rebase-with-pseudomerges as a
> downstream.

I just read the IRC log you posted in another bug; thanks for that.

-- 
Sean Whitton


signature.asc
Description: PGP signature


Bug#720177: `git debrebase` UI

2017-07-18 Thread Ian Jackson
Sean Whitton writes ("Bug#720177: `git debrebase` UI"):
> I'm working my way through NOTES.git-debrebase-pseudomergehandling.

I think it might be useful to think about possible states of the
user's tree:

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

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

C. pseudomerge stripped, and branch maybe rebased,
   but not currently rebasing
 (we might need to remember the old HEAD, at least
 the old HEAD from A or B)

D. rebasing

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 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.  This means the user would
have to use `git-debrebase --continue'.  If they ran
`git-rebase --continue' instead they would end up in the
to-them-anomalous state C.  This would not show up in `git status'
(because `git status' is not extensible).

> In the case of a debrebase, there will never be any conflicts to
> resolve,

This is not true for upstream changes.  It is also not true if the
user used fixup! and --autosquash, or something.

Ie, the user might do
  git-debrebase -i --autosquash

git-debrebase is magic in that it can figure out the base
automatically.

> How about calling (2) immediately after (1) -- and if there is a clean
> way of doing it, after (3), too?  That way, the user can conceptualise
> the debrebase operation as "make the history into a nice patch series,
> and use a bit of magic to ensure that this is still fast-forwarding".
> They don't have to try to understand the state before the final
> pseudomerge is back on top.

The other reason to expose this state to the user is that it is one
that many other git tools already understand.  If the user wants to
try to use stg or gbp pq or god-knows-what, they need a branch without
merges.


Also: there is more.

Much of the code in git-debrebase will be useful for downstreams too.
In particular, the automatic pseudomerge handling and perhaps the
stripping of debian/patches.

I have one person already trying to do rebase-with-pseudomerges as a
downstream.  We will need way way for the user to tell git-debrebase
"who" they are in this sense.  This is because a Debian maintainer
wants to maintain the git-debrebase breakwater branch, ie use a
merging structure for Debian packaging changes, and bubble
changes-to-upstream to the top.  But a downstream wants a single stack
without such nonsense.

I was thinking that gitish downstreams would use `git-ffrebase' which
would have no Debian-specific knowledge.  The downside of this is that
it would have contents in debian/patches/ which would be a snare and a
delusion.

Ian.



Bug#720177: `git debrebase` UI

2017-07-17 Thread Sean Whitton
Hello Ian,

I'm working my way through NOTES.git-debrebase-pseudomergehandling.

ISTM from your notes that the script will need four user subcommand:

1. strip pseudomerges and cleanup the branch, i.e., start or continue a
   debrebase

2. finish a debrebase by pseudo-merging the remote interchange branch

   This is what the `git debrebase prep-push` hook would do, but the
   user needs to be able to make it happen in order that they can
   publish a branch that fast-forwards from the result of `dgit clone`,
   without doing an upload.

3. start a `git rebase` onto a new upstream version

4. special command to protect pseudomerges that the user wants to keep

Users normally think of rebases as operations that are first started,
potentially interrupted by conflicts, and then finished.  We are fine
with (3), because this is just a wrapper around git-rebase(1) and users
know how to deal with its --continue, --skip and --abort options.

In the case of a debrebase, there will never be any conflicts to
resolve, but until (2) has occurred, the result strikes the user as
unfinished.  The workflow was sold to them as producing something that
is a ff of the interchange branch, but it isn't a ff of the interchange
branch yet.  They wonder "did I forget a --continue somewhere?"

How about calling (2) immediately after (1) -- and if there is a clean
way of doing it, after (3), too?  That way, the user can conceptualise
the debrebase operation as "make the history into a nice patch series,
and use a bit of magic to ensure that this is still fast-forwarding".
They don't have to try to understand the state before the final
pseudomerge is back on top.

-- 
Sean Whitton


signature.asc
Description: PGP signature