Unfortunately,
git rebase
just doesn't cut it for this. A while back I wrote git rebase-tree
that would rebase a whole branched tree from one root to another (bringing all the branches along with), but it had a black eye in conflict handling, requiring a prompt for "continue/skip/abort". So I would need to open up a second terminal to git status
and resolve the conflict, etc (or more typically, run git conflicts
in emacs).
I had been meaning to redo git rebase-tree
with its own --continue
flag, but my experience with another custom function (git diff-mail
, which I use at work to prevent the changelist mailer from counting all the earlier changes that were already counted in a previous changelist) taught me that this can cause problems, as I often needed to git rebase --continue; diff-mail --continue
, plus --abort
often got confusing and sometimes actually clobbered my real changes (fortunately they've been easy to reconstruct so far). But it occurred to me that git rebase
already has a queue, and with some clever manipulation, I can make it do what I want.
Enter
git ir
.
This function takes a list of branches, a commit to rebase them onto, and optionally a commit to rebase them from (in case they're already on top of the destination). It sets up an interactive rebase session but completely ignores the plan
git
prepares, instead using its own plan that includes a few additional commands in the rebase plan.
# Extended Commands: # !, exec! = mandatory command (the rest of the line), reinserted on failure # b, branch = sets the named branch to the current commit # (, push = pushes the current commit onto the stack # ), pop = pops the current commit from the stackThe initial plan is effectively equivalent to
git rebase-tree
(though slightly more permissive). But with some quick edits (adding or removing parentheses, for instance) a tree of single-commit branches all off the same base can be instantly converted into a chain of dependent branches, and vice versa.
Once the initial plan is complete, it's ordinary
git rebase
the rest of the way, so when conflicts arise, it's back to the normal git rebase --continue
(or --skip
or --abort
) workflow to handle them! Aborting happens for free. Moreover, no branches are moved until all commits have been successful rebased, so aborting before that brings everything exactly back to where it started. Finally, if you don't want it to be interactive, just call it with ::
(which I alias to 'EDITOR=: '
).