threads / discuss / 60692

Leveraging --rebase-merges --update-refs mechanism to rebase several branches in one run

Subject: Leveraging --rebase-merges --update-refs mechanism to rebase several branches in one run

## tl;dr

4 messages between Jan 6, 2024 and Jan 7, 2024.

replies: 3people: 2as markdown or json

Yann Dirson· Jan 6, 2024, 19:05 UTC · lore

This idea comes from a repo[1] where I am experimenting with code variants: on one side I have a branch where I add to the core mechanisms, and on the other(s) I have several branches where I experiment with different rendering options.

There are indeed 2 different workflows here:
- improving the variants themselves, where occasionally some fixup or new
  commit for the core branch gets introduced
- adding feature to the core branch, then merging that into each variant,
  where fixups already appear quite regularly

That produces a set closely-related branches with lots of merges, and applying the fixups is a bit tricky.

The "core + 1 variant" case pretty much works out of the box, with --rebase-merges and --update-refs generating a perfect instructions sheet.

But if I was to rebase just one variant while rewriting the core branch, obviously all other variants would still fork off the pre-rewrite core branch, and we'd loose all chances of automating the same work on the other variants.

OTOH, if I get `git-rebase` to generate the instruction sheets for those other variants first, strip them (manually) from the common part, and insert them in the instruction sheet of my "core + 1 variant" case ... I do get the whole of my branches rebased together, and sharing the updated core.

So the question is, would there be any obstacles to let git-rebase automate this completely? By chance it could even be a trivial change? I guess we'd only want this feature to be enabled under certain conditions, like --update-refs being specified so the many heads of the rebase would be reachable.

[1] https://github.com/ydirson/test-yew-tutorial/tree/opr is the "core" branch, and branches opr-* are the variants

Johannes Sixt· Jan 7, 2024, 08:57 UTC · re: Yann Dirson · lore

Re: Leveraging --rebase-merges --update-refs mechanism to rebase several branches in one run

Am 06.01.24 um 20:05 schrieb Yann Dirson:
Show 11 quoted lines
> The "core + 1 variant" case pretty much works out of the box, with --rebase-merges
> and --update-refs generating a perfect instructions sheet.
> 
> But if I was to rebase just one variant while rewriting the core branch, obviously
> all other variants would still fork off the pre-rewrite core branch, and we'd loose
> all chances of automating the same work on the other variants.
> 
> OTOH, if I get `git-rebase` to generate the instruction sheets for those other
> variants first, strip them (manually) from the common part, and insert them in the
> instruction sheet of my "core + 1 variant" case ... I do get the whole of my branches
> rebased together, and sharing the updated core.

Not a complete automation, but... You can merge all variant branches into a temporary branch (or detached HEAD), even if that are merely -s ours merges, and then rebase the temporary branch with --rebase-merges --update-refs. This will generate the instruction sheet that you want. You can remove the final merge instructions (the temporary ones) from the instruction sheet if you do not want them to be executed.

-- Hannes
Yann Dirson· Jan 7, 2024, 11:37 UTC · re: Johannes Sixt · lore

Re: Leveraging --rebase-merges --update-refs mechanism to rebase several branches in one run

Johannes Sixt wrote:
Show 28 quoted lines
> Am 06.01.24 um 20:05 schrieb Yann Dirson:
> > The "core + 1 variant" case pretty much works out of the box, with
> > --rebase-merges
> > and --update-refs generating a perfect instructions sheet.
> > 
> > But if I was to rebase just one variant while rewriting the core
> > branch, obviously
> > all other variants would still fork off the pre-rewrite core
> > branch, and we'd loose
> > all chances of automating the same work on the other variants.
> > 
> > OTOH, if I get `git-rebase` to generate the instruction sheets for
> > those other
> > variants first, strip them (manually) from the common part, and
> > insert them in the
> > instruction sheet of my "core + 1 variant" case ... I do get the
> > whole of my branches
> > rebased together, and sharing the updated core.
> 
> Not a complete automation, but... You can merge all variant branches
> into a temporary branch (or detached HEAD), even if that are merely
> -s
> ours merges, and then rebase the temporary branch with
> --rebase-merges
> --update-refs. This will generate the instruction sheet that you
> want.
> You can remove the final merge instructions (the temporary ones) from
> the instruction sheet if you do not want them to be executed.
Nice idea, and this is indeed automatable for the most part, Q&D PoC below.
There are a few things I can see missing in this PoC:
- removal of the final merge from instruction sheet
  Could be done by wrapping $EDITOR - I'm not particularly fond doing things
  behind the user's back, but I lack better ideas.
- restoration of HEAD
  In the general case it cannot be done from the script, so we would naturally
  want to do that from the instruction sheet?
  While I was at manually removing the final merge, I experimented with changing
  the "reset onto" to "reset <a branch name>", but that resulted in moving HEAD
  to the pre-rebase version of the requested branch.
- When aborting the rebase HEAD still points to the extra merge
  This is indeed a special case of the above, where instruction sheet cannot
  be used, and where the script could help since we won't be in the middle of
  a rebase when git-rebase stops.
  There does not seem to be any documented exit-code protocol to tell the
  git-rebase caller the user aborted.  I guess "HEAD pointing to this commit"
  could be used to identify the abort.

---- 8< ---- git-rebase-batch #!/bin/bash set -e

die() {
    echo >&2 "ERROR: $0: $*"
    exit 1
}
REBASE_OPTS=(--interactive --rebase-merges --update-refs)
# all args before "--" are passed to git-rebase
while [ $# -ge 1 ]; do
    case "$1" in
        --) shift; break;;
        *) REBASE_OPTS+=("$1"); shift;;
    esac
done

[ $# -ge 3 ] || die "need cutting-point and at least 2 refs to rebase" CUT="$1" shift

git checkout --detach "$CUT" git merge -s ours "$@" -m "temporary handle for all rebased branches" git rebase "${REBASE_OPTS[@]}" "$CUT" HEAD

# here we can be in the middle of interactive rebase, cannot perform # any kind of cleanup (which would include restoring HEAD ref to its # original destination) ---- 8< ----

Yann Dirson· Jan 7, 2024, 15:31 UTC · re: Yann Dirson · lore

Interactive rebase doc (Was: Leveraging --rebase-merges --update-refs mechanism to rebase several branches in one run)

Show 56 quoted lines
> Johannes Sixt wrote:
> > Am 06.01.24 um 20:05 schrieb Yann Dirson:
> > > The "core + 1 variant" case pretty much works out of the box,
> > > with
> > > --rebase-merges
> > > and --update-refs generating a perfect instructions sheet.
> > > 
> > > But if I was to rebase just one variant while rewriting the core
> > > branch, obviously
> > > all other variants would still fork off the pre-rewrite core
> > > branch, and we'd loose
> > > all chances of automating the same work on the other variants.
> > > 
> > > OTOH, if I get `git-rebase` to generate the instruction sheets
> > > for
> > > those other
> > > variants first, strip them (manually) from the common part, and
> > > insert them in the
> > > instruction sheet of my "core + 1 variant" case ... I do get the
> > > whole of my branches
> > > rebased together, and sharing the updated core.
> > 
> > Not a complete automation, but... You can merge all variant
> > branches
> > into a temporary branch (or detached HEAD), even if that are merely
> > -s
> > ours merges, and then rebase the temporary branch with
> > --rebase-merges
> > --update-refs. This will generate the instruction sheet that you
> > want.
> > You can remove the final merge instructions (the temporary ones)
> > from
> > the instruction sheet if you do not want them to be executed.
> 
> Nice idea, and this is indeed automatable for the most part, Q&D PoC
> below.
> 
> There are a few things I can see missing in this PoC:
> 
> - removal of the final merge from instruction sheet
> 
>   Could be done by wrapping $EDITOR - I'm not particularly fond doing
>   things
>   behind the user's back, but I lack better ideas.
> 
> - restoration of HEAD
> 
>   In the general case it cannot be done from the script, so we would
>   naturally
>   want to do that from the instruction sheet?
> 
>   While I was at manually removing the final merge, I experimented
>   with changing
>   the "reset onto" to "reset <a branch name>", but that resulted in
>   moving HEAD
>   to the pre-rebase version of the requested branch.

Related to this, I turned to the rebase manpage to get reference information about update-ref, but I could not find anything about it: only --update-refs is described, but this description also only seems to address the non-interactive behavior.

In fact:
- there does not appear to be a reference to the interactive
instruction sheet in the rebase doc, only in the default template
- --interactive only directs the user to "Splitting commits", not to
"interactive mode"
- the "interactive mode" section really looks more like a didactic intro
to interactive rebase than like a reference doc
Would it seem OK to change things as follows?
- move current "interactive mode", "splitting commits", and "rebasing merges"
contents into a new gitrebase(7) guide
- leave in git-rebase(1) only an "interactive mode" with the reference doc
for the instruction sheet, and a pointer to the guide for detailed walkthrough
- selectively move back a few things like --strategy paragraph from
"rebasing merges"
Best regards,
-- 
Yann

← back to recent threads