Re: git-rebase-walk
- From
- Alejandro Colomar <alx@kernel.org>
- Date
- Oct 1, 2026, 16:50 UTC
- Message-ID
- <ar6LUeH3AjxbiMgd@debian>
- In-Reply-To
- <ar6GExDLasWWFajm@ubby>
Hi Nico,
Show 24 quoted lines
> Date: 2026-10-01 11:10:59-0500
> From: Nico Williams <nico@cryptonector.com>
>
> On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:
> > I use this little command to apply iterative rebases, which are easier
> > to handle when there are large conflicts. Are you interested in it?
> >
> > $ cat $(which git-rebase-walk)
> > #!/bin/bash
> >
> > set -Eeufo pipefail;
> >
> > git merge-base HEAD "$1" \
> > | xargs -I{} git log --oneline {}.."$1" \
> > | cut -f1 -d' ' \
> > | tac \
> > | while read -r c; do
> > git rebase "$c";
> > done;
>
> You could simplify this pipeline to:
>
> git log --reverse --format=%H $(git merge-base HEAD "$1").."$1" |
> while read c; do git rebase "$c"; doneActually, I've simplified it to:
$ cat $(which git-rebase-walk) #!/bin/bash
set -Eeufo pipefail;
git merge-base HEAD "$1" \
| xargs -I{} git rev-list {}.."$1" \
| tac \
| while read -r c; do
git rebase "$c";
done;since git-rev-list(1) is the plumbing command (IIUC).
I prefer the explicit tac(1) instead of --reverse. It's simpler conceptually (we don't need to know/remember that there exists a --reverse flag to git-rev-parse(1) nor to understand its exact meaning). tac(1) is well known. The performance doesn't change much, IME (sometimes better; sometimes worse).
I also prefer to use a pipe with xargs(1), since it keeps each command short and readable, without nested commands inside arguments to other commands.
Show 5 quoted lines
> > But: > > - you need to add conflict handling > - this is very slow
I have it running on the background while doing other stuff, and when it stops at a conflict, I look at it.
> I've tried this before, so I know it's very slow if you're rebasing > across thousands of upstream commits!
Yes, it is. When I did this manually before writing the tool, I did roughly a binary search of the conflicts. That'd be faster, and if implemented as part of git(1), it would make sense to implement it that way. For my use case, I could live with a slow thing in the background, which is why I chose to keep it robust.
I expect it wouldn't be that hard to do a binary search within a script.
> Also, you need some extra handling of conflicts.
No, that's the nice part. It works as is. When I see a conflict, I get stopped at the rebase that caused the issue. I solve that conflict, and then can --continue that one rebase. Or I can --abort that one rebase.
Once I've --continue'd, it ends at that one rebase, and doesn't continue the walk. I must run git-rebase-walk again for resuming the rebase-walk, which allows me to see the status before doing it.
Show 6 quoted lines
> > The source code is trivial, so I guess I don't need to explain much. > > It behaves quite nicely, IME. > > It can be much too slow. I've a better solution: bisect-rebase.sh: > > https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297
Hmmm, 93 LoC is certainly more interesting than the 4k+ python script. I'll have a look. I'll also attempt at writing a bisect-rebase from scratch myself, to compare.
Show 6 quoted lines
> (The first revision of that gist is slow-rebase.sh, which is a linear > rebase like the one you posted.) > > This script very efficiently finds the firts upstream commit that your > branch conflicts with, asks the user to resolve conflicts, then resumes > rebasing.
Indeed, this is what I did manually before writing my slow script, so it seems you've had the same needs and line of thought that I had. :)
Show 20 quoted lines
> So let's say that your upstream has 1,000 commits you need to rebase > across, and 10 of those introduce conflicts (assume there's no reverts > of those for now), then this script will ask you to resolve conflicts 10 > times, and each time it's clear which pair of local and upstream commits > conflict so you have the best possible context for conflict resolution. > > It's like git-imerge, but better in that it's specifically geared to > rebase workflows. > > I've successfully used this bisect-rebase.sh script to rebase a > postgresql fork across between 1,000 and 2,000 commits twice, each time > with significant conflicts to resolve that were much too difficult to > resolve with a plain rebase. I.e., a plain `git rebase origin/master` > produced large conflicts where I didn't have enough context, but > bisect-rebase.sh let me resolve much smaller conflicts with a new base > that immediately introduced those conflicts, so I always had the right > context for resolving them. > > PG is a perfect test case for this sort of thing because it's so large > and moves so fast.
I'll certainly try your script; thanks!
Out of curiosity, did you offer this script to git(1)? If not, why not? If yes, what happened?
This is something that would clearly be helpful to people solving rebase conflicts in many projects.
Have a lovely night! Alex
> > Nico > --
-- <https://www.alejandro-colomar.es>