Bug#720177: `git debrebase` UI
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
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
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
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
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
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