* git-rebase-walk
@ 2026-10-01 11:58 Alejandro Colomar
2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt
` (2 more replies)
0 siblings, 3 replies; 23+ messages in thread
From: Alejandro Colomar @ 2026-10-01 11:58 UTC (permalink / raw)
To: git
[-- Attachment #1: Type: text/plain, Size: 669 bytes --]
Hi!
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;
The source code is trivial, so I guess I don't need to explain much.
It behaves quite nicely, IME.
You may of course want to adapt it a little bit for merging in git(1).
I could help improve it a little bit.
Have a lovely day!
Alex
--
<https://www.alejandro-colomar.es>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
^ permalink raw reply [flat|nested] 23+ messages in thread* Re: git-rebase-walk 2026-10-01 11:58 git-rebase-walk Alejandro Colomar @ 2026-10-01 13:22 ` Patrick Steinhardt 2026-10-01 15:51 ` git-rebase-walk Alejandro Colomar 2026-10-01 17:31 ` git-rebase-walk Junio C Hamano 2026-10-01 16:10 ` git-rebase-walk Nico Williams 2026-10-02 2:49 ` git-rebase-walk Simon Richter 2 siblings, 2 replies; 23+ messages in thread From: Patrick Steinhardt @ 2026-10-01 13:22 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git Hi, On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote: > Hi! > > 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; > > The source code is trivial, so I guess I don't need to explain much. > It behaves quite nicely, IME. > > You may of course want to adapt it a little bit for merging in git(1). > I could help improve it a little bit. this reminds me a bit of git-imerge [1]. What this tool does is to basically perform a merge between two branches incrementally using a matrix. The tool tries to address exactly your use case, which is to "present the user with one pairwise conflict at a time for resolution". Maybe that tool is interesting to you. But it's certainly fallen a bit out of date, as it hasn't received any updates for more than 6 years by now. Chances are it stll works alright though. Thanks! Patrick [1]: https://github.com/mhagger/git-imerge ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt @ 2026-10-01 15:51 ` Alejandro Colomar 2026-10-02 6:46 ` git-rebase-walk Patrick Steinhardt 2026-10-01 17:31 ` git-rebase-walk Junio C Hamano 1 sibling, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-01 15:51 UTC (permalink / raw) To: Patrick Steinhardt; +Cc: git [-- Attachment #1: Type: text/plain, Size: 2230 bytes --] Hi Patrick, > Date: 2026-10-01 15:22:02+0200 > From: Patrick Steinhardt <ps@pks.im> > > Hi, > > On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote: > > Hi! > > > > 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; > > > > The source code is trivial, so I guess I don't need to explain much. > > It behaves quite nicely, IME. > > > > You may of course want to adapt it a little bit for merging in git(1). > > I could help improve it a little bit. > > this reminds me a bit of git-imerge [1]. What this tool does is to > basically perform a merge between two branches incrementally using a > matrix. The tool tries to address exactly your use case, which is to > "present the user with one pairwise conflict at a time for resolution". Yup, from the description, it seems to do the same thing. Thanks! I've also seen at least one other tool that does the same thing. > Maybe that tool is interesting to you. Not much, because I prefer a 9-line shell script that's robust as a rock vs. a 4k+ LoC python script for the same functionality. :-) > But it's certainly fallen a bit > out of date, as it hasn't received any updates for more than 6 years by > now. Chances are it stll works alright though. My script I use it in shadow-utils and in the Linux man-pages project, and is in use today. I was wondering if there was interest in integrating it to git(1). If not, I will likely provide it in the man-pages repository as a help tool (which might end up packed by distros as part of manpages-utils). Is that okay to you? (I ask mainly because it's using the git- namespace for commands, so you should at lease be aware of it.) Have a lovely day! Alex > > Thanks! > > Patrick > > [1]: https://github.com/mhagger/git-imerge -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 15:51 ` git-rebase-walk Alejandro Colomar @ 2026-10-02 6:46 ` Patrick Steinhardt 2026-10-02 7:19 ` git-rebase-walk Alejandro Colomar 2026-10-04 10:03 ` git-rebase-walk Phillip Wood 0 siblings, 2 replies; 23+ messages in thread From: Patrick Steinhardt @ 2026-10-02 6:46 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote: > Hi Patrick, > > > Date: 2026-10-01 15:22:02+0200 > > From: Patrick Steinhardt <ps@pks.im> > > > > Hi, > > > > On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote: > > > Hi! > > > > > > 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; > > > > > > The source code is trivial, so I guess I don't need to explain much. > > > It behaves quite nicely, IME. > > > > > > You may of course want to adapt it a little bit for merging in git(1). > > > I could help improve it a little bit. > > > > this reminds me a bit of git-imerge [1]. What this tool does is to > > basically perform a merge between two branches incrementally using a > > matrix. The tool tries to address exactly your use case, which is to > > "present the user with one pairwise conflict at a time for resolution". > > Yup, from the description, it seems to do the same thing. Thanks! > I've also seen at least one other tool that does the same thing. > > > Maybe that tool is interesting to you. > > Not much, because I prefer a 9-line shell script that's robust as a rock > vs. a 4k+ LoC python script for the same functionality. :-) > > > But it's certainly fallen a bit > > out of date, as it hasn't received any updates for more than 6 years by > > now. Chances are it stll works alright though. > > My script I use it in shadow-utils and in the Linux man-pages project, > and is in use today. I was wondering if there was interest in > integrating it to git(1). I guess the answer is "maybe". The fact that multiple folks have solved similar issues over the course of many years is an indicator that the funcitonality may be more generally useful. But it probably shouldn't be a separate script, so if we wanted to integrate it I'd think the best way forward would be to integrate it into git-rebase(1) directly. That's of course more involved though, so I understand in case you're not interested in doing that. > If not, I will likely provide it in the man-pages repository as a help > tool (which might end up packed by distros as part of manpages-utils). > Is that okay to you? (I ask mainly because it's using the git- > namespace for commands, so you should at lease be aware of it.) I mean overall this is our primary way of extension, by picking up utilities that have the "git-" prefix. So arguably you don't have to ask us for permission to do that. Whether it makes sense to distribute such a tool as part of manpages-utils is a different question, and one where I myself am of a split mind. But that feels more like a question for distributors rather than for us in the Git project. Thanks! Patrick ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-02 6:46 ` git-rebase-walk Patrick Steinhardt @ 2026-10-02 7:19 ` Alejandro Colomar 2026-10-03 19:37 ` git-rebase-walk Nico Williams 2026-10-04 10:03 ` git-rebase-walk Phillip Wood 1 sibling, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-02 7:19 UTC (permalink / raw) To: Patrick Steinhardt; +Cc: git [-- Attachment #1: Type: text/plain, Size: 2420 bytes --] Hi Patrick, > Date: 2026-10-02 08:46:36+0200 > From: Patrick Steinhardt <ps@pks.im> > [...] > > My script I use it in shadow-utils and in the Linux man-pages project, > > and is in use today. I was wondering if there was interest in > > integrating it to git(1). > > I guess the answer is "maybe". The fact that multiple folks have solved > similar issues over the course of many years is an indicator that the > funcitonality may be more generally useful. Nice. :) > But it probably shouldn't be > a separate script, so if we wanted to integrate it I'd think the best > way forward would be to integrate it into git-rebase(1) directly. For a git-rebase(1) option, I guess it would have to be named something like --first-conflict. --first conflict because it doesn't really rebase on the target commit, but rather on the first commit of that branch which causes conflict. > That's of course more involved though, so I understand in case you're > not interested in doing that. I'd still be interested, but it may take me time, and I'll probably need help. > > If not, I will likely provide it in the man-pages repository as a help > > tool (which might end up packed by distros as part of manpages-utils). > > Is that okay to you? (I ask mainly because it's using the git- > > namespace for commands, so you should at lease be aware of it.) > > I mean overall this is our primary way of extension, by picking up > utilities that have the "git-" prefix. So arguably you don't have to ask > us for permission to do that. I think I'll do this to provide the command in the meantime as an easy extension, with the goal of deprecating it eventually once it lands in git-rebase(1). > Whether it makes sense to distribute such a tool as part of > manpages-utils is a different question, and one where I myself am of a > split mind. But that feels more like a question for distributors rather > than for us in the Git project. We already have other tools that are generally useful, such as grepc(1), which finds C source code with a grep(1)-like interface. It's essentially similar to things like ctags, but it has a traditional command-line interface, and doesn't use any index or cache (yet it's very fast). So, it wouldn't hurt having this one. Have a lovely day! Alex > > Thanks! > > Patrick -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-02 7:19 ` git-rebase-walk Alejandro Colomar @ 2026-10-03 19:37 ` Nico Williams 0 siblings, 0 replies; 23+ messages in thread From: Nico Williams @ 2026-10-03 19:37 UTC (permalink / raw) To: Alejandro Colomar; +Cc: Patrick Steinhardt, git On Fri, Oct 02, 2026 at 09:19:56AM +0200, Alejandro Colomar wrote: > For a git-rebase(1) option, I guess it would have to be named something > like --first-conflict. --first conflict because it doesn't really > rebase on the target commit, but rather on the first commit of that > branch which causes conflict. I really like this. Or `git rebase --onto-first-conflict`. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-02 6:46 ` git-rebase-walk Patrick Steinhardt 2026-10-02 7:19 ` git-rebase-walk Alejandro Colomar @ 2026-10-04 10:03 ` Phillip Wood 2026-10-05 13:28 ` git-rebase-walk Alejandro Colomar 1 sibling, 1 reply; 23+ messages in thread From: Phillip Wood @ 2026-10-04 10:03 UTC (permalink / raw) To: Patrick Steinhardt, Alejandro Colomar; +Cc: git, Nico Williams On 02/10/2026 07:46, Patrick Steinhardt wrote: > On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote: >> >> My script I use it in shadow-utils and in the Linux man-pages project, >> and is in use today. I was wondering if there was interest in >> integrating it to git(1). > > I guess the answer is "maybe". The fact that multiple folks have solved > similar issues over the course of many years is an indicator that the > funcitonality may be more generally useful. But it probably shouldn't be > a separate script, so if we wanted to integrate it I'd think the best > way forward would be to integrate it into git-rebase(1) directly. I agree that would be the best way forward. Adding an "--incremental", or "--progressive" option to rebase would be useful I think. For ease of use, I have a strong preference for an implementation where "rebase --continue" handles rebasing onto progressively more recent bases, rather than the multi shot approach where the user has to run "git rebase --incremental" multiple times. Having a multi-shot approach makes it much less clear when we've successfully rebased onto the desired base. Thanks Phillip > That's of course more involved though, so I understand in case you're > not interested in doing that. > >> If not, I will likely provide it in the man-pages repository as a help >> tool (which might end up packed by distros as part of manpages-utils). >> Is that okay to you? (I ask mainly because it's using the git- >> namespace for commands, so you should at lease be aware of it.) > > I mean overall this is our primary way of extension, by picking up > utilities that have the "git-" prefix. So arguably you don't have to ask > us for permission to do that. > > Whether it makes sense to distribute such a tool as part of > manpages-utils is a different question, and one where I myself am of a > split mind. But that feels more like a question for distributors rather > than for us in the Git project. > > Thanks! > > Patrick ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-04 10:03 ` git-rebase-walk Phillip Wood @ 2026-10-05 13:28 ` Alejandro Colomar 2026-10-05 13:37 ` git-rebase-walk Alejandro Colomar 0 siblings, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-05 13:28 UTC (permalink / raw) To: phillip.wood; +Cc: Patrick Steinhardt, git, Nico Williams [-- Attachment #1: Type: text/plain, Size: 18337 bytes --] Hi Phillip, > Date: 2026-10-04 11:03:39+0100 > From: Phillip Wood <phillip.wood123@gmail.com> > > On 02/10/2026 07:46, Patrick Steinhardt wrote: > > On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote: > > > > > > My script I use it in shadow-utils and in the Linux man-pages project, > > > and is in use today. I was wondering if there was interest in > > > integrating it to git(1). > > > > I guess the answer is "maybe". The fact that multiple folks have solved > > similar issues over the course of many years is an indicator that the > > funcitonality may be more generally useful. But it probably shouldn't be > > a separate script, so if we wanted to integrate it I'd think the best > > way forward would be to integrate it into git-rebase(1) directly. > > I agree that would be the best way forward. Adding an "--incremental", or > "--progressive" option to rebase would be useful I think. For ease of use, I > have a strong preference for an implementation where "rebase --continue" > handles rebasing onto progressively more recent bases, rather than the multi > shot approach where the user has to run "git rebase --incremental" multiple > times. Having a multi-shot approach makes it much less clear when we've > successfully rebased onto the desired base. For rebasing a single branch, having --continue do what you suggest wouldn't be too problematic. However, for when rebasing a tree of branches, I really need a multi-shot operation, since I want to advance branches in a very specific order. Below is a shell session performing such a rebase, which hopefully shows why I need this to be multi-shot. On the simpler case of a single branch, I'd still prefer a multi-shot approach where --continue only advances one rebase operation, because at the end of it I want to stop, and check git-range-diff(1) to make sure it all makes sense. I've indented the output of commands, so that they are easier to distinguish. alx@debian:~/tmp/brebase$ git log --all --graph --oneline * G ada8aff4f08a (r/B, B) foo j * G d6163efdc2db bar i | * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l | * G f7309b21ebfa bar k |/ * G e949e24ba457 (HEAD -> A, r/A) bar h * G 607b450498be bar g |\ | * G b787bcd373d9 bar e * | G c496b325576f baz f |/ | * G dfd9156d099a (r/main, main) foo d | * G 4940c7d739be bar c | * G cebc8fde25bb foo b |/ * G 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git brebase --rebase-merges main Rebase: conflict Bisecting: 0 revisions left to test after this (roughly 1 step) [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict Bisecting: 0 revisions left to test after this (roughly 0 steps) [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b running '.git/bisect-rebase/git-bisect-run-callback' Rebase: success 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 Author: Alejandro Colomar <alx@kernel.org> Date: 2026-10-05 14:42:32 +0200 bar c bar | 1 + 1 file changed, 1 insertion(+) create mode 100644 bar bisect found first 'bad' commit Auto-merging bar CONFLICT (add/add): Merge conflict in bar error: could not apply 899eeb5c4e32... bar e hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply 899eeb5c4e32... # bar e alx@debian:~/tmp/brebase$ git rebase --abort alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 655c38e3cee8 (HEAD -> A) bar h * 1ababced193d bar g |\ | * 899eeb5c4e32 bar e * | 761c9dbcfa5b baz f |/ | * ada8aff4f08a (r/B, B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | * | c496b325576f baz f | |/ | | * dfd9156d099a (r/main, main) foo d | | * 4940c7d739be bar c | |/ |/| * | cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git switch B Switched to branch 'B' Your branch is up to date with 'r/B'. alx@debian:~/tmp/brebase$ git brebase A Rebase: conflict Bisecting: 2 revisions left to test after this (roughly 1 step) [899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict Bisecting: 0 revisions left to test after this (roughly 0 steps) [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit commit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 Author: Alejandro Colomar <alx@kernel.org> Date: 2026-10-05 14:42:04 +0200 foo b foo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) bisect found first 'bad' commit Auto-merging foo CONFLICT (content): Merge conflict in foo error: could not apply ada8aff4f08a... foo j hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply ada8aff4f08a... # foo j alx@debian:~/tmp/brebase$ echo j >foo alx@debian:~/tmp/brebase$ git add foo alx@debian:~/tmp/brebase$ git rebase --continue [detached HEAD 2e0b72e7440a] foo j 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/B. alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 2e0b72e7440a (HEAD -> B) foo j * a1c6c1fb7ca2 bar i * d8fa6c4da463 bar h * bef9f1c4da4d bar e * 0bac26895b94 baz f | * 655c38e3cee8 (A) bar h | * 1ababced193d bar g | |\ | | * 899eeb5c4e32 bar e | |/ |/| | * 761c9dbcfa5b baz f |/ | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | * | c496b325576f baz f | |/ | | * dfd9156d099a (r/main, main) foo d | | * 4940c7d739be bar c | |/ |/| * | cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git brebase A Rebase: success alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 5ff93a00f9f2 (HEAD -> B) foo j * 01522206a7bc bar i * 655c38e3cee8 (A) bar h * 1ababced193d bar g |\ | * 899eeb5c4e32 bar e * | 761c9dbcfa5b baz f |/ | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | * | c496b325576f baz f | |/ | | * dfd9156d099a (r/main, main) foo d | | * 4940c7d739be bar c | |/ |/| * | cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git switch C Switched to branch 'C' alx@debian:~/tmp/brebase$ git brebase A Rebase: success alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 06d462903420 (HEAD -> C) bar l * 20f0a887b83b bar k | * 5ff93a00f9f2 (B) foo j | * 01522206a7bc bar i |/ * 655c38e3cee8 (A) bar h * 1ababced193d bar g |\ | * 899eeb5c4e32 bar e * | 761c9dbcfa5b baz f |/ | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | * | c496b325576f baz f | |/ | | * dfd9156d099a (r/main, main) foo d | | * 4940c7d739be bar c | |/ |/| * | cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git switch A Switched to branch 'A' alx@debian:~/tmp/brebase$ git brebase --rebase-merges main Rebase: conflict Bisecting: 0 revisions left to test after this (roughly 0 steps) [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 Author: Alejandro Colomar <alx@kernel.org> Date: 2026-10-05 14:42:32 +0200 bar c bar | 1 + 1 file changed, 1 insertion(+) create mode 100644 bar bisect found first 'bad' commit Auto-merging bar CONFLICT (add/add): Merge conflict in bar error: could not apply 899eeb5c4e32... bar e hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply 899eeb5c4e32... # bar e alx@debian:~/tmp/brebase$ echo e >bar alx@debian:~/tmp/brebase$ git add bar alx@debian:~/tmp/brebase$ git rebase --continue [detached HEAD 2a4fa7fe2f44] bar e 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/A. alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 0954f3d9b9e1 (HEAD -> A) bar h * 4f09c21bf2ca bar g |\ | * 2a4fa7fe2f44 bar e * | e42246e75159 baz f |/ | * 06d462903420 (C) bar l | * 20f0a887b83b bar k | | * 5ff93a00f9f2 (B) foo j | | * 01522206a7bc bar i | |/ | * 655c38e3cee8 bar h | * 1ababced193d bar g | |\ | | * 899eeb5c4e32 bar e | * | 761c9dbcfa5b baz f | |/ | | * ada8aff4f08a (r/B) foo j | | * d6163efdc2db bar i | | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | | * f7309b21ebfa bar k | | |/ | | * e949e24ba457 (r/A) bar h | | * 607b450498be bar g | | |\ | | | * b787bcd373d9 bar e | | * | c496b325576f baz f | | |/ | | | * dfd9156d099a (r/main, main) foo d | |_|/ |/| | * | | 4940c7d739be bar c |/ / * / cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B Successfully rebased and updated refs/heads/B. alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C Successfully rebased and updated refs/heads/C. alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 4a4ba76f55a4 (HEAD -> C) bar l * 86350e1490f3 bar k | * 4b6b40b14255 (B) foo j | * ba5a233ee4bc bar i |/ * 0954f3d9b9e1 (A) bar h * 4f09c21bf2ca bar g |\ | * 2a4fa7fe2f44 bar e * | e42246e75159 baz f |/ | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | * | c496b325576f baz f | |/ | | * dfd9156d099a (r/main, main) foo d | |/ |/| * | 4940c7d739be bar c * | cebc8fde25bb foo b |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git switch A Switched to branch 'A' alx@debian:~/tmp/brebase$ git brebase --rebase-merges main Rebase: success alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 30e2d96b3da5 (HEAD -> A) bar h * 01702a5b5d6b bar g |\ | * c961883d543a bar e * | e17aadb725c4 baz f |/ * dfd9156d099a (r/main, main) foo d | * 4a4ba76f55a4 (C) bar l | * 86350e1490f3 bar k | | * 4b6b40b14255 (B) foo j | | * ba5a233ee4bc bar i | |/ | * 0954f3d9b9e1 bar h | * 4f09c21bf2ca bar g | |\ | | * 2a4fa7fe2f44 bar e | |/ |/| | * e42246e75159 baz f |/ * 4940c7d739be bar c * cebc8fde25bb foo b | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | |/ |/| | * c496b325576f baz f |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C Successfully rebased and updated refs/heads/C. alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B Auto-merging foo CONFLICT (content): Merge conflict in foo error: could not apply 4b6b40b14255... foo j hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply 4b6b40b14255... # foo j alx@debian:~/tmp/brebase$ git rebase --abort alx@debian:~/tmp/brebase$ git switch B Already on 'B' Your branch and 'r/B' have diverged, and have 8 and 6 different commits each, respectively. (use "git pull" if you want to integrate the remote branch with yours) alx@debian:~/tmp/brebase$ git brebase A Rebase: conflict Bisecting: 2 revisions left to test after this (roughly 1 step) [c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict Bisecting: 0 revisions left to test after this (roughly 0 steps) [dfd9156d099ad3507a2850294c7a584b80712f04] foo d running '.git/bisect-rebase/git-bisect-run-callback' Rebase: conflict dfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit commit dfd9156d099ad3507a2850294c7a584b80712f04 Author: Alejandro Colomar <alx@kernel.org> Date: 2026-10-05 14:42:50 +0200 foo d foo | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) bisect found first 'bad' commit Auto-merging foo CONFLICT (content): Merge conflict in foo error: could not apply 4b6b40b14255... foo j hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply 4b6b40b14255... # foo j alx@debian:~/tmp/brebase$ echo j >foo alx@debian:~/tmp/brebase$ git add foo alx@debian:~/tmp/brebase$ git rebase --continue [detached HEAD e7fdf07fd077] foo j 1 file changed, 1 insertion(+), 1 deletion(-) Successfully rebased and updated refs/heads/B. alx@debian:~/tmp/brebase$ git log --all --graph --oneline * e7fdf07fd077 (HEAD -> B) foo j * dddf632a735f bar i * 7ac284de12ba bar h * e4541508ab3e bar e * cefec5878c67 baz f | * 6c7952d6fec5 (C) bar l | * bd43684f73c8 bar k | * 30e2d96b3da5 (A) bar h | * 01702a5b5d6b bar g | |\ | | * c961883d543a bar e | |/ |/| | * e17aadb725c4 baz f |/ * dfd9156d099a (r/main, main) foo d * 4940c7d739be bar c * cebc8fde25bb foo b | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | |/ |/| | * c496b325576f baz f |/ * 1dcb901ebf60 foo a alx@debian:~/tmp/brebase$ git brebase A Rebase: success alx@debian:~/tmp/brebase$ git log --all --graph --oneline * 1201c4f20b19 (HEAD -> B) foo j * 44103f51a783 bar i | * 6c7952d6fec5 (C) bar l | * bd43684f73c8 bar k |/ * 30e2d96b3da5 (A) bar h * 01702a5b5d6b bar g |\ | * c961883d543a bar e * | e17aadb725c4 baz f |/ * dfd9156d099a (r/main, main) foo d * 4940c7d739be bar c * cebc8fde25bb foo b | * ada8aff4f08a (r/B) foo j | * d6163efdc2db bar i | | * 450f3a7f4f25 (r/HEAD, r/C) bar l | | * f7309b21ebfa bar k | |/ | * e949e24ba457 (r/A) bar h | * 607b450498be bar g | |\ | | * b787bcd373d9 bar e | |/ |/| | * c496b325576f baz f |/ * 1dcb901ebf60 foo a This would be impossible with an approach that handles all the way until the end. I need to be able to stop a bisect-rebase operation on one branch in the middle, then do a bisect-rebase on its descendants, then come back to bisect-rebase the parent branch. Does this make sense? Have a lovely day! Alex > > Thanks > > Phillip > > > > That's of course more involved though, so I understand in case you're > > not interested in doing that. > > > > > If not, I will likely provide it in the man-pages repository as a help > > > tool (which might end up packed by distros as part of manpages-utils). > > > Is that okay to you? (I ask mainly because it's using the git- > > > namespace for commands, so you should at lease be aware of it.) > > > > I mean overall this is our primary way of extension, by picking up > > utilities that have the "git-" prefix. So arguably you don't have to ask > > us for permission to do that. > > > > Whether it makes sense to distribute such a tool as part of > > manpages-utils is a different question, and one where I myself am of a > > split mind. But that feels more like a question for distributors rather > > than for us in the Git project. > > > > Thanks! > > > > Patrick > -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-05 13:28 ` git-rebase-walk Alejandro Colomar @ 2026-10-05 13:37 ` Alejandro Colomar 2026-10-06 14:01 ` git-rebase-walk Phillip Wood 0 siblings, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-05 13:37 UTC (permalink / raw) To: phillip.wood; +Cc: Patrick Steinhardt, git, Nico Williams [-- Attachment #1: Type: text/plain, Size: 19746 bytes --] > Date: 2026-10-05 15:28:28+0200 > From: Alejandro Colomar <alx@kernel.org> > > Hi Phillip, > > > Date: 2026-10-04 11:03:39+0100 > > From: Phillip Wood <phillip.wood123@gmail.com> > > > > On 02/10/2026 07:46, Patrick Steinhardt wrote: > > > On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote: > > > > > > > > My script I use it in shadow-utils and in the Linux man-pages project, > > > > and is in use today. I was wondering if there was interest in > > > > integrating it to git(1). > > > > > > I guess the answer is "maybe". The fact that multiple folks have solved > > > similar issues over the course of many years is an indicator that the > > > funcitonality may be more generally useful. But it probably shouldn't be > > > a separate script, so if we wanted to integrate it I'd think the best > > > way forward would be to integrate it into git-rebase(1) directly. > > > > I agree that would be the best way forward. Adding an "--incremental", or > > "--progressive" option to rebase would be useful I think. For ease of use, I > > have a strong preference for an implementation where "rebase --continue" > > handles rebasing onto progressively more recent bases, rather than the multi > > shot approach where the user has to run "git rebase --incremental" multiple > > times. Having a multi-shot approach makes it much less clear when we've > > successfully rebased onto the desired base. > > For rebasing a single branch, having --continue do what you suggest > wouldn't be too problematic. > > However, for when rebasing a tree of branches, I really need a > multi-shot operation, since I want to advance branches in a very > specific order. > > Below is a shell session performing such a rebase, which hopefully shows > why I need this to be multi-shot. > > On the simpler case of a single branch, I'd still prefer a multi-shot > approach where --continue only advances one rebase operation, because at > the end of it I want to stop, and check git-range-diff(1) to make sure > it all makes sense. > > I've indented the output of commands, so that they are easier to > distinguish. > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * G ada8aff4f08a (r/B, B) foo j > * G d6163efdc2db bar i > | * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l > | * G f7309b21ebfa bar k > |/ > * G e949e24ba457 (HEAD -> A, r/A) bar h > * G 607b450498be bar g > |\ > | * G b787bcd373d9 bar e > * | G c496b325576f baz f > |/ > | * G dfd9156d099a (r/main, main) foo d > | * G 4940c7d739be bar c > | * G cebc8fde25bb foo b > |/ > * G 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > Rebase: conflict > Bisecting: 0 revisions left to test after this (roughly 1 step) > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > Bisecting: 0 revisions left to test after this (roughly 0 steps) > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: success > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > Author: Alejandro Colomar <alx@kernel.org> > Date: 2026-10-05 14:42:32 +0200 > > bar c > > bar | 1 + > 1 file changed, 1 insertion(+) > create mode 100644 bar > bisect found first 'bad' commit > Auto-merging bar > CONFLICT (add/add): Merge conflict in bar > error: could not apply 899eeb5c4e32... bar e > hint: Resolve all conflicts manually, mark them as resolved with > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > hint: You can instead skip this commit: run "git rebase --skip". > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > hint: Disable this message with "git config set advice.mergeConflict false" > Could not apply 899eeb5c4e32... # bar e > alx@debian:~/tmp/brebase$ git rebase --abort > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 655c38e3cee8 (HEAD -> A) bar h > * 1ababced193d bar g > |\ > | * 899eeb5c4e32 bar e > * | 761c9dbcfa5b baz f > |/ > | * ada8aff4f08a (r/B, B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | * | c496b325576f baz f > | |/ > | | * dfd9156d099a (r/main, main) foo d > | | * 4940c7d739be bar c > | |/ > |/| > * | cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git switch B > Switched to branch 'B' > Your branch is up to date with 'r/B'. > alx@debian:~/tmp/brebase$ git brebase A > Rebase: conflict > Bisecting: 2 revisions left to test after this (roughly 1 step) > [899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > Bisecting: 0 revisions left to test after this (roughly 0 steps) > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit > commit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 > Author: Alejandro Colomar <alx@kernel.org> > Date: 2026-10-05 14:42:04 +0200 > > foo b > > foo | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > bisect found first 'bad' commit > Auto-merging foo > CONFLICT (content): Merge conflict in foo > error: could not apply ada8aff4f08a... foo j > hint: Resolve all conflicts manually, mark them as resolved with > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > hint: You can instead skip this commit: run "git rebase --skip". > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > hint: Disable this message with "git config set advice.mergeConflict false" > Could not apply ada8aff4f08a... # foo j > alx@debian:~/tmp/brebase$ echo j >foo > alx@debian:~/tmp/brebase$ git add foo > alx@debian:~/tmp/brebase$ git rebase --continue > [detached HEAD 2e0b72e7440a] foo j > 1 file changed, 1 insertion(+), 1 deletion(-) > Successfully rebased and updated refs/heads/B. > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 2e0b72e7440a (HEAD -> B) foo j > * a1c6c1fb7ca2 bar i > * d8fa6c4da463 bar h > * bef9f1c4da4d bar e > * 0bac26895b94 baz f > | * 655c38e3cee8 (A) bar h > | * 1ababced193d bar g > | |\ > | | * 899eeb5c4e32 bar e > | |/ > |/| > | * 761c9dbcfa5b baz f > |/ > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | * | c496b325576f baz f > | |/ > | | * dfd9156d099a (r/main, main) foo d > | | * 4940c7d739be bar c > | |/ > |/| > * | cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git brebase A > Rebase: success > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 5ff93a00f9f2 (HEAD -> B) foo j > * 01522206a7bc bar i > * 655c38e3cee8 (A) bar h > * 1ababced193d bar g > |\ > | * 899eeb5c4e32 bar e > * | 761c9dbcfa5b baz f > |/ > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | * | c496b325576f baz f > | |/ > | | * dfd9156d099a (r/main, main) foo d > | | * 4940c7d739be bar c > | |/ > |/| > * | cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git switch C > Switched to branch 'C' > alx@debian:~/tmp/brebase$ git brebase A > Rebase: success > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 06d462903420 (HEAD -> C) bar l > * 20f0a887b83b bar k > | * 5ff93a00f9f2 (B) foo j > | * 01522206a7bc bar i > |/ > * 655c38e3cee8 (A) bar h > * 1ababced193d bar g > |\ > | * 899eeb5c4e32 bar e > * | 761c9dbcfa5b baz f > |/ > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | * | c496b325576f baz f > | |/ > | | * dfd9156d099a (r/main, main) foo d > | | * 4940c7d739be bar c > | |/ > |/| > * | cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git switch A > Switched to branch 'A' > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > Rebase: conflict > Bisecting: 0 revisions left to test after this (roughly 0 steps) > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > Author: Alejandro Colomar <alx@kernel.org> > Date: 2026-10-05 14:42:32 +0200 > > bar c > > bar | 1 + > 1 file changed, 1 insertion(+) > create mode 100644 bar > bisect found first 'bad' commit > Auto-merging bar > CONFLICT (add/add): Merge conflict in bar > error: could not apply 899eeb5c4e32... bar e > hint: Resolve all conflicts manually, mark them as resolved with > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > hint: You can instead skip this commit: run "git rebase --skip". > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > hint: Disable this message with "git config set advice.mergeConflict false" > Could not apply 899eeb5c4e32... # bar e > alx@debian:~/tmp/brebase$ echo e >bar > alx@debian:~/tmp/brebase$ git add bar > alx@debian:~/tmp/brebase$ git rebase --continue > [detached HEAD 2a4fa7fe2f44] bar e > 1 file changed, 1 insertion(+), 1 deletion(-) > Successfully rebased and updated refs/heads/A. > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 0954f3d9b9e1 (HEAD -> A) bar h > * 4f09c21bf2ca bar g > |\ > | * 2a4fa7fe2f44 bar e > * | e42246e75159 baz f > |/ > | * 06d462903420 (C) bar l > | * 20f0a887b83b bar k > | | * 5ff93a00f9f2 (B) foo j > | | * 01522206a7bc bar i > | |/ > | * 655c38e3cee8 bar h > | * 1ababced193d bar g > | |\ > | | * 899eeb5c4e32 bar e > | * | 761c9dbcfa5b baz f > | |/ > | | * ada8aff4f08a (r/B) foo j > | | * d6163efdc2db bar i > | | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | | * f7309b21ebfa bar k > | | |/ > | | * e949e24ba457 (r/A) bar h > | | * 607b450498be bar g > | | |\ > | | | * b787bcd373d9 bar e > | | * | c496b325576f baz f > | | |/ > | | | * dfd9156d099a (r/main, main) foo d > | |_|/ > |/| | > * | | 4940c7d739be bar c > |/ / > * / cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B > Successfully rebased and updated refs/heads/B. > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C > Successfully rebased and updated refs/heads/C. > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 4a4ba76f55a4 (HEAD -> C) bar l > * 86350e1490f3 bar k > | * 4b6b40b14255 (B) foo j > | * ba5a233ee4bc bar i > |/ > * 0954f3d9b9e1 (A) bar h > * 4f09c21bf2ca bar g > |\ > | * 2a4fa7fe2f44 bar e > * | e42246e75159 baz f > |/ > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | * | c496b325576f baz f > | |/ > | | * dfd9156d099a (r/main, main) foo d > | |/ > |/| > * | 4940c7d739be bar c > * | cebc8fde25bb foo b > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git switch A > Switched to branch 'A' > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > Rebase: success > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 30e2d96b3da5 (HEAD -> A) bar h > * 01702a5b5d6b bar g > |\ > | * c961883d543a bar e > * | e17aadb725c4 baz f > |/ > * dfd9156d099a (r/main, main) foo d > | * 4a4ba76f55a4 (C) bar l > | * 86350e1490f3 bar k > | | * 4b6b40b14255 (B) foo j > | | * ba5a233ee4bc bar i > | |/ > | * 0954f3d9b9e1 bar h > | * 4f09c21bf2ca bar g > | |\ > | | * 2a4fa7fe2f44 bar e > | |/ > |/| > | * e42246e75159 baz f > |/ > * 4940c7d739be bar c > * cebc8fde25bb foo b > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | |/ > |/| > | * c496b325576f baz f > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C > Successfully rebased and updated refs/heads/C. > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B > Auto-merging foo > CONFLICT (content): Merge conflict in foo > error: could not apply 4b6b40b14255... foo j > hint: Resolve all conflicts manually, mark them as resolved with > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > hint: You can instead skip this commit: run "git rebase --skip". > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > hint: Disable this message with "git config set advice.mergeConflict false" > Could not apply 4b6b40b14255... # foo j > alx@debian:~/tmp/brebase$ git rebase --abort Oh, this was a mistake; I should have resolved the conflict here instead of using brebase below. (brebase produced the same exact conflict). :) Cheers, Alex > alx@debian:~/tmp/brebase$ git switch B > Already on 'B' > Your branch and 'r/B' have diverged, > and have 8 and 6 different commits each, respectively. > (use "git pull" if you want to integrate the remote branch with yours) > alx@debian:~/tmp/brebase$ git brebase A > Rebase: conflict > Bisecting: 2 revisions left to test after this (roughly 1 step) > [c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > Bisecting: 0 revisions left to test after this (roughly 0 steps) > [dfd9156d099ad3507a2850294c7a584b80712f04] foo d > running '.git/bisect-rebase/git-bisect-run-callback' > Rebase: conflict > dfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit > commit dfd9156d099ad3507a2850294c7a584b80712f04 > Author: Alejandro Colomar <alx@kernel.org> > Date: 2026-10-05 14:42:50 +0200 > > foo d > > foo | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > bisect found first 'bad' commit > Auto-merging foo > CONFLICT (content): Merge conflict in foo > error: could not apply 4b6b40b14255... foo j > hint: Resolve all conflicts manually, mark them as resolved with > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > hint: You can instead skip this commit: run "git rebase --skip". > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > hint: Disable this message with "git config set advice.mergeConflict false" > Could not apply 4b6b40b14255... # foo j > alx@debian:~/tmp/brebase$ echo j >foo > alx@debian:~/tmp/brebase$ git add foo > alx@debian:~/tmp/brebase$ git rebase --continue > [detached HEAD e7fdf07fd077] foo j > 1 file changed, 1 insertion(+), 1 deletion(-) > Successfully rebased and updated refs/heads/B. > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * e7fdf07fd077 (HEAD -> B) foo j > * dddf632a735f bar i > * 7ac284de12ba bar h > * e4541508ab3e bar e > * cefec5878c67 baz f > | * 6c7952d6fec5 (C) bar l > | * bd43684f73c8 bar k > | * 30e2d96b3da5 (A) bar h > | * 01702a5b5d6b bar g > | |\ > | | * c961883d543a bar e > | |/ > |/| > | * e17aadb725c4 baz f > |/ > * dfd9156d099a (r/main, main) foo d > * 4940c7d739be bar c > * cebc8fde25bb foo b > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | |/ > |/| > | * c496b325576f baz f > |/ > * 1dcb901ebf60 foo a > alx@debian:~/tmp/brebase$ git brebase A > Rebase: success > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > * 1201c4f20b19 (HEAD -> B) foo j > * 44103f51a783 bar i > | * 6c7952d6fec5 (C) bar l > | * bd43684f73c8 bar k > |/ > * 30e2d96b3da5 (A) bar h > * 01702a5b5d6b bar g > |\ > | * c961883d543a bar e > * | e17aadb725c4 baz f > |/ > * dfd9156d099a (r/main, main) foo d > * 4940c7d739be bar c > * cebc8fde25bb foo b > | * ada8aff4f08a (r/B) foo j > | * d6163efdc2db bar i > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > | | * f7309b21ebfa bar k > | |/ > | * e949e24ba457 (r/A) bar h > | * 607b450498be bar g > | |\ > | | * b787bcd373d9 bar e > | |/ > |/| > | * c496b325576f baz f > |/ > * 1dcb901ebf60 foo a > > This would be impossible with an approach that handles all the way until > the end. I need to be able to stop a bisect-rebase operation on one > branch in the middle, then do a bisect-rebase on its descendants, then > come back to bisect-rebase the parent branch. Does this make sense? > > > Have a lovely day! > Alex > > > > > > Thanks > > > > Phillip > > > > > > > That's of course more involved though, so I understand in case you're > > > not interested in doing that. > > > > > > > If not, I will likely provide it in the man-pages repository as a help > > > > tool (which might end up packed by distros as part of manpages-utils). > > > > Is that okay to you? (I ask mainly because it's using the git- > > > > namespace for commands, so you should at lease be aware of it.) > > > > > > I mean overall this is our primary way of extension, by picking up > > > utilities that have the "git-" prefix. So arguably you don't have to ask > > > us for permission to do that. > > > > > > Whether it makes sense to distribute such a tool as part of > > > manpages-utils is a different question, and one where I myself am of a > > > split mind. But that feels more like a question for distributors rather > > > than for us in the Git project. > > > > > > Thanks! > > > > > > Patrick > > > > -- > <https://www.alejandro-colomar.es> -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-05 13:37 ` git-rebase-walk Alejandro Colomar @ 2026-10-06 14:01 ` Phillip Wood 2026-10-06 14:58 ` git-rebase-walk Nico Williams 2026-10-08 22:05 ` git-rebase-walk Alejandro Colomar 0 siblings, 2 replies; 23+ messages in thread From: Phillip Wood @ 2026-10-06 14:01 UTC (permalink / raw) To: Alejandro Colomar, phillip.wood; +Cc: Patrick Steinhardt, git, Nico Williams Hi Alejandro On 05/10/2026 14:37, Alejandro Colomar wrote: >> Date: 2026-10-05 15:28:28+0200 >> From: Alejandro Colomar <alx@kernel.org> >>> Date: 2026-10-04 11:03:39+0100 >>> From: Phillip Wood <phillip.wood123@gmail.com> >>> >>> I agree that would be the best way forward. Adding an "--incremental", or >>> "--progressive" option to rebase would be useful I think. For ease of use, I >>> have a strong preference for an implementation where "rebase --continue" >>> handles rebasing onto progressively more recent bases, rather than the multi >>> shot approach where the user has to run "git rebase --incremental" multiple >>> times. Having a multi-shot approach makes it much less clear when we've >>> successfully rebased onto the desired base. >> >> For rebasing a single branch, having --continue do what you suggest >> wouldn't be too problematic. >> >> However, for when rebasing a tree of branches, I really need a >> multi-shot operation, since I want to advance branches in a very >> specific order. >> >> Below is a shell session performing such a rebase, which hopefully shows >> why I need this to be multi-shot. To me it shows that we need to improve "git rebase --update-refs" so that it can rebase a tree of branches automatically. Doing it manually is labor intensive and error-prone (your example output shows it is easy to forget when you're meant to be resolving a conflict instead aborting the rebase and checking out another branch). In the example below git rebase --update-refs --rebase-merges main B will rebase A and B, but we don't have a way of including C. >> On the simpler case of a single branch, I'd still prefer a multi-shot >> approach where --continue only advances one rebase operation, because at >> the end of it I want to stop, and check git-range-diff(1) to make sure >> it all makes sense. Perhaps we could insert "break" commands after each branch is rebased so the user can check the range-diff. Thanks Phillip >> I've indented the output of commands, so that they are easier to >> distinguish. >> >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * G ada8aff4f08a (r/B, B) foo j >> * G d6163efdc2db bar i >> | * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l >> | * G f7309b21ebfa bar k >> |/ >> * G e949e24ba457 (HEAD -> A, r/A) bar h >> * G 607b450498be bar g >> |\ >> | * G b787bcd373d9 bar e >> * | G c496b325576f baz f >> |/ >> | * G dfd9156d099a (r/main, main) foo d >> | * G 4940c7d739be bar c >> | * G cebc8fde25bb foo b >> |/ >> * G 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git brebase --rebase-merges main >> Rebase: conflict >> Bisecting: 0 revisions left to test after this (roughly 1 step) >> [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> Bisecting: 0 revisions left to test after this (roughly 0 steps) >> [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: success >> 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit >> commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 >> Author: Alejandro Colomar <alx@kernel.org> >> Date: 2026-10-05 14:42:32 +0200 >> >> bar c >> >> bar | 1 + >> 1 file changed, 1 insertion(+) >> create mode 100644 bar >> bisect found first 'bad' commit >> Auto-merging bar >> CONFLICT (add/add): Merge conflict in bar >> error: could not apply 899eeb5c4e32... bar e >> hint: Resolve all conflicts manually, mark them as resolved with >> hint: "git add/rm <conflicted_files>", then run "git rebase --continue". >> hint: You can instead skip this commit: run "git rebase --skip". >> hint: To abort and get back to the state before "git rebase", run "git rebase --abort". >> hint: Disable this message with "git config set advice.mergeConflict false" >> Could not apply 899eeb5c4e32... # bar e >> alx@debian:~/tmp/brebase$ git rebase --abort >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 655c38e3cee8 (HEAD -> A) bar h >> * 1ababced193d bar g >> |\ >> | * 899eeb5c4e32 bar e >> * | 761c9dbcfa5b baz f >> |/ >> | * ada8aff4f08a (r/B, B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | * | c496b325576f baz f >> | |/ >> | | * dfd9156d099a (r/main, main) foo d >> | | * 4940c7d739be bar c >> | |/ >> |/| >> * | cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git switch B >> Switched to branch 'B' >> Your branch is up to date with 'r/B'. >> alx@debian:~/tmp/brebase$ git brebase A >> Rebase: conflict >> Bisecting: 2 revisions left to test after this (roughly 1 step) >> [899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> Bisecting: 0 revisions left to test after this (roughly 0 steps) >> [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit >> commit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 >> Author: Alejandro Colomar <alx@kernel.org> >> Date: 2026-10-05 14:42:04 +0200 >> >> foo b >> >> foo | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> bisect found first 'bad' commit >> Auto-merging foo >> CONFLICT (content): Merge conflict in foo >> error: could not apply ada8aff4f08a... foo j >> hint: Resolve all conflicts manually, mark them as resolved with >> hint: "git add/rm <conflicted_files>", then run "git rebase --continue". >> hint: You can instead skip this commit: run "git rebase --skip". >> hint: To abort and get back to the state before "git rebase", run "git rebase --abort". >> hint: Disable this message with "git config set advice.mergeConflict false" >> Could not apply ada8aff4f08a... # foo j >> alx@debian:~/tmp/brebase$ echo j >foo >> alx@debian:~/tmp/brebase$ git add foo >> alx@debian:~/tmp/brebase$ git rebase --continue >> [detached HEAD 2e0b72e7440a] foo j >> 1 file changed, 1 insertion(+), 1 deletion(-) >> Successfully rebased and updated refs/heads/B. >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 2e0b72e7440a (HEAD -> B) foo j >> * a1c6c1fb7ca2 bar i >> * d8fa6c4da463 bar h >> * bef9f1c4da4d bar e >> * 0bac26895b94 baz f >> | * 655c38e3cee8 (A) bar h >> | * 1ababced193d bar g >> | |\ >> | | * 899eeb5c4e32 bar e >> | |/ >> |/| >> | * 761c9dbcfa5b baz f >> |/ >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | * | c496b325576f baz f >> | |/ >> | | * dfd9156d099a (r/main, main) foo d >> | | * 4940c7d739be bar c >> | |/ >> |/| >> * | cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git brebase A >> Rebase: success >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 5ff93a00f9f2 (HEAD -> B) foo j >> * 01522206a7bc bar i >> * 655c38e3cee8 (A) bar h >> * 1ababced193d bar g >> |\ >> | * 899eeb5c4e32 bar e >> * | 761c9dbcfa5b baz f >> |/ >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | * | c496b325576f baz f >> | |/ >> | | * dfd9156d099a (r/main, main) foo d >> | | * 4940c7d739be bar c >> | |/ >> |/| >> * | cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git switch C >> Switched to branch 'C' >> alx@debian:~/tmp/brebase$ git brebase A >> Rebase: success >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 06d462903420 (HEAD -> C) bar l >> * 20f0a887b83b bar k >> | * 5ff93a00f9f2 (B) foo j >> | * 01522206a7bc bar i >> |/ >> * 655c38e3cee8 (A) bar h >> * 1ababced193d bar g >> |\ >> | * 899eeb5c4e32 bar e >> * | 761c9dbcfa5b baz f >> |/ >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | * | c496b325576f baz f >> | |/ >> | | * dfd9156d099a (r/main, main) foo d >> | | * 4940c7d739be bar c >> | |/ >> |/| >> * | cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git switch A >> Switched to branch 'A' >> alx@debian:~/tmp/brebase$ git brebase --rebase-merges main >> Rebase: conflict >> Bisecting: 0 revisions left to test after this (roughly 0 steps) >> [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit >> commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 >> Author: Alejandro Colomar <alx@kernel.org> >> Date: 2026-10-05 14:42:32 +0200 >> >> bar c >> >> bar | 1 + >> 1 file changed, 1 insertion(+) >> create mode 100644 bar >> bisect found first 'bad' commit >> Auto-merging bar >> CONFLICT (add/add): Merge conflict in bar >> error: could not apply 899eeb5c4e32... bar e >> hint: Resolve all conflicts manually, mark them as resolved with >> hint: "git add/rm <conflicted_files>", then run "git rebase --continue". >> hint: You can instead skip this commit: run "git rebase --skip". >> hint: To abort and get back to the state before "git rebase", run "git rebase --abort". >> hint: Disable this message with "git config set advice.mergeConflict false" >> Could not apply 899eeb5c4e32... # bar e >> alx@debian:~/tmp/brebase$ echo e >bar >> alx@debian:~/tmp/brebase$ git add bar >> alx@debian:~/tmp/brebase$ git rebase --continue >> [detached HEAD 2a4fa7fe2f44] bar e >> 1 file changed, 1 insertion(+), 1 deletion(-) >> Successfully rebased and updated refs/heads/A. >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 0954f3d9b9e1 (HEAD -> A) bar h >> * 4f09c21bf2ca bar g >> |\ >> | * 2a4fa7fe2f44 bar e >> * | e42246e75159 baz f >> |/ >> | * 06d462903420 (C) bar l >> | * 20f0a887b83b bar k >> | | * 5ff93a00f9f2 (B) foo j >> | | * 01522206a7bc bar i >> | |/ >> | * 655c38e3cee8 bar h >> | * 1ababced193d bar g >> | |\ >> | | * 899eeb5c4e32 bar e >> | * | 761c9dbcfa5b baz f >> | |/ >> | | * ada8aff4f08a (r/B) foo j >> | | * d6163efdc2db bar i >> | | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | | * f7309b21ebfa bar k >> | | |/ >> | | * e949e24ba457 (r/A) bar h >> | | * 607b450498be bar g >> | | |\ >> | | | * b787bcd373d9 bar e >> | | * | c496b325576f baz f >> | | |/ >> | | | * dfd9156d099a (r/main, main) foo d >> | |_|/ >> |/| | >> * | | 4940c7d739be bar c >> |/ / >> * / cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B >> Successfully rebased and updated refs/heads/B. >> alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C >> Successfully rebased and updated refs/heads/C. >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 4a4ba76f55a4 (HEAD -> C) bar l >> * 86350e1490f3 bar k >> | * 4b6b40b14255 (B) foo j >> | * ba5a233ee4bc bar i >> |/ >> * 0954f3d9b9e1 (A) bar h >> * 4f09c21bf2ca bar g >> |\ >> | * 2a4fa7fe2f44 bar e >> * | e42246e75159 baz f >> |/ >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | * | c496b325576f baz f >> | |/ >> | | * dfd9156d099a (r/main, main) foo d >> | |/ >> |/| >> * | 4940c7d739be bar c >> * | cebc8fde25bb foo b >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git switch A >> Switched to branch 'A' >> alx@debian:~/tmp/brebase$ git brebase --rebase-merges main >> Rebase: success >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 30e2d96b3da5 (HEAD -> A) bar h >> * 01702a5b5d6b bar g >> |\ >> | * c961883d543a bar e >> * | e17aadb725c4 baz f >> |/ >> * dfd9156d099a (r/main, main) foo d >> | * 4a4ba76f55a4 (C) bar l >> | * 86350e1490f3 bar k >> | | * 4b6b40b14255 (B) foo j >> | | * ba5a233ee4bc bar i >> | |/ >> | * 0954f3d9b9e1 bar h >> | * 4f09c21bf2ca bar g >> | |\ >> | | * 2a4fa7fe2f44 bar e >> | |/ >> |/| >> | * e42246e75159 baz f >> |/ >> * 4940c7d739be bar c >> * cebc8fde25bb foo b >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | |/ >> |/| >> | * c496b325576f baz f >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C >> Successfully rebased and updated refs/heads/C. >> alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B >> Auto-merging foo >> CONFLICT (content): Merge conflict in foo >> error: could not apply 4b6b40b14255... foo j >> hint: Resolve all conflicts manually, mark them as resolved with >> hint: "git add/rm <conflicted_files>", then run "git rebase --continue". >> hint: You can instead skip this commit: run "git rebase --skip". >> hint: To abort and get back to the state before "git rebase", run "git rebase --abort". >> hint: Disable this message with "git config set advice.mergeConflict false" >> Could not apply 4b6b40b14255... # foo j >> alx@debian:~/tmp/brebase$ git rebase --abort > > Oh, this was a mistake; I should have resolved the conflict here > instead of using brebase below. (brebase produced the same exact > conflict). :) > > > Cheers, > Alex > >> alx@debian:~/tmp/brebase$ git switch B >> Already on 'B' >> Your branch and 'r/B' have diverged, >> and have 8 and 6 different commits each, respectively. >> (use "git pull" if you want to integrate the remote branch with yours) >> alx@debian:~/tmp/brebase$ git brebase A >> Rebase: conflict >> Bisecting: 2 revisions left to test after this (roughly 1 step) >> [c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> Bisecting: 0 revisions left to test after this (roughly 0 steps) >> [dfd9156d099ad3507a2850294c7a584b80712f04] foo d >> running '.git/bisect-rebase/git-bisect-run-callback' >> Rebase: conflict >> dfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit >> commit dfd9156d099ad3507a2850294c7a584b80712f04 >> Author: Alejandro Colomar <alx@kernel.org> >> Date: 2026-10-05 14:42:50 +0200 >> >> foo d >> >> foo | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> bisect found first 'bad' commit >> Auto-merging foo >> CONFLICT (content): Merge conflict in foo >> error: could not apply 4b6b40b14255... foo j >> hint: Resolve all conflicts manually, mark them as resolved with >> hint: "git add/rm <conflicted_files>", then run "git rebase --continue". >> hint: You can instead skip this commit: run "git rebase --skip". >> hint: To abort and get back to the state before "git rebase", run "git rebase --abort". >> hint: Disable this message with "git config set advice.mergeConflict false" >> Could not apply 4b6b40b14255... # foo j >> alx@debian:~/tmp/brebase$ echo j >foo >> alx@debian:~/tmp/brebase$ git add foo >> alx@debian:~/tmp/brebase$ git rebase --continue >> [detached HEAD e7fdf07fd077] foo j >> 1 file changed, 1 insertion(+), 1 deletion(-) >> Successfully rebased and updated refs/heads/B. >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * e7fdf07fd077 (HEAD -> B) foo j >> * dddf632a735f bar i >> * 7ac284de12ba bar h >> * e4541508ab3e bar e >> * cefec5878c67 baz f >> | * 6c7952d6fec5 (C) bar l >> | * bd43684f73c8 bar k >> | * 30e2d96b3da5 (A) bar h >> | * 01702a5b5d6b bar g >> | |\ >> | | * c961883d543a bar e >> | |/ >> |/| >> | * e17aadb725c4 baz f >> |/ >> * dfd9156d099a (r/main, main) foo d >> * 4940c7d739be bar c >> * cebc8fde25bb foo b >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | |/ >> |/| >> | * c496b325576f baz f >> |/ >> * 1dcb901ebf60 foo a >> alx@debian:~/tmp/brebase$ git brebase A >> Rebase: success >> alx@debian:~/tmp/brebase$ git log --all --graph --oneline >> * 1201c4f20b19 (HEAD -> B) foo j >> * 44103f51a783 bar i >> | * 6c7952d6fec5 (C) bar l >> | * bd43684f73c8 bar k >> |/ >> * 30e2d96b3da5 (A) bar h >> * 01702a5b5d6b bar g >> |\ >> | * c961883d543a bar e >> * | e17aadb725c4 baz f >> |/ >> * dfd9156d099a (r/main, main) foo d >> * 4940c7d739be bar c >> * cebc8fde25bb foo b >> | * ada8aff4f08a (r/B) foo j >> | * d6163efdc2db bar i >> | | * 450f3a7f4f25 (r/HEAD, r/C) bar l >> | | * f7309b21ebfa bar k >> | |/ >> | * e949e24ba457 (r/A) bar h >> | * 607b450498be bar g >> | |\ >> | | * b787bcd373d9 bar e >> | |/ >> |/| >> | * c496b325576f baz f >> |/ >> * 1dcb901ebf60 foo a >> >> This would be impossible with an approach that handles all the way until >> the end. I need to be able to stop a bisect-rebase operation on one >> branch in the middle, then do a bisect-rebase on its descendants, then >> come back to bisect-rebase the parent branch. Does this make sense? >> >> >> Have a lovely day! >> Alex >> >> >>> >>> Thanks >>> >>> Phillip >>> >>> >>>> That's of course more involved though, so I understand in case you're >>>> not interested in doing that. >>>> >>>>> If not, I will likely provide it in the man-pages repository as a help >>>>> tool (which might end up packed by distros as part of manpages-utils). >>>>> Is that okay to you? (I ask mainly because it's using the git- >>>>> namespace for commands, so you should at lease be aware of it.) >>>> >>>> I mean overall this is our primary way of extension, by picking up >>>> utilities that have the "git-" prefix. So arguably you don't have to ask >>>> us for permission to do that. >>>> >>>> Whether it makes sense to distribute such a tool as part of >>>> manpages-utils is a different question, and one where I myself am of a >>>> split mind. But that feels more like a question for distributors rather >>>> than for us in the Git project. >>>> >>>> Thanks! >>>> >>>> Patrick >>> >> >> -- >> <https://www.alejandro-colomar.es> > > > ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-06 14:01 ` git-rebase-walk Phillip Wood @ 2026-10-06 14:58 ` Nico Williams 2026-10-06 16:45 ` git-rebase-walk Alejandro Colomar 2026-10-08 22:05 ` git-rebase-walk Alejandro Colomar 1 sibling, 1 reply; 23+ messages in thread From: Nico Williams @ 2026-10-06 14:58 UTC (permalink / raw) To: phillip.wood; +Cc: Alejandro Colomar, Patrick Steinhardt, git On Tue, Oct 06, 2026 at 03:01:29PM +0100, Phillip Wood wrote: > On 05/10/2026 14:37, Alejandro Colomar wrote: > > > Below is a shell session performing such a rebase, which hopefully shows > > > why I need this to be multi-shot. > > To me it shows that we need to improve "git rebase --update-refs" so that it > can rebase a tree of branches automatically. Doing it manually is labor > intensive and error-prone (your example output shows it is easy to forget > when you're meant to be resolving a conflict instead aborting the rebase and > checking out another branch). In the example below > > git rebase --update-refs --rebase-merges main B > > will rebase A and B, but we don't have a way of including C. But it's not the same problem. This isn't about rebasing a set of stacked branches all at once. This is about rebasing quickly across thousands of upstream commits. Naturally one _could_ use `--update-refs` with a bisect-rebase. The two features are orthogonal. I've been using this bisect-rebase script to rebase an old branch off PG to the latest upstream -- that's 10,135 commits in my case(!). > > > On the simpler case of a single branch, I'd still prefer a multi-shot > > > approach where --continue only advances one rebase operation, because at > > > the end of it I want to stop, and check git-range-diff(1) to make sure > > > it all makes sense. > > Perhaps we could insert "break" commands after each branch is rebased so the > user can check the range-diff. The bisect-rebase scripts do stop when a conflict is found that the user should resolve. The noise from the bisection's search for that appropriate commit is not that interesting except as a sort of progress meter. Stopping at each point in the bisection where the bisection would continue is not going to be that useful unless the user could check if the conflicts are simple and obvious enough at each point and skip the rest of the bisection -- is that your idea? But if so then the bisection will be very painful if the user would mostly elect to continue it. That could be an option -- if it works, great, and if not start over without that option. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-06 14:58 ` git-rebase-walk Nico Williams @ 2026-10-06 16:45 ` Alejandro Colomar 0 siblings, 0 replies; 23+ messages in thread From: Alejandro Colomar @ 2026-10-06 16:45 UTC (permalink / raw) To: Nico Williams; +Cc: phillip.wood, Patrick Steinhardt, git [-- Attachment #1: Type: text/plain, Size: 4753 bytes --] Hi Nico, Phillip, > Date: 2026-10-06 09:58:24-0500 > From: Nico Williams <nico@cryptonector.com> > > On Tue, Oct 06, 2026 at 03:01:29PM +0100, Phillip Wood wrote: > > On 05/10/2026 14:37, Alejandro Colomar wrote: > > > > Below is a shell session performing such a rebase, which hopefully shows > > > > why I need this to be multi-shot. > > > > To me it shows that we need to improve "git rebase --update-refs" so that it > > can rebase a tree of branches automatically. Doing it manually is labor > > intensive and error-prone (your example output shows it is easy to forget > > when you're meant to be resolving a conflict instead aborting the rebase and > > checking out another branch). It's easy to forget, but that's inconsequential. What happened if I abort and try again is that I'll meet the conflict again. It's like there's a barrier, and I won't cross it until I decide to cross it. The very worst case is when bisect-rebase presents a conflict and you forget to abort before solving it (to bring children closer before the conflict), is that I'd have to resolve the conflict twice. You face it a few times, then you learn it. But aborting too much is not a problem. That doesn't increase your work. It's just one more command, but the same amount of conflict resolutions. To summarize: aborting too much is fine (which is what happened to me); forgetting to abort will lead to having to resolve the same conflict twice (you'll eventually learn to abort early, even a bit too much, just in case). > > In the example below > > > > git rebase --update-refs --rebase-merges main B > > > > will rebase A and B, but we don't have a way of including C. --update-refs would need to present conflicts too. After each conflict, I --abort the current rebase, and do a bisect-rebase for each child that brings childs into place. Those bisect-rebase may themselves present conflicts, which must be resolved immediately (before continuing the main bisect-rebase), in case there are no grandchilds; but if there are grandchilds, that also needs to be aborted, and grandchilds need to be bisect-rebased to the child. It's a recursive problem, and I don't think we want to get into implementing a recursive rebase within rebase. Plus, the order in which the recursion is made could be problematic (I may prefer to tackle the branches in a certain order, due to personal preferences). It's not easy. For now, I think the safest thing is to keep it multi-shot. Once you're familiar with the interface, we may discuss whether it can be integrated into git-rebase(1). Please, play with it for some time. Try it with trees of branches, and see how it works, and what you'd improve from it. I've used it to rebase some very old work of mine that had never found the energy to rebase. And it was amazing! Nico seems to be having the same experience. I'm not convinced I'd have the same experience. > But it's not the same problem. This isn't about rebasing a set of > stacked branches all at once. This is about rebasing quickly across > thousands of upstream commits. > > Naturally one _could_ use `--update-refs` with a bisect-rebase. The two > features are orthogonal. > > I've been using this bisect-rebase script to rebase an old branch off PG > to the latest upstream -- that's 10,135 commits in my case(!). > > > > > On the simpler case of a single branch, I'd still prefer a multi-shot > > > > approach where --continue only advances one rebase operation, because at > > > > the end of it I want to stop, and check git-range-diff(1) to make sure > > > > it all makes sense. > > > > Perhaps we could insert "break" commands after each branch is rebased so the > > user can check the range-diff. > > The bisect-rebase scripts do stop when a conflict is found that the user > should resolve. The noise from the bisection's search for that > appropriate commit is not that interesting except as a sort of progress > meter. Stopping at each point in the bisection where the bisection > would continue is not going to be that useful unless the user could > check if the conflicts are simple and obvious enough at each point and > skip the rest of the bisection -- is that your idea? But if so then the > bisection will be very painful if the user would mostly elect to > continue it. That could be an option -- if it works, great, and if not > start over without that option. I guess we could insert break points at the end only in the rebases that are known to fail (the "conflicting rebase" at the end of my script). That "could" work. I'm not convinced though. Cheers, Alex -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-06 14:01 ` git-rebase-walk Phillip Wood 2026-10-06 14:58 ` git-rebase-walk Nico Williams @ 2026-10-08 22:05 ` Alejandro Colomar 2026-10-08 22:07 ` git-rebase-walk Alejandro Colomar 1 sibling, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-08 22:05 UTC (permalink / raw) To: phillip.wood; +Cc: Patrick Steinhardt, git, Nico Williams [-- Attachment #1: Type: text/plain, Size: 23472 bytes --] Hi Philipp, > Date: 2026-10-06 15:01:29+0100 > From: Phillip Wood <phillip.wood123@gmail.com> > > Hi Alejandro > > On 05/10/2026 14:37, Alejandro Colomar wrote: > > > Date: 2026-10-05 15:28:28+0200 > > > From: Alejandro Colomar <alx@kernel.org> > > > > Date: 2026-10-04 11:03:39+0100 > > > > From: Phillip Wood <phillip.wood123@gmail.com> > > > > > > > > I agree that would be the best way forward. Adding an "--incremental", or > > > > "--progressive" option to rebase would be useful I think. For ease of use, I > > > > have a strong preference for an implementation where "rebase --continue" > > > > handles rebasing onto progressively more recent bases, rather than the multi > > > > shot approach where the user has to run "git rebase --incremental" multiple > > > > times. Having a multi-shot approach makes it much less clear when we've > > > > successfully rebased onto the desired base. > > > > > > For rebasing a single branch, having --continue do what you suggest > > > wouldn't be too problematic. > > > > > > However, for when rebasing a tree of branches, I really need a > > > multi-shot operation, since I want to advance branches in a very > > > specific order. > > > > > > Below is a shell session performing such a rebase, which hopefully shows > > > why I need this to be multi-shot. > > To me it shows that we need to improve "git rebase --update-refs" so that it > can rebase a tree of branches automatically. Doing it manually is labor > intensive and error-prone (your example output shows it is easy to forget > when you're meant to be resolving a conflict instead aborting the rebase and > checking out another branch). In the example below > > git rebase --update-refs --rebase-merges main B > > will rebase A and B, but we don't have a way of including C. > > > On the simpler case of a single branch, I'd still prefer a multi-shot > > > approach where --continue only advances one rebase operation, because at > > > the end of it I want to stop, and check git-range-diff(1) to make sure > > > it all makes sense. > > Perhaps we could insert "break" commands after each branch is rebased so the > user can check the range-diff. I've done something different: I've implemented --abort/--continue/--quit in git-bisect-rebase, which do something different than in git-rebase(1). 'git bisect-rebase --abort' returns to the original HEAD, and cleans up any temporary stuff. It can be run at any time. 'git bisect-rebase --continue' restarts the whole bisect-rebase process. The current (conflicting) rebase must be resolved before (or it fails, and prints an error message). 'git bisect-rebase --quit' exist the bisect-rebase session, without moving the HEAD nor the branch from their last position. I can use this to quit a bisect-rebase operation with one branch right before solving a conflict, then move all descentands into it, then come back to moving the original branch. So, the usual algorithm for moving a tree would be: $ git bisect-rebase master A; $ git rebase --abort; $ git bisect-rebase --quit; $ git bisect-rebase A B; ## ... until success $ git bisect-rebase A C; ## ... until success $ git tag tmpA; $ git bisect-rebase master A; ## resolve conflicts here $ git rebase --continue; $ git bisect-rebase --quit; $ git rebase --onto A tmpA B; $ git rebase --onto A tmpA B; $ git tag -d tmpA; ## ... rinse and repeat (goto first command, until no conflicts) And the algorithm for moving a single branch would be simpler: $ git bisect-rebase master X; ## resolve conflicts here $ git rebase --continue; $ git bisect-rebase --continue; ## ... rinse and repeat (goto first command, until no conflicts) I've been trying both, and they both seem nice. Have a lovely night! Alex > > Thanks > > Phillip > > > > > I've indented the output of commands, so that they are easier to > > > distinguish. > > > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * G ada8aff4f08a (r/B, B) foo j > > > * G d6163efdc2db bar i > > > | * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > | * G f7309b21ebfa bar k > > > |/ > > > * G e949e24ba457 (HEAD -> A, r/A) bar h > > > * G 607b450498be bar g > > > |\ > > > | * G b787bcd373d9 bar e > > > * | G c496b325576f baz f > > > |/ > > > | * G dfd9156d099a (r/main, main) foo d > > > | * G 4940c7d739be bar c > > > | * G cebc8fde25bb foo b > > > |/ > > > * G 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > Rebase: conflict > > > Bisecting: 0 revisions left to test after this (roughly 1 step) > > > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: success > > > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > > > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > > > Author: Alejandro Colomar <alx@kernel.org> > > > Date: 2026-10-05 14:42:32 +0200 > > > > > > bar c > > > > > > bar | 1 + > > > 1 file changed, 1 insertion(+) > > > create mode 100644 bar > > > bisect found first 'bad' commit > > > Auto-merging bar > > > CONFLICT (add/add): Merge conflict in bar > > > error: could not apply 899eeb5c4e32... bar e > > > hint: Resolve all conflicts manually, mark them as resolved with > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > hint: You can instead skip this commit: run "git rebase --skip". > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > Could not apply 899eeb5c4e32... # bar e > > > alx@debian:~/tmp/brebase$ git rebase --abort > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 655c38e3cee8 (HEAD -> A) bar h > > > * 1ababced193d bar g > > > |\ > > > | * 899eeb5c4e32 bar e > > > * | 761c9dbcfa5b baz f > > > |/ > > > | * ada8aff4f08a (r/B, B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | * | c496b325576f baz f > > > | |/ > > > | | * dfd9156d099a (r/main, main) foo d > > > | | * 4940c7d739be bar c > > > | |/ > > > |/| > > > * | cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git switch B > > > Switched to branch 'B' > > > Your branch is up to date with 'r/B'. > > > alx@debian:~/tmp/brebase$ git brebase A > > > Rebase: conflict > > > Bisecting: 2 revisions left to test after this (roughly 1 step) > > > [899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit > > > commit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 > > > Author: Alejandro Colomar <alx@kernel.org> > > > Date: 2026-10-05 14:42:04 +0200 > > > > > > foo b > > > > > > foo | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > bisect found first 'bad' commit > > > Auto-merging foo > > > CONFLICT (content): Merge conflict in foo > > > error: could not apply ada8aff4f08a... foo j > > > hint: Resolve all conflicts manually, mark them as resolved with > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > hint: You can instead skip this commit: run "git rebase --skip". > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > Could not apply ada8aff4f08a... # foo j > > > alx@debian:~/tmp/brebase$ echo j >foo > > > alx@debian:~/tmp/brebase$ git add foo > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > [detached HEAD 2e0b72e7440a] foo j > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > Successfully rebased and updated refs/heads/B. > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 2e0b72e7440a (HEAD -> B) foo j > > > * a1c6c1fb7ca2 bar i > > > * d8fa6c4da463 bar h > > > * bef9f1c4da4d bar e > > > * 0bac26895b94 baz f > > > | * 655c38e3cee8 (A) bar h > > > | * 1ababced193d bar g > > > | |\ > > > | | * 899eeb5c4e32 bar e > > > | |/ > > > |/| > > > | * 761c9dbcfa5b baz f > > > |/ > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | * | c496b325576f baz f > > > | |/ > > > | | * dfd9156d099a (r/main, main) foo d > > > | | * 4940c7d739be bar c > > > | |/ > > > |/| > > > * | cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git brebase A > > > Rebase: success > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 5ff93a00f9f2 (HEAD -> B) foo j > > > * 01522206a7bc bar i > > > * 655c38e3cee8 (A) bar h > > > * 1ababced193d bar g > > > |\ > > > | * 899eeb5c4e32 bar e > > > * | 761c9dbcfa5b baz f > > > |/ > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | * | c496b325576f baz f > > > | |/ > > > | | * dfd9156d099a (r/main, main) foo d > > > | | * 4940c7d739be bar c > > > | |/ > > > |/| > > > * | cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git switch C > > > Switched to branch 'C' > > > alx@debian:~/tmp/brebase$ git brebase A > > > Rebase: success > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 06d462903420 (HEAD -> C) bar l > > > * 20f0a887b83b bar k > > > | * 5ff93a00f9f2 (B) foo j > > > | * 01522206a7bc bar i > > > |/ > > > * 655c38e3cee8 (A) bar h > > > * 1ababced193d bar g > > > |\ > > > | * 899eeb5c4e32 bar e > > > * | 761c9dbcfa5b baz f > > > |/ > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | * | c496b325576f baz f > > > | |/ > > > | | * dfd9156d099a (r/main, main) foo d > > > | | * 4940c7d739be bar c > > > | |/ > > > |/| > > > * | cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git switch A > > > Switched to branch 'A' > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > Rebase: conflict > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > > > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > > > Author: Alejandro Colomar <alx@kernel.org> > > > Date: 2026-10-05 14:42:32 +0200 > > > > > > bar c > > > > > > bar | 1 + > > > 1 file changed, 1 insertion(+) > > > create mode 100644 bar > > > bisect found first 'bad' commit > > > Auto-merging bar > > > CONFLICT (add/add): Merge conflict in bar > > > error: could not apply 899eeb5c4e32... bar e > > > hint: Resolve all conflicts manually, mark them as resolved with > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > hint: You can instead skip this commit: run "git rebase --skip". > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > Could not apply 899eeb5c4e32... # bar e > > > alx@debian:~/tmp/brebase$ echo e >bar > > > alx@debian:~/tmp/brebase$ git add bar > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > [detached HEAD 2a4fa7fe2f44] bar e > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > Successfully rebased and updated refs/heads/A. > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 0954f3d9b9e1 (HEAD -> A) bar h > > > * 4f09c21bf2ca bar g > > > |\ > > > | * 2a4fa7fe2f44 bar e > > > * | e42246e75159 baz f > > > |/ > > > | * 06d462903420 (C) bar l > > > | * 20f0a887b83b bar k > > > | | * 5ff93a00f9f2 (B) foo j > > > | | * 01522206a7bc bar i > > > | |/ > > > | * 655c38e3cee8 bar h > > > | * 1ababced193d bar g > > > | |\ > > > | | * 899eeb5c4e32 bar e > > > | * | 761c9dbcfa5b baz f > > > | |/ > > > | | * ada8aff4f08a (r/B) foo j > > > | | * d6163efdc2db bar i > > > | | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | | * f7309b21ebfa bar k > > > | | |/ > > > | | * e949e24ba457 (r/A) bar h > > > | | * 607b450498be bar g > > > | | |\ > > > | | | * b787bcd373d9 bar e > > > | | * | c496b325576f baz f > > > | | |/ > > > | | | * dfd9156d099a (r/main, main) foo d > > > | |_|/ > > > |/| | > > > * | | 4940c7d739be bar c > > > |/ / > > > * / cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B > > > Successfully rebased and updated refs/heads/B. > > > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C > > > Successfully rebased and updated refs/heads/C. > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 4a4ba76f55a4 (HEAD -> C) bar l > > > * 86350e1490f3 bar k > > > | * 4b6b40b14255 (B) foo j > > > | * ba5a233ee4bc bar i > > > |/ > > > * 0954f3d9b9e1 (A) bar h > > > * 4f09c21bf2ca bar g > > > |\ > > > | * 2a4fa7fe2f44 bar e > > > * | e42246e75159 baz f > > > |/ > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | * | c496b325576f baz f > > > | |/ > > > | | * dfd9156d099a (r/main, main) foo d > > > | |/ > > > |/| > > > * | 4940c7d739be bar c > > > * | cebc8fde25bb foo b > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git switch A > > > Switched to branch 'A' > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > Rebase: success > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 30e2d96b3da5 (HEAD -> A) bar h > > > * 01702a5b5d6b bar g > > > |\ > > > | * c961883d543a bar e > > > * | e17aadb725c4 baz f > > > |/ > > > * dfd9156d099a (r/main, main) foo d > > > | * 4a4ba76f55a4 (C) bar l > > > | * 86350e1490f3 bar k > > > | | * 4b6b40b14255 (B) foo j > > > | | * ba5a233ee4bc bar i > > > | |/ > > > | * 0954f3d9b9e1 bar h > > > | * 4f09c21bf2ca bar g > > > | |\ > > > | | * 2a4fa7fe2f44 bar e > > > | |/ > > > |/| > > > | * e42246e75159 baz f > > > |/ > > > * 4940c7d739be bar c > > > * cebc8fde25bb foo b > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | |/ > > > |/| > > > | * c496b325576f baz f > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C > > > Successfully rebased and updated refs/heads/C. > > > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B > > > Auto-merging foo > > > CONFLICT (content): Merge conflict in foo > > > error: could not apply 4b6b40b14255... foo j > > > hint: Resolve all conflicts manually, mark them as resolved with > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > hint: You can instead skip this commit: run "git rebase --skip". > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > Could not apply 4b6b40b14255... # foo j > > > alx@debian:~/tmp/brebase$ git rebase --abort > > > > Oh, this was a mistake; I should have resolved the conflict here > > instead of using brebase below. (brebase produced the same exact > > conflict). :) > > > > > > Cheers, > > Alex > > > > > alx@debian:~/tmp/brebase$ git switch B > > > Already on 'B' > > > Your branch and 'r/B' have diverged, > > > and have 8 and 6 different commits each, respectively. > > > (use "git pull" if you want to integrate the remote branch with yours) > > > alx@debian:~/tmp/brebase$ git brebase A > > > Rebase: conflict > > > Bisecting: 2 revisions left to test after this (roughly 1 step) > > > [c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > [dfd9156d099ad3507a2850294c7a584b80712f04] foo d > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > Rebase: conflict > > > dfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit > > > commit dfd9156d099ad3507a2850294c7a584b80712f04 > > > Author: Alejandro Colomar <alx@kernel.org> > > > Date: 2026-10-05 14:42:50 +0200 > > > > > > foo d > > > > > > foo | 2 +- > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > bisect found first 'bad' commit > > > Auto-merging foo > > > CONFLICT (content): Merge conflict in foo > > > error: could not apply 4b6b40b14255... foo j > > > hint: Resolve all conflicts manually, mark them as resolved with > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > hint: You can instead skip this commit: run "git rebase --skip". > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > Could not apply 4b6b40b14255... # foo j > > > alx@debian:~/tmp/brebase$ echo j >foo > > > alx@debian:~/tmp/brebase$ git add foo > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > [detached HEAD e7fdf07fd077] foo j > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > Successfully rebased and updated refs/heads/B. > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * e7fdf07fd077 (HEAD -> B) foo j > > > * dddf632a735f bar i > > > * 7ac284de12ba bar h > > > * e4541508ab3e bar e > > > * cefec5878c67 baz f > > > | * 6c7952d6fec5 (C) bar l > > > | * bd43684f73c8 bar k > > > | * 30e2d96b3da5 (A) bar h > > > | * 01702a5b5d6b bar g > > > | |\ > > > | | * c961883d543a bar e > > > | |/ > > > |/| > > > | * e17aadb725c4 baz f > > > |/ > > > * dfd9156d099a (r/main, main) foo d > > > * 4940c7d739be bar c > > > * cebc8fde25bb foo b > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | |/ > > > |/| > > > | * c496b325576f baz f > > > |/ > > > * 1dcb901ebf60 foo a > > > alx@debian:~/tmp/brebase$ git brebase A > > > Rebase: success > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > * 1201c4f20b19 (HEAD -> B) foo j > > > * 44103f51a783 bar i > > > | * 6c7952d6fec5 (C) bar l > > > | * bd43684f73c8 bar k > > > |/ > > > * 30e2d96b3da5 (A) bar h > > > * 01702a5b5d6b bar g > > > |\ > > > | * c961883d543a bar e > > > * | e17aadb725c4 baz f > > > |/ > > > * dfd9156d099a (r/main, main) foo d > > > * 4940c7d739be bar c > > > * cebc8fde25bb foo b > > > | * ada8aff4f08a (r/B) foo j > > > | * d6163efdc2db bar i > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > | | * f7309b21ebfa bar k > > > | |/ > > > | * e949e24ba457 (r/A) bar h > > > | * 607b450498be bar g > > > | |\ > > > | | * b787bcd373d9 bar e > > > | |/ > > > |/| > > > | * c496b325576f baz f > > > |/ > > > * 1dcb901ebf60 foo a > > > > > > This would be impossible with an approach that handles all the way until > > > the end. I need to be able to stop a bisect-rebase operation on one > > > branch in the middle, then do a bisect-rebase on its descendants, then > > > come back to bisect-rebase the parent branch. Does this make sense? > > > > > > > > > Have a lovely day! > > > Alex > > > > > > > > > > > > > > Thanks > > > > > > > > Phillip > > > > > > > > > > > > > That's of course more involved though, so I understand in case you're > > > > > not interested in doing that. > > > > > > > > > > > If not, I will likely provide it in the man-pages repository as a help > > > > > > tool (which might end up packed by distros as part of manpages-utils). > > > > > > Is that okay to you? (I ask mainly because it's using the git- > > > > > > namespace for commands, so you should at lease be aware of it.) > > > > > > > > > > I mean overall this is our primary way of extension, by picking up > > > > > utilities that have the "git-" prefix. So arguably you don't have to ask > > > > > us for permission to do that. > > > > > > > > > > Whether it makes sense to distribute such a tool as part of > > > > > manpages-utils is a different question, and one where I myself am of a > > > > > split mind. But that feels more like a question for distributors rather > > > > > than for us in the Git project. > > > > > > > > > > Thanks! > > > > > > > > > > Patrick > > > > > > > > > > -- > > > <https://www.alejandro-colomar.es> > > > > > > > -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-08 22:05 ` git-rebase-walk Alejandro Colomar @ 2026-10-08 22:07 ` Alejandro Colomar 0 siblings, 0 replies; 23+ messages in thread From: Alejandro Colomar @ 2026-10-08 22:07 UTC (permalink / raw) To: phillip.wood; +Cc: Patrick Steinhardt, git, Nico Williams [-- Attachment #1: Type: text/plain, Size: 24932 bytes --] > Date: 2026-10-09 00:05:47+0200 > From: Alejandro Colomar <alx@kernel.org> > > Hi Philipp, > > > Date: 2026-10-06 15:01:29+0100 > > From: Phillip Wood <phillip.wood123@gmail.com> > > > > Hi Alejandro > > > > On 05/10/2026 14:37, Alejandro Colomar wrote: > > > > Date: 2026-10-05 15:28:28+0200 > > > > From: Alejandro Colomar <alx@kernel.org> > > > > > Date: 2026-10-04 11:03:39+0100 > > > > > From: Phillip Wood <phillip.wood123@gmail.com> > > > > > > > > > > I agree that would be the best way forward. Adding an "--incremental", or > > > > > "--progressive" option to rebase would be useful I think. For ease of use, I > > > > > have a strong preference for an implementation where "rebase --continue" > > > > > handles rebasing onto progressively more recent bases, rather than the multi > > > > > shot approach where the user has to run "git rebase --incremental" multiple > > > > > times. Having a multi-shot approach makes it much less clear when we've > > > > > successfully rebased onto the desired base. > > > > > > > > For rebasing a single branch, having --continue do what you suggest > > > > wouldn't be too problematic. > > > > > > > > However, for when rebasing a tree of branches, I really need a > > > > multi-shot operation, since I want to advance branches in a very > > > > specific order. > > > > > > > > Below is a shell session performing such a rebase, which hopefully shows > > > > why I need this to be multi-shot. > > > > To me it shows that we need to improve "git rebase --update-refs" so that it > > can rebase a tree of branches automatically. Doing it manually is labor > > intensive and error-prone (your example output shows it is easy to forget > > when you're meant to be resolving a conflict instead aborting the rebase and > > checking out another branch). In the example below > > > > git rebase --update-refs --rebase-merges main B > > > > will rebase A and B, but we don't have a way of including C. > > > > On the simpler case of a single branch, I'd still prefer a multi-shot > > > > approach where --continue only advances one rebase operation, because at > > > > the end of it I want to stop, and check git-range-diff(1) to make sure > > > > it all makes sense. > > > > Perhaps we could insert "break" commands after each branch is rebased so the > > user can check the range-diff. > > I've done something different: > > I've implemented --abort/--continue/--quit in git-bisect-rebase, which > do something different than in git-rebase(1). > > 'git bisect-rebase --abort' returns to the original HEAD, and cleans up > any temporary stuff. It can be run at any time. > > 'git bisect-rebase --continue' restarts the whole bisect-rebase process. > The current (conflicting) rebase must be resolved before (or it fails, > and prints an error message). > > 'git bisect-rebase --quit' exist the bisect-rebase session, without > moving the HEAD nor the branch from their last position. I can use this > to quit a bisect-rebase operation with one branch right before solving > a conflict, then move all descentands into it, then come back to moving > the original branch. > > > So, the usual algorithm for moving a tree would be: > > $ git bisect-rebase master A; > $ git rebase --abort; > $ git bisect-rebase --quit; > $ git bisect-rebase A B; > ## ... until success > $ git bisect-rebase A C; > ## ... until success > $ git tag tmpA; > $ git bisect-rebase master A; > ## resolve conflicts here > $ git rebase --continue; > $ git bisect-rebase --quit; > $ git rebase --onto A tmpA B; > $ git rebase --onto A tmpA B; This one meant to use C instead of B. Cheers, Alex > $ git tag -d tmpA; > ## ... rinse and repeat (goto first command, until no conflicts) > > And the algorithm for moving a single branch would be simpler: > > $ git bisect-rebase master X; > ## resolve conflicts here > $ git rebase --continue; > $ git bisect-rebase --continue; > ## ... rinse and repeat (goto first command, until no conflicts) > > I've been trying both, and they both seem nice. > > > Have a lovely night! > Alex > > > > > Thanks > > > > Phillip > > > > > > > > I've indented the output of commands, so that they are easier to > > > > distinguish. > > > > > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * G ada8aff4f08a (r/B, B) foo j > > > > * G d6163efdc2db bar i > > > > | * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > > | * G f7309b21ebfa bar k > > > > |/ > > > > * G e949e24ba457 (HEAD -> A, r/A) bar h > > > > * G 607b450498be bar g > > > > |\ > > > > | * G b787bcd373d9 bar e > > > > * | G c496b325576f baz f > > > > |/ > > > > | * G dfd9156d099a (r/main, main) foo d > > > > | * G 4940c7d739be bar c > > > > | * G cebc8fde25bb foo b > > > > |/ > > > > * G 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > > Rebase: conflict > > > > Bisecting: 0 revisions left to test after this (roughly 1 step) > > > > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: success > > > > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > > > > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > > > > Author: Alejandro Colomar <alx@kernel.org> > > > > Date: 2026-10-05 14:42:32 +0200 > > > > > > > > bar c > > > > > > > > bar | 1 + > > > > 1 file changed, 1 insertion(+) > > > > create mode 100644 bar > > > > bisect found first 'bad' commit > > > > Auto-merging bar > > > > CONFLICT (add/add): Merge conflict in bar > > > > error: could not apply 899eeb5c4e32... bar e > > > > hint: Resolve all conflicts manually, mark them as resolved with > > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > > hint: You can instead skip this commit: run "git rebase --skip". > > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > > Could not apply 899eeb5c4e32... # bar e > > > > alx@debian:~/tmp/brebase$ git rebase --abort > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 655c38e3cee8 (HEAD -> A) bar h > > > > * 1ababced193d bar g > > > > |\ > > > > | * 899eeb5c4e32 bar e > > > > * | 761c9dbcfa5b baz f > > > > |/ > > > > | * ada8aff4f08a (r/B, B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | * | c496b325576f baz f > > > > | |/ > > > > | | * dfd9156d099a (r/main, main) foo d > > > > | | * 4940c7d739be bar c > > > > | |/ > > > > |/| > > > > * | cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git switch B > > > > Switched to branch 'B' > > > > Your branch is up to date with 'r/B'. > > > > alx@debian:~/tmp/brebase$ git brebase A > > > > Rebase: conflict > > > > Bisecting: 2 revisions left to test after this (roughly 1 step) > > > > [899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > > [cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit > > > > commit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6 > > > > Author: Alejandro Colomar <alx@kernel.org> > > > > Date: 2026-10-05 14:42:04 +0200 > > > > > > > > foo b > > > > > > > > foo | 2 +- > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > bisect found first 'bad' commit > > > > Auto-merging foo > > > > CONFLICT (content): Merge conflict in foo > > > > error: could not apply ada8aff4f08a... foo j > > > > hint: Resolve all conflicts manually, mark them as resolved with > > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > > hint: You can instead skip this commit: run "git rebase --skip". > > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > > Could not apply ada8aff4f08a... # foo j > > > > alx@debian:~/tmp/brebase$ echo j >foo > > > > alx@debian:~/tmp/brebase$ git add foo > > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > > [detached HEAD 2e0b72e7440a] foo j > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > Successfully rebased and updated refs/heads/B. > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 2e0b72e7440a (HEAD -> B) foo j > > > > * a1c6c1fb7ca2 bar i > > > > * d8fa6c4da463 bar h > > > > * bef9f1c4da4d bar e > > > > * 0bac26895b94 baz f > > > > | * 655c38e3cee8 (A) bar h > > > > | * 1ababced193d bar g > > > > | |\ > > > > | | * 899eeb5c4e32 bar e > > > > | |/ > > > > |/| > > > > | * 761c9dbcfa5b baz f > > > > |/ > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | * | c496b325576f baz f > > > > | |/ > > > > | | * dfd9156d099a (r/main, main) foo d > > > > | | * 4940c7d739be bar c > > > > | |/ > > > > |/| > > > > * | cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git brebase A > > > > Rebase: success > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 5ff93a00f9f2 (HEAD -> B) foo j > > > > * 01522206a7bc bar i > > > > * 655c38e3cee8 (A) bar h > > > > * 1ababced193d bar g > > > > |\ > > > > | * 899eeb5c4e32 bar e > > > > * | 761c9dbcfa5b baz f > > > > |/ > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | * | c496b325576f baz f > > > > | |/ > > > > | | * dfd9156d099a (r/main, main) foo d > > > > | | * 4940c7d739be bar c > > > > | |/ > > > > |/| > > > > * | cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git switch C > > > > Switched to branch 'C' > > > > alx@debian:~/tmp/brebase$ git brebase A > > > > Rebase: success > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 06d462903420 (HEAD -> C) bar l > > > > * 20f0a887b83b bar k > > > > | * 5ff93a00f9f2 (B) foo j > > > > | * 01522206a7bc bar i > > > > |/ > > > > * 655c38e3cee8 (A) bar h > > > > * 1ababced193d bar g > > > > |\ > > > > | * 899eeb5c4e32 bar e > > > > * | 761c9dbcfa5b baz f > > > > |/ > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | * | c496b325576f baz f > > > > | |/ > > > > | | * dfd9156d099a (r/main, main) foo d > > > > | | * 4940c7d739be bar c > > > > | |/ > > > > |/| > > > > * | cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git switch A > > > > Switched to branch 'A' > > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > > Rebase: conflict > > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > > [4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > 4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit > > > > commit 4940c7d739be44c0ca32c1d610b85fd5650e1528 > > > > Author: Alejandro Colomar <alx@kernel.org> > > > > Date: 2026-10-05 14:42:32 +0200 > > > > > > > > bar c > > > > > > > > bar | 1 + > > > > 1 file changed, 1 insertion(+) > > > > create mode 100644 bar > > > > bisect found first 'bad' commit > > > > Auto-merging bar > > > > CONFLICT (add/add): Merge conflict in bar > > > > error: could not apply 899eeb5c4e32... bar e > > > > hint: Resolve all conflicts manually, mark them as resolved with > > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > > hint: You can instead skip this commit: run "git rebase --skip". > > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > > Could not apply 899eeb5c4e32... # bar e > > > > alx@debian:~/tmp/brebase$ echo e >bar > > > > alx@debian:~/tmp/brebase$ git add bar > > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > > [detached HEAD 2a4fa7fe2f44] bar e > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > Successfully rebased and updated refs/heads/A. > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 0954f3d9b9e1 (HEAD -> A) bar h > > > > * 4f09c21bf2ca bar g > > > > |\ > > > > | * 2a4fa7fe2f44 bar e > > > > * | e42246e75159 baz f > > > > |/ > > > > | * 06d462903420 (C) bar l > > > > | * 20f0a887b83b bar k > > > > | | * 5ff93a00f9f2 (B) foo j > > > > | | * 01522206a7bc bar i > > > > | |/ > > > > | * 655c38e3cee8 bar h > > > > | * 1ababced193d bar g > > > > | |\ > > > > | | * 899eeb5c4e32 bar e > > > > | * | 761c9dbcfa5b baz f > > > > | |/ > > > > | | * ada8aff4f08a (r/B) foo j > > > > | | * d6163efdc2db bar i > > > > | | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | | * f7309b21ebfa bar k > > > > | | |/ > > > > | | * e949e24ba457 (r/A) bar h > > > > | | * 607b450498be bar g > > > > | | |\ > > > > | | | * b787bcd373d9 bar e > > > > | | * | c496b325576f baz f > > > > | | |/ > > > > | | | * dfd9156d099a (r/main, main) foo d > > > > | |_|/ > > > > |/| | > > > > * | | 4940c7d739be bar c > > > > |/ / > > > > * / cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B > > > > Successfully rebased and updated refs/heads/B. > > > > alx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C > > > > Successfully rebased and updated refs/heads/C. > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 4a4ba76f55a4 (HEAD -> C) bar l > > > > * 86350e1490f3 bar k > > > > | * 4b6b40b14255 (B) foo j > > > > | * ba5a233ee4bc bar i > > > > |/ > > > > * 0954f3d9b9e1 (A) bar h > > > > * 4f09c21bf2ca bar g > > > > |\ > > > > | * 2a4fa7fe2f44 bar e > > > > * | e42246e75159 baz f > > > > |/ > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | * | c496b325576f baz f > > > > | |/ > > > > | | * dfd9156d099a (r/main, main) foo d > > > > | |/ > > > > |/| > > > > * | 4940c7d739be bar c > > > > * | cebc8fde25bb foo b > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git switch A > > > > Switched to branch 'A' > > > > alx@debian:~/tmp/brebase$ git brebase --rebase-merges main > > > > Rebase: success > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 30e2d96b3da5 (HEAD -> A) bar h > > > > * 01702a5b5d6b bar g > > > > |\ > > > > | * c961883d543a bar e > > > > * | e17aadb725c4 baz f > > > > |/ > > > > * dfd9156d099a (r/main, main) foo d > > > > | * 4a4ba76f55a4 (C) bar l > > > > | * 86350e1490f3 bar k > > > > | | * 4b6b40b14255 (B) foo j > > > > | | * ba5a233ee4bc bar i > > > > | |/ > > > > | * 0954f3d9b9e1 bar h > > > > | * 4f09c21bf2ca bar g > > > > | |\ > > > > | | * 2a4fa7fe2f44 bar e > > > > | |/ > > > > |/| > > > > | * e42246e75159 baz f > > > > |/ > > > > * 4940c7d739be bar c > > > > * cebc8fde25bb foo b > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | |/ > > > > |/| > > > > | * c496b325576f baz f > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C > > > > Successfully rebased and updated refs/heads/C. > > > > alx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B > > > > Auto-merging foo > > > > CONFLICT (content): Merge conflict in foo > > > > error: could not apply 4b6b40b14255... foo j > > > > hint: Resolve all conflicts manually, mark them as resolved with > > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > > hint: You can instead skip this commit: run "git rebase --skip". > > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > > Could not apply 4b6b40b14255... # foo j > > > > alx@debian:~/tmp/brebase$ git rebase --abort > > > > > > Oh, this was a mistake; I should have resolved the conflict here > > > instead of using brebase below. (brebase produced the same exact > > > conflict). :) > > > > > > > > > Cheers, > > > Alex > > > > > > > alx@debian:~/tmp/brebase$ git switch B > > > > Already on 'B' > > > > Your branch and 'r/B' have diverged, > > > > and have 8 and 6 different commits each, respectively. > > > > (use "git pull" if you want to integrate the remote branch with yours) > > > > alx@debian:~/tmp/brebase$ git brebase A > > > > Rebase: conflict > > > > Bisecting: 2 revisions left to test after this (roughly 1 step) > > > > [c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > Bisecting: 0 revisions left to test after this (roughly 0 steps) > > > > [dfd9156d099ad3507a2850294c7a584b80712f04] foo d > > > > running '.git/bisect-rebase/git-bisect-run-callback' > > > > Rebase: conflict > > > > dfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit > > > > commit dfd9156d099ad3507a2850294c7a584b80712f04 > > > > Author: Alejandro Colomar <alx@kernel.org> > > > > Date: 2026-10-05 14:42:50 +0200 > > > > > > > > foo d > > > > > > > > foo | 2 +- > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > bisect found first 'bad' commit > > > > Auto-merging foo > > > > CONFLICT (content): Merge conflict in foo > > > > error: could not apply 4b6b40b14255... foo j > > > > hint: Resolve all conflicts manually, mark them as resolved with > > > > hint: "git add/rm <conflicted_files>", then run "git rebase --continue". > > > > hint: You can instead skip this commit: run "git rebase --skip". > > > > hint: To abort and get back to the state before "git rebase", run "git rebase --abort". > > > > hint: Disable this message with "git config set advice.mergeConflict false" > > > > Could not apply 4b6b40b14255... # foo j > > > > alx@debian:~/tmp/brebase$ echo j >foo > > > > alx@debian:~/tmp/brebase$ git add foo > > > > alx@debian:~/tmp/brebase$ git rebase --continue > > > > [detached HEAD e7fdf07fd077] foo j > > > > 1 file changed, 1 insertion(+), 1 deletion(-) > > > > Successfully rebased and updated refs/heads/B. > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * e7fdf07fd077 (HEAD -> B) foo j > > > > * dddf632a735f bar i > > > > * 7ac284de12ba bar h > > > > * e4541508ab3e bar e > > > > * cefec5878c67 baz f > > > > | * 6c7952d6fec5 (C) bar l > > > > | * bd43684f73c8 bar k > > > > | * 30e2d96b3da5 (A) bar h > > > > | * 01702a5b5d6b bar g > > > > | |\ > > > > | | * c961883d543a bar e > > > > | |/ > > > > |/| > > > > | * e17aadb725c4 baz f > > > > |/ > > > > * dfd9156d099a (r/main, main) foo d > > > > * 4940c7d739be bar c > > > > * cebc8fde25bb foo b > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | |/ > > > > |/| > > > > | * c496b325576f baz f > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > alx@debian:~/tmp/brebase$ git brebase A > > > > Rebase: success > > > > alx@debian:~/tmp/brebase$ git log --all --graph --oneline > > > > * 1201c4f20b19 (HEAD -> B) foo j > > > > * 44103f51a783 bar i > > > > | * 6c7952d6fec5 (C) bar l > > > > | * bd43684f73c8 bar k > > > > |/ > > > > * 30e2d96b3da5 (A) bar h > > > > * 01702a5b5d6b bar g > > > > |\ > > > > | * c961883d543a bar e > > > > * | e17aadb725c4 baz f > > > > |/ > > > > * dfd9156d099a (r/main, main) foo d > > > > * 4940c7d739be bar c > > > > * cebc8fde25bb foo b > > > > | * ada8aff4f08a (r/B) foo j > > > > | * d6163efdc2db bar i > > > > | | * 450f3a7f4f25 (r/HEAD, r/C) bar l > > > > | | * f7309b21ebfa bar k > > > > | |/ > > > > | * e949e24ba457 (r/A) bar h > > > > | * 607b450498be bar g > > > > | |\ > > > > | | * b787bcd373d9 bar e > > > > | |/ > > > > |/| > > > > | * c496b325576f baz f > > > > |/ > > > > * 1dcb901ebf60 foo a > > > > > > > > This would be impossible with an approach that handles all the way until > > > > the end. I need to be able to stop a bisect-rebase operation on one > > > > branch in the middle, then do a bisect-rebase on its descendants, then > > > > come back to bisect-rebase the parent branch. Does this make sense? > > > > > > > > > > > > Have a lovely day! > > > > Alex > > > > > > > > > > > > > > > > > > Thanks > > > > > > > > > > Phillip > > > > > > > > > > > > > > > > That's of course more involved though, so I understand in case you're > > > > > > not interested in doing that. > > > > > > > > > > > > > If not, I will likely provide it in the man-pages repository as a help > > > > > > > tool (which might end up packed by distros as part of manpages-utils). > > > > > > > Is that okay to you? (I ask mainly because it's using the git- > > > > > > > namespace for commands, so you should at lease be aware of it.) > > > > > > > > > > > > I mean overall this is our primary way of extension, by picking up > > > > > > utilities that have the "git-" prefix. So arguably you don't have to ask > > > > > > us for permission to do that. > > > > > > > > > > > > Whether it makes sense to distribute such a tool as part of > > > > > > manpages-utils is a different question, and one where I myself am of a > > > > > > split mind. But that feels more like a question for distributors rather > > > > > > than for us in the Git project. > > > > > > > > > > > > Thanks! > > > > > > > > > > > > Patrick > > > > > > > > > > > > > -- > > > > <https://www.alejandro-colomar.es> > > > > > > > > > > > > > -- > <https://www.alejandro-colomar.es> -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt 2026-10-01 15:51 ` git-rebase-walk Alejandro Colomar @ 2026-10-01 17:31 ` Junio C Hamano 1 sibling, 0 replies; 23+ messages in thread From: Junio C Hamano @ 2026-10-01 17:31 UTC (permalink / raw) To: Patrick Steinhardt; +Cc: Alejandro Colomar, git Patrick Steinhardt <ps@pks.im> writes: > Maybe that tool is interesting to you. But it's certainly fallen a bit > out of date, as it hasn't received any updates for more than 6 years by > now. Chances are it stll works alright though. > > [1]: https://github.com/mhagger/git-imerge ;-) imerge is one of the best things since sliced bread, and what I still occasinally fall back on when I encounter a really difficult merges and rebases. ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 11:58 git-rebase-walk Alejandro Colomar 2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt @ 2026-10-01 16:10 ` Nico Williams 2026-10-01 16:50 ` git-rebase-walk Alejandro Colomar 2026-10-02 2:49 ` git-rebase-walk Simon Richter 2 siblings, 1 reply; 23+ messages in thread From: Nico Williams @ 2026-10-01 16:10 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git 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"; done But: - you need to add conflict handling - this is very slow I've tried this before, so I know it's very slow if you're rebasing across thousands of upstream commits! Also, you need some extra handling of conflicts. > 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 (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. 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. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 16:10 ` git-rebase-walk Nico Williams @ 2026-10-01 16:50 ` Alejandro Colomar 2026-10-01 17:40 ` git-rebase-walk Nico Williams 0 siblings, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-01 16:50 UTC (permalink / raw) To: Nico Williams; +Cc: git [-- Attachment #1: Type: text/plain, Size: 5039 bytes --] Hi Nico, > 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"; done Actually, 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. > > 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. > > 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. > (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. :) > 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> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 16:50 ` git-rebase-walk Alejandro Colomar @ 2026-10-01 17:40 ` Nico Williams 2026-10-01 20:29 ` git-rebase-walk Alejandro Colomar 0 siblings, 1 reply; 23+ messages in thread From: Nico Williams @ 2026-10-01 17:40 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git On Thu, Oct 01, 2026 at 06:50:08PM +0200, Alejandro Colomar wrote: > > 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. Oh, because of `set -euo pipefail`, hah, yes. > > https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297 > > Hmmm, 93 LoC is certainly more interesting than the 4k+ python script. There is that, indeed. > I'll have a look. I'll also attempt at writing a bisect-rebase from > scratch myself, to compare. I love that attitude! > I'll certainly try your script; thanks! > > Out of curiosity, did you offer this script to git(1)? No, though I think I've mentioned it here before. I'd be happy to submit a patch, but I'd first have to get employer approval for it (which is not a problem -- it will only take time). > If not, why not? No real reason other than bureaucracy on my side. > This is something that would clearly be helpful to people solving rebase > conflicts in many projects. I agree! > Have a lovely night! Cheers! Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 17:40 ` git-rebase-walk Nico Williams @ 2026-10-01 20:29 ` Alejandro Colomar 2026-10-01 21:01 ` git-rebase-walk Nico Williams 0 siblings, 1 reply; 23+ messages in thread From: Alejandro Colomar @ 2026-10-01 20:29 UTC (permalink / raw) To: Nico Williams; +Cc: git [-- Attachment #1: Type: text/plain, Size: 5489 bytes --] Hi Nico, > Date: 2026-10-01 12:40:00-0500 > From: Nico Williams <nico@cryptonector.com> > > On Thu, Oct 01, 2026 at 06:50:08PM +0200, Alejandro Colomar wrote: > > > 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. > > Oh, because of `set -euo pipefail`, hah, yes. :-) > > > https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297 > > > > Hmmm, 93 LoC is certainly more interesting than the 4k+ python script. > > There is that, indeed. > > > I'll have a look. I'll also attempt at writing a bisect-rebase from > > scratch myself, to compare. > > I love that attitude! Heh! Thanks! I've already tried it, and it seems to work (I've only tried it once; I'll test it more before considering it stable). Here's the implementation: $ cat $(which git-bisect-rebase) #!/bin/bash set -Eeufo pipefail; shopt -s lastpipe; tgt="$(git rev-list -1 "$1")"; ## Try a regular rebase. if git rebase "$tgt" >/dev/null 2>/dev/null; test $? -eq 0; then echo 'Successfully rebased.'; exit 0; else echo '[conflict]'; git rebase --abort >/dev/null 2>/dev/null; fi; ## Bisect. while git merge-base HEAD "$tgt" \ | xargs -I{} git rev-list {}.."$tgt" \ | wc -l \ | read -r n; test $n -gt 1; do if git merge-base HEAD "$tgt" \ | xargs -I{} git rev-list {}.."$tgt" \ | sed "$(echo "($n + 2) / 2" | bc)!d" \ | read -r mid; echo "$n commits left to test in the target branch (trying $mid)"; git rebase $mid >/dev/null 2>/dev/null; test $? -eq 0; then echo '[ok]'; else echo '[conflict]'; tgt="$(git rev-list -1 "$mid")"; git rebase --abort >/dev/null 2>/dev/null; fi; done; ## Perform the conflicting rebase echo "The conflict is at $tgt; about to rebase now."; git rebase "$tgt"; And here's now it behaves: $ git bisect-rebase agetpass [conflict] 215 commits left to test in the target branch (trying 0482fd5f353c473268aff39e38513df2fb589a52) [conflict] 108 commits left to test in the target branch (trying b21a76f759492f88388840d69f85b8d27ad5dffe) [conflict] 54 commits left to test in the target branch (trying db3ca9f917efff9e2dab2fe36fa02fd6ef81ab08) [ok] 27 commits left to test in the target branch (trying 4df3f783c4d936e6985590981a2ddaf0377a3785) [ok] 13 commits left to test in the target branch (trying 93c675ef030e4eb226f60a317f3759755cd5bc5d) [ok] 6 commits left to test in the target branch (trying b4adbe6387ae8d95dbe0bd547a157492842bea12) [conflict] 3 commits left to test in the target branch (trying f7c712c3ade10c1d14916ea44408e42495fd1a8a) [conflict] 2 commits left to test in the target branch (trying 0bb39793716a2466aa1f477e4634e9d86532df80) [ok] The conflict is at f7c712c3ade10c1d14916ea44408e42495fd1a8a; about to rebase now. Auto-merging src/gpasswd.c Auto-merging src/newgrp.c CONFLICT (content): Merge conflict in src/newgrp.c Auto-merging src/passwd.c CONFLICT (content): Merge conflict in src/passwd.c error: could not apply e22c98497c16... lib/, src/: Use getpassa()/passzero() instead of agetpass()/erase_pass() hint: Resolve all conflicts manually, mark them as resolved with hint: "git add/rm <conflicted_files>", then run "git rebase --continue". hint: You can instead skip this commit: run "git rebase --skip". hint: To abort and get back to the state before "git rebase", run "git rebase --abort". hint: Disable this message with "git config set advice.mergeConflict false" Could not apply e22c98497c16... # lib/, src/: Use getpassa()/passzero() instead of agetpass()/erase_pass() It seems to work fine, and the source file uses 52 lines (including blank lines). The behavior seems intuitive, and not too verbose. Now, compared to your script, the source length is similar (most of the difference is printf calls). I use more pipes, while you use shell features like arrays (I have a very hard time reading shell code that does heavy use of shell features). Other than that, they look fundamentally similar (except for the paragraph below). :) One thing I'm surprised, though, is that you take two parameters instead of just the target branch. I very much prefer my script in this sense, which is like git-rebase(1), which rebases the active branch on top of the target commit. It's up to the caller to make sure that the active branch is the right one. > > I'll certainly try your script; thanks! > > > > Out of curiosity, did you offer this script to git(1)? > > No, though I think I've mentioned it here before. I'd be happy to > submit a patch, but I'd first have to get employer approval for it > (which is not a problem -- it will only take time). Please! :) Or I could send mine; I don't need to do any paperwork. Actually, due to the difference in parameters, I prefer to send mine. > > > If not, why not? > > No real reason other than bureaucracy on my side. Ok. > > > This is something that would clearly be helpful to people solving rebase > > conflicts in many projects. > > I agree! :) > > > Have a lovely night! > > Cheers! Cheers, Alex -- <https://www.alejandro-colomar.es> [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 833 bytes --] ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 20:29 ` git-rebase-walk Alejandro Colomar @ 2026-10-01 21:01 ` Nico Williams 2026-10-01 21:35 ` git-rebase-walk Nico Williams 0 siblings, 1 reply; 23+ messages in thread From: Nico Williams @ 2026-10-01 21:01 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git On Thu, Oct 01, 2026 at 10:29:41PM +0200, Alejandro Colomar wrote: > Here's the implementation: > > [...] > > It seems to work fine, and the source file uses 52 lines (including > blank lines). The behavior seems intuitive, and not too verbose. Yes, exactly. > Now, compared to your script, the source length is similar (most of the > difference is printf calls). I use more pipes, while you use shell > features like arrays (I have a very hard time reading shell code that > does heavy use of shell features). Other than that, they look > fundamentally similar (except for the paragraph below). :) Indeed. My script minus unnecessary vertical whitespace and printfs is very similar in size. > One thing I'm surprised, though, is that you take two parameters instead > of just the target branch. I very much prefer my script in this sense, > which is like git-rebase(1), which rebases the active branch on top of > the target commit. It's up to the caller to make sure that the active > branch is the right one. Oh, I know... I... was being paternalistic there. It's completely unnecessary, I agree. I'll remove it. > > > I'll certainly try your script; thanks! > > > > > > Out of curiosity, did you offer this script to git(1)? > > > > No, though I think I've mentioned it here before. I'd be happy to > > submit a patch, but I'd first have to get employer approval for it > > (which is not a problem -- it will only take time). > > Please! :) > > Or I could send mine; I don't need to do any paperwork. > Actually, due to the difference in parameters, I prefer to send mine. You're there already, so go for it. You can credit Vitor Dukhovni and me for this idea (he wrote slow-rebase.sh, and he and I rewrote it together into bisect-rebase.sh when I just didn't have the patience to babysit a slow rebase of my PG work), though.. it's fairly obvious, so much so that there's also the three alternatives mentioned by @pabs3 in a comment on my gist any or all of which you could credit as well, and probably more if you look hard enough: https://github.com/CTSRD-CHERI/git-mergify-rebase https://github.com/mhagger/git-imerge/ https://github.com/brooksdavis/mergify/ I agree with you: smaller and simpler is better, which is one reason I prefer bisect-rebase.sh over git-imerge. But I confess I've not looked a those three alternatives in much detail because, frankly, bisect-rebase.sh is so simple and easy to use, and since I [co-]wrote it, I know it well, so for me it's the best choice. Since it seems to be a best choice for someone other than me, it might actually be a good choice for others. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 21:01 ` git-rebase-walk Nico Williams @ 2026-10-01 21:35 ` Nico Williams 0 siblings, 0 replies; 23+ messages in thread From: Nico Williams @ 2026-10-01 21:35 UTC (permalink / raw) To: Alejandro Colomar; +Cc: git On Thu, Oct 01, 2026 at 04:01:01PM -0500, Nico Williams wrote: > though.. it's fairly obvious Concisely: repeatedly try to rebase to the new base, then fall back on bisection to find the upstream commit that causes conflicts. `bisect-rebase` is kind of a misnomer, because the best-case behavior is O(1), and worst-case is O(N log N) when _every_ upstream commit introduces conflicts, whereas one would expect O(log N). Still, it's a reasonable name given the intent. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-01 11:58 git-rebase-walk Alejandro Colomar 2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt 2026-10-01 16:10 ` git-rebase-walk Nico Williams @ 2026-10-02 2:49 ` Simon Richter 2026-10-02 3:19 ` git-rebase-walk Nico Williams 2 siblings, 1 reply; 23+ messages in thread From: Simon Richter @ 2026-10-02 2:49 UTC (permalink / raw) To: Alejandro Colomar, git Hi, On 10/1/26 8:58 PM, 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? I use something similar: [alias] slowrebase = "!bash -c 'for i in $(git rev-list --reverse $(git merge-base HEAD @{u})..@{u}); do git rebase $i || break; done'" slowrebasemerges = "!bash -c 'for i in $(git rev-list --merges --reverse $(git merge-base HEAD @{u})..@{u}); do git rebase $i || break; done'" Alas, this breaks down with merges, and it is slow, so I've been thinking about only listing those revisions that modify the same files as the branch being rebased, and their immediate predecessors -- the latter because the rebase should apply cleanly there. I wonder if it would make sense to have a rebase-bisect (bisect-rebase?) command that finds the first commit that the branch cannot be cleanly rebased onto, optionally with a test command to see if there are semantic conflicts. So given A --- B --- C --- D --- E --- F (main) \ a --- b --- c (feature) I'd like to be able to use "git bisect rebase main -x 'make check'" to attempt rebasing onto D first, and continue on to B or E, depending on whether the merge goes cleanly and "make check" succeeds, maybe with an option to try F first if the resolution is trivial. Simon ^ permalink raw reply [flat|nested] 23+ messages in thread
* Re: git-rebase-walk 2026-10-02 2:49 ` git-rebase-walk Simon Richter @ 2026-10-02 3:19 ` Nico Williams 0 siblings, 0 replies; 23+ messages in thread From: Nico Williams @ 2026-10-02 3:19 UTC (permalink / raw) To: Simon Richter; +Cc: Alejandro Colomar, git On Fri, Oct 02, 2026 at 11:49:26AM +0900, Simon Richter wrote: > On 10/1/26 8:58 PM, 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? > > I use something similar: > > [alias] > slowrebase = "!bash -c 'for i in $(git rev-list --reverse $(git > merge-base HEAD @{u})..@{u}); do git rebase $i || break; done'" > slowrebasemerges = "!bash -c 'for i in $(git rev-list --merges > --reverse $(git merge-base HEAD @{u})..@{u}); do git rebase $i || break; > done'" Nice! > Alas, this breaks down with merges, and it is slow, so I've been thinking > [...] A slow-rebase or bisect-rebase works best when a) you follow a rebase workflow, and b) the upstream has linear history (i.e., they also do a rebase workflow). When the upstream has merges then... improving this experience gets difficult, and the easiest thing to do is to treat the merge as a single [large] commit and not try to bisect-rebase on the merge author's branch side. But if you're looking for a slow-rebase or a bisect-rebase then chances are you're doing (a), and if the upstream doesn't have linear history then you accept the trouble. > I wonder if it would make sense to have a rebase-bisect (bisect-rebase?) We had a whole sub-thread on this thread about just that! :) > command that finds the first commit that the branch cannot be cleanly > rebased onto, optionally with a test command to see if there are semantic > conflicts. > > So given > > A --- B --- C --- D --- E --- F (main) > \ > a --- b --- c (feature) > > I'd like to be able to use "git bisect rebase main -x 'make check'" to > attempt rebasing onto D first, and continue on to B or E, depending on > whether the merge goes cleanly and "make check" succeeds, maybe with an > option to try F first if the resolution is trivial. I linked to my version of this, then Alejandro re-wrote it, on this thread. I've used mine a few times to rebase across thousands of upstream commits. It works very well, IMO. Nico -- ^ permalink raw reply [flat|nested] 23+ messages in thread
end of thread, other threads:[~2026-10-08 22:07 UTC | newest] Thread overview: 23+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-10-01 11:58 git-rebase-walk Alejandro Colomar 2026-10-01 13:22 ` git-rebase-walk Patrick Steinhardt 2026-10-01 15:51 ` git-rebase-walk Alejandro Colomar 2026-10-02 6:46 ` git-rebase-walk Patrick Steinhardt 2026-10-02 7:19 ` git-rebase-walk Alejandro Colomar 2026-10-03 19:37 ` git-rebase-walk Nico Williams 2026-10-04 10:03 ` git-rebase-walk Phillip Wood 2026-10-05 13:28 ` git-rebase-walk Alejandro Colomar 2026-10-05 13:37 ` git-rebase-walk Alejandro Colomar 2026-10-06 14:01 ` git-rebase-walk Phillip Wood 2026-10-06 14:58 ` git-rebase-walk Nico Williams 2026-10-06 16:45 ` git-rebase-walk Alejandro Colomar 2026-10-08 22:05 ` git-rebase-walk Alejandro Colomar 2026-10-08 22:07 ` git-rebase-walk Alejandro Colomar 2026-10-01 17:31 ` git-rebase-walk Junio C Hamano 2026-10-01 16:10 ` git-rebase-walk Nico Williams 2026-10-01 16:50 ` git-rebase-walk Alejandro Colomar 2026-10-01 17:40 ` git-rebase-walk Nico Williams 2026-10-01 20:29 ` git-rebase-walk Alejandro Colomar 2026-10-01 21:01 ` git-rebase-walk Nico Williams 2026-10-01 21:35 ` git-rebase-walk Nico Williams 2026-10-02 2:49 ` git-rebase-walk Simon Richter 2026-10-02 3:19 ` git-rebase-walk Nico Williams
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.