On Thu, Jul 14, 2022 at 7:50 AM Derrick Stolee <derrickstolee@xxxxxxxxxx> wrote: > > On 7/12/22 11:37 AM, Junio C Hamano wrote:> "Derrick Stolee via GitGitGadget" <gitgitgadget@xxxxxxxxx> writes: > > This is a tangent, but may serve as some food for thought. > > > > When I queue (or develop myself) a topic that depends on another > > topic, I often do > > > > $ git checkout --detach vX.Y.Z ;# choose an appropriate base > > $ git merge --into derived-topic base-topic > > $ develop develop (or "git am") > > > > which would end up in > > > > vX.Y.Z -----M---A---B---C derived-topic > > / > > base-topic > > > > so that "git log --first-parent --oneline master.." would show the > > commits in the topic plus the fact that it depends on which other > > topic recorded in a single merge commit. A topic that depends on > > two or more topics can be handled the same way. > > > > One good thing about this arrangement, unlike the "totally linear" > > one depicted at the top of your cover letter, is that it is easier > > to rebuild each topic independently and the first-parent view is > > still useful. If you futz with the base topic in a totally linear > > history, "log --decorate" of the derived topic would no longer tell > > you where the old iteration of the base topic ended. > > > > It would be very nice to see the update-ref feature (or something > > like that) makes it easy to deal with such a topology, too. > > Your topology is an interesting one, but --update-refs isn't limited to > linear history. > > (Begin aside) > > One goal of this feature is to make it easier to manage the topics that > are being juggled in friendly forks. For example, git-for-windows/git and > microsoft/git have some topics that evolve version-to-version but might be > cleaned up and sent upstream. Both of these forks use 'git rebase > --rebase-merges=rebase-cousins' when consuming new upstream versions to > keep the merge structure of these new topics. However, we lose the branch > names and need to reconstruct them from the context of the merge commits. > > With --update-refs, we can automatically rewrite the branches that are > included in these individual topics. That might make it simpler to extract > a series to send upstream. > > One test in this series does test such a case with the --rebase-merges > option. > > (End aside) > > Back to your topology, I wonder what your rebase command looks like when > tracking those topics. > > The goal of --update-refs is to help rebase multiple branches at the same > time, and with your example here, it would imply you want to rebase both > dependent topics. > > Before: > > A---B----C---M---Q1---Q2---Q3 <-- refs/heads/Q > \ / > P1--P2--P3 <-- refs/heads/P > > After rebasing both topics simultaneously (with 'git rebase --update-refs > C' while Q is checked out): > > A---B---C---D---P1---P2---P3---Q1---Q2---Q3 > ^ ^ > refs/heads/P refs/heads/Q > > But it seems what you mean to say is to update the merge commit M, which > means that the 'P' branch above has been updated independently of the 'Q' > branch, so we need to update 'Q' after-the-fact. I'm not sure what that > rebase would look like, indepdendent of updating refs. Since this is an aside, I'll take a chance to talk about stuff I'm working on. After git replay --onto main --contained main..Q (where "--contained" seems to be similar to rebase's --update-refs option, in that it assumes all refs pointing to history being rewritten should also be updated), or the more explicit git replay --onto main ^main P Q and assuming 'main' has one additional commit 'D' on top of 'C', you'd see A---B---C---D-----------M---Q1---Q2---Q3 <-- refs/heads/Q \ / P1--P2--P3 <-- refs/heads/P In other words, both P and Q would be replayed but with relative topology preserved. Also, important changes in M (conflict fixups or semantic fixes, etc.) would be preserved -- at least that's the plan. > Do you have an example rebase command that manipulates the commits the > way you want? Then I can better understand how the --update-refs could fit > in with that. (Or maybe the point of your tangent is that there isn't an > option.) This would be nice. > If instead we thought about an example like re-rolling the 'next' branch > entirely on top of the 'master' branch, then we have an example that is > closer to the friendly fork example. (I know this isn't a realistic > scenario since we don't rewrite the commits already merged to 'next', but > it's an interesting stress test.) > > While having 'next' checked out, I ran > > git rebase -i --update-refs --rebase-merges=rebase-cousins master Re-rolling 'next' might not be realistic, but re-rolling 'seen' isn't quite as far fetched. I think it'd be more likely to use no-rebase-cousins, so: git checkout seen && git rebase -i --update-refs [--rebase-merges=no-rebase-cousins] next or git replay -i --contained --keep-base next..seen > and it updated all of the branches currently in the region master..next. > I've attached the output of > > git -c log.excludeDecoration="refs/remotes/*" \ > log --oneline --graph --boundary master..next > > just to show what this looks like. One example that I thought might be useful, is tweaking a single topic in 'seen', and updating 'seen' to reflect those updates. This would be something like git replay --keep-base --first-parent ^next seen topic_branch Which would show you all the commits in the first-line history of next..topic_branch plus the first-line history of next..seen, and let you tweak that todo list.