{"thread":{"id":"66435","subject":"git-rebase-walk","startedAt":"2026-10-01T11:58:50Z","lastAt":"2026-10-05T13:37:21Z","messageCount":18,"participants":["Alejandro Colomar","Patrick Steinhardt","Nico Williams","Junio C Hamano","Simon Richter","Phillip Wood"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"553832","messageId":"ar5KL4_IKXYbx3Sb@debian","threadId":"66435","inReplyTo":null,"subject":"git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-01T11:58:42Z","receivedAt":"2026-10-01T11:58:50Z","isPatch":false,"body":"Hi!\n\nI use this little command to apply iterative rebases, which are easier\nto handle when there are large conflicts.  Are you interested in it?\n\n\t$ cat $(which git-rebase-walk)\n\t#!/bin/bash\n\n\tset -Eeufo pipefail;\n\n\tgit merge-base HEAD \"$1\" \\\n\t| xargs -I{} git log --oneline {}..\"$1\" \\\n\t| cut -f1 -d' ' \\\n\t| tac \\\n\t| while read -r c; do\n\t\tgit rebase \"$c\";\n\tdone;\n\nThe source code is trivial, so I guess I don't need to explain much.\nIt behaves quite nicely, IME.\n\nYou may of course want to adapt it a little bit for merging in git(1).\nI could help improve it a little bit.\n\n\nHave a lovely day!\nAlex\n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"553836","messageId":"ar5eereSq91xldo-@pks.im","threadId":"66435","inReplyTo":"ar5KL4_IKXYbx3Sb@debian","subject":"Re: git-rebase-walk","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-10-01T13:22:02Z","receivedAt":"2026-10-01T13:22:08Z","isPatch":false,"body":"Hi,\n\nOn Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:\n> Hi!\n> \n> I use this little command to apply iterative rebases, which are easier\n> to handle when there are large conflicts.  Are you interested in it?\n> \n> \t$ cat $(which git-rebase-walk)\n> \t#!/bin/bash\n> \n> \tset -Eeufo pipefail;\n> \n> \tgit merge-base HEAD \"$1\" \\\n> \t| xargs -I{} git log --oneline {}..\"$1\" \\\n> \t| cut -f1 -d' ' \\\n> \t| tac \\\n> \t| while read -r c; do\n> \t\tgit rebase \"$c\";\n> \tdone;\n> \n> The source code is trivial, so I guess I don't need to explain much.\n> It behaves quite nicely, IME.\n> \n> You may of course want to adapt it a little bit for merging in git(1).\n> I could help improve it a little bit.\n\nthis reminds me a bit of git-imerge [1]. What this tool does is to\nbasically perform a merge between two branches incrementally using a\nmatrix. The tool tries to address exactly your use case, which is to\n\"present the user with one pairwise conflict at a time for resolution\".\n\nMaybe that tool is interesting to you. But it's certainly fallen a bit\nout of date, as it hasn't received any updates for more than 6 years by\nnow. Chances are it stll works alright though.\n\nThanks!\n\nPatrick\n\n[1]: https://github.com/mhagger/git-imerge\n"},{"id":"553842","messageId":"ar5-7ZtM6C23H-8m@debian","threadId":"66435","inReplyTo":"ar5eereSq91xldo-@pks.im","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-01T15:51:58Z","receivedAt":"2026-10-01T15:52:03Z","isPatch":false,"body":"Hi Patrick,\n\n> Date: 2026-10-01 15:22:02+0200\n> From: Patrick Steinhardt <ps@pks.im>\n>\n> Hi,\n> \n> On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:\n> > Hi!\n> > \n> > I use this little command to apply iterative rebases, which are easier\n> > to handle when there are large conflicts.  Are you interested in it?\n> > \n> > \t$ cat $(which git-rebase-walk)\n> > \t#!/bin/bash\n> > \n> > \tset -Eeufo pipefail;\n> > \n> > \tgit merge-base HEAD \"$1\" \\\n> > \t| xargs -I{} git log --oneline {}..\"$1\" \\\n> > \t| cut -f1 -d' ' \\\n> > \t| tac \\\n> > \t| while read -r c; do\n> > \t\tgit rebase \"$c\";\n> > \tdone;\n> > \n> > The source code is trivial, so I guess I don't need to explain much.\n> > It behaves quite nicely, IME.\n> > \n> > You may of course want to adapt it a little bit for merging in git(1).\n> > I could help improve it a little bit.\n> \n> this reminds me a bit of git-imerge [1]. What this tool does is to\n> basically perform a merge between two branches incrementally using a\n> matrix. The tool tries to address exactly your use case, which is to\n> \"present the user with one pairwise conflict at a time for resolution\".\n\nYup, from the description, it seems to do the same thing.  Thanks!\nI've also seen at least one other tool that does the same thing.\n\n> Maybe that tool is interesting to you.\n\nNot much, because I prefer a 9-line shell script that's robust as a rock\nvs. a 4k+ LoC python script for the same functionality.  :-)\n\n> But it's certainly fallen a bit\n> out of date, as it hasn't received any updates for more than 6 years by\n> now. Chances are it stll works alright though.\n\nMy script I use it in shadow-utils and in the Linux man-pages project,\nand is in use today.  I was wondering if there was interest in\nintegrating it to git(1).  If not, I will likely provide it in the\nman-pages repository as a help tool (which might end up packed by\ndistros as part of manpages-utils).  Is that okay to you?  (I ask mainly\nbecause it's using the git- namespace for commands, so you should at\nlease be aware of it.)\n\n\nHave a lovely day!\nAlex\n\n> \n> Thanks!\n> \n> Patrick\n> \n> [1]: https://github.com/mhagger/git-imerge\n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"553846","messageId":"ar6GExDLasWWFajm@ubby","threadId":"66435","inReplyTo":"ar5KL4_IKXYbx3Sb@debian","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-01T16:10:59Z","receivedAt":"2026-10-01T16:35:59Z","isPatch":false,"body":"On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:\n> I use this little command to apply iterative rebases, which are easier\n> to handle when there are large conflicts.  Are you interested in it?\n> \n> \t$ cat $(which git-rebase-walk)\n> \t#!/bin/bash\n> \n> \tset -Eeufo pipefail;\n> \n> \tgit merge-base HEAD \"$1\" \\\n> \t| xargs -I{} git log --oneline {}..\"$1\" \\\n> \t| cut -f1 -d' ' \\\n> \t| tac \\\n> \t| while read -r c; do\n> \t\tgit rebase \"$c\";\n> \tdone;\n\nYou could simplify this pipeline to:\n\n    git log --reverse --format=%H $(git merge-base HEAD \"$1\")..\"$1\" |\n    while read c; do git rebase \"$c\"; done\n\nBut:\n\n - you need to add conflict handling\n - this is very slow\n\nI've tried this before, so I know it's very slow if you're rebasing\nacross thousands of upstream commits!\n\nAlso, you need some extra handling of conflicts.\n\n> The source code is trivial, so I guess I don't need to explain much.\n> It behaves quite nicely, IME.\n\nIt can be much too slow.  I've a better solution: bisect-rebase.sh:\n\nhttps://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297\n\n(The first revision of that gist is slow-rebase.sh, which is a linear\nrebase like the one you posted.)\n\nThis script very efficiently finds the firts upstream commit that your\nbranch conflicts with, asks the user to resolve conflicts, then resumes\nrebasing.\n\nSo let's say that your upstream has 1,000 commits you need to rebase\nacross, and 10 of those introduce conflicts (assume there's no reverts\nof those for now), then this script will ask you to resolve conflicts 10\ntimes, and each time it's clear which pair of local and upstream commits\nconflict so you have the best possible context for conflict resolution.\n\nIt's like git-imerge, but better in that it's specifically geared to\nrebase workflows.\n\nI've successfully used this bisect-rebase.sh script to rebase a\npostgresql fork across between 1,000 and 2,000 commits twice, each time\nwith significant conflicts to resolve that were much too difficult to\nresolve with a plain rebase.  I.e., a plain `git rebase origin/master`\nproduced large conflicts where I didn't have enough context, but\nbisect-rebase.sh let me resolve much smaller conflicts with a new base\nthat immediately introduced those conflicts, so I always had the right\ncontext for resolving them.\n\nPG is a perfect test case for this sort of thing because it's so large\nand moves so fast.\n\nNico\n-- \n"},{"id":"553848","messageId":"ar6LUeH3AjxbiMgd@debian","threadId":"66435","inReplyTo":"ar6GExDLasWWFajm@ubby","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-01T16:50:08Z","receivedAt":"2026-10-01T16:50:12Z","isPatch":false,"body":"Hi Nico,\n\n> Date: 2026-10-01 11:10:59-0500\n> From: Nico Williams <nico@cryptonector.com>\n>\n> On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:\n> > I use this little command to apply iterative rebases, which are easier\n> > to handle when there are large conflicts.  Are you interested in it?\n> > \n> > \t$ cat $(which git-rebase-walk)\n> > \t#!/bin/bash\n> > \n> > \tset -Eeufo pipefail;\n> > \n> > \tgit merge-base HEAD \"$1\" \\\n> > \t| xargs -I{} git log --oneline {}..\"$1\" \\\n> > \t| cut -f1 -d' ' \\\n> > \t| tac \\\n> > \t| while read -r c; do\n> > \t\tgit rebase \"$c\";\n> > \tdone;\n> \n> You could simplify this pipeline to:\n> \n>     git log --reverse --format=%H $(git merge-base HEAD \"$1\")..\"$1\" |\n>     while read c; do git rebase \"$c\"; done\n\nActually, I've simplified it to:\n\n\t$ cat $(which git-rebase-walk)\n\t#!/bin/bash\n\n\tset -Eeufo pipefail;\n\n\tgit merge-base HEAD \"$1\" \\\n\t| xargs -I{} git rev-list {}..\"$1\" \\\n\t| tac \\\n\t| while read -r c; do\n\t\tgit rebase \"$c\";\n\tdone;\n\nsince git-rev-list(1) is the plumbing command (IIUC).\n\nI prefer the explicit tac(1) instead of --reverse.  It's simpler\nconceptually (we don't need to know/remember that there exists a\n--reverse flag to git-rev-parse(1) nor to understand its exact meaning).\ntac(1) is well known.  The performance doesn't change much, IME\n(sometimes better; sometimes worse).\n\nI also prefer to use a pipe with xargs(1), since it keeps each command\nshort and readable, without nested commands inside arguments to other\ncommands.\n\n> \n> But:\n> \n>  - you need to add conflict handling\n>  - this is very slow\n\nI have it running on the background while doing other stuff, and when\nit stops at a conflict, I look at it.\n\n> I've tried this before, so I know it's very slow if you're rebasing\n> across thousands of upstream commits!\n\nYes, it is.  When I did this manually before writing the tool, I did\nroughly a binary search of the conflicts.  That'd be faster, and if\nimplemented as part of git(1), it would make sense to implement it that\nway.  For my use case, I could live with a slow thing in the background,\nwhich is why I chose to keep it robust.\n\nI expect it wouldn't be that hard to do a binary search within a script.\n\n> Also, you need some extra handling of conflicts.\n\nNo, that's the nice part.  It works as is.  When I see a conflict, I get\nstopped at the rebase that caused the issue.  I solve that conflict, and\nthen can --continue that one rebase.  Or I can --abort that one rebase.\n\nOnce I've --continue'd, it ends at that one rebase, and doesn't continue\nthe walk.  I must run git-rebase-walk again for resuming the\nrebase-walk, which allows me to see the status before doing it.\n\n> > The source code is trivial, so I guess I don't need to explain much.\n> > It behaves quite nicely, IME.\n> \n> It can be much too slow.  I've a better solution: bisect-rebase.sh:\n> \n> https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297\n\nHmmm, 93 LoC is certainly more interesting than the 4k+ python script.\nI'll have a look.  I'll also attempt at writing a bisect-rebase from\nscratch myself, to compare.\n\n> (The first revision of that gist is slow-rebase.sh, which is a linear\n> rebase like the one you posted.)\n> \n> This script very efficiently finds the firts upstream commit that your\n> branch conflicts with, asks the user to resolve conflicts, then resumes\n> rebasing.\n\nIndeed, this is what I did manually before writing my slow script, so it\nseems you've had the same needs and line of thought that I had.  :)\n\n> So let's say that your upstream has 1,000 commits you need to rebase\n> across, and 10 of those introduce conflicts (assume there's no reverts\n> of those for now), then this script will ask you to resolve conflicts 10\n> times, and each time it's clear which pair of local and upstream commits\n> conflict so you have the best possible context for conflict resolution.\n> \n> It's like git-imerge, but better in that it's specifically geared to\n> rebase workflows.\n> \n> I've successfully used this bisect-rebase.sh script to rebase a\n> postgresql fork across between 1,000 and 2,000 commits twice, each time\n> with significant conflicts to resolve that were much too difficult to\n> resolve with a plain rebase.  I.e., a plain `git rebase origin/master`\n> produced large conflicts where I didn't have enough context, but\n> bisect-rebase.sh let me resolve much smaller conflicts with a new base\n> that immediately introduced those conflicts, so I always had the right\n> context for resolving them.\n> \n> PG is a perfect test case for this sort of thing because it's so large\n> and moves so fast.\n\nI'll certainly try your script; thanks!\n\nOut of curiosity, did you offer this script to git(1)?\nIf not, why not?\nIf yes, what happened?\n\nThis is something that would clearly be helpful to people solving rebase\nconflicts in many projects.\n\n\nHave a lovely night!\nAlex\n\n> \n> Nico\n> -- \n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"553852","messageId":"xmqqmrsx5nuz.fsf@gitster.g","threadId":"66435","inReplyTo":"ar5eereSq91xldo-@pks.im","subject":"Re: git-rebase-walk","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-10-01T17:31:32Z","receivedAt":"2026-10-01T17:31:34Z","isPatch":false,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Maybe that tool is interesting to you. But it's certainly fallen a bit\n> out of date, as it hasn't received any updates for more than 6 years by\n> now. Chances are it stll works alright though.\n>\n> [1]: https://github.com/mhagger/git-imerge\n\n;-)\n\nimerge is one of the best things since sliced bread, and what I\nstill occasinally fall back on when I encounter a really difficult\nmerges and rebases.\n"},{"id":"553864","messageId":"ar6a8OkGhmYVoM7E@ubby","threadId":"66435","inReplyTo":"ar6LUeH3AjxbiMgd@debian","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-01T17:40:00Z","receivedAt":"2026-10-01T18:59:59Z","isPatch":false,"body":"On Thu, Oct 01, 2026 at 06:50:08PM +0200, Alejandro Colomar wrote:\n> > Also, you need some extra handling of conflicts.\n> \n> No, that's the nice part.  It works as is.  When I see a conflict, I get\n> stopped at the rebase that caused the issue.  I solve that conflict, and\n> then can --continue that one rebase.  Or I can --abort that one rebase.\n\nOh, because of `set -euo pipefail`, hah, yes.\n\n> > https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297\n> \n> Hmmm, 93 LoC is certainly more interesting than the 4k+ python script.\n\nThere is that, indeed.\n\n> I'll have a look.  I'll also attempt at writing a bisect-rebase from\n> scratch myself, to compare.\n\nI love that attitude!\n\n> I'll certainly try your script; thanks!\n> \n> Out of curiosity, did you offer this script to git(1)?\n\nNo, though I think I've mentioned it here before.  I'd be happy to\nsubmit a patch, but I'd first have to get employer approval for it\n(which is not a problem -- it will only take time).\n\n> If not, why not?\n\nNo real reason other than bureaucracy on my side.\n\n> This is something that would clearly be helpful to people solving rebase\n> conflicts in many projects.\n\nI agree!\n\n> Have a lovely night!\n\nCheers!\n\nNico\n-- \n"},{"id":"553867","messageId":"ar69ZZ4r9ZxISIHz@debian","threadId":"66435","inReplyTo":"ar6a8OkGhmYVoM7E@ubby","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-01T20:29:41Z","receivedAt":"2026-10-01T20:29:48Z","isPatch":false,"body":"Hi Nico,\n\n> Date: 2026-10-01 12:40:00-0500\n> From: Nico Williams <nico@cryptonector.com>\n>\n> On Thu, Oct 01, 2026 at 06:50:08PM +0200, Alejandro Colomar wrote:\n> > > Also, you need some extra handling of conflicts.\n> > \n> > No, that's the nice part.  It works as is.  When I see a conflict, I get\n> > stopped at the rebase that caused the issue.  I solve that conflict, and\n> > then can --continue that one rebase.  Or I can --abort that one rebase.\n> \n> Oh, because of `set -euo pipefail`, hah, yes.\n\n:-)\n\n> > > https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee6509c3526297\n> > \n> > Hmmm, 93 LoC is certainly more interesting than the 4k+ python script.\n> \n> There is that, indeed.\n> \n> > I'll have a look.  I'll also attempt at writing a bisect-rebase from\n> > scratch myself, to compare.\n> \n> I love that attitude!\n\nHeh!  Thanks!\n\nI've already tried it, and it seems to work (I've only tried it once;\nI'll test it more before considering it stable).\n\nHere's the implementation:\n\n\t$ cat $(which git-bisect-rebase)\n\t#!/bin/bash\n\n\tset -Eeufo pipefail;\n\tshopt -s lastpipe;\n\n\ttgt=\"$(git rev-list -1 \"$1\")\";\n\n\t## Try a regular rebase.\n\tif\n\t\tgit rebase \"$tgt\" >/dev/null 2>/dev/null;\n\t\ttest $? -eq 0;\n\tthen\n\t\techo 'Successfully rebased.';\n\t\texit 0;\n\telse\n\t\techo '[conflict]';\n\t\tgit rebase --abort >/dev/null 2>/dev/null;\n\tfi;\n\n\t## Bisect.\n\twhile\n\t\tgit merge-base HEAD \"$tgt\" \\\n\t\t| xargs -I{} git rev-list {}..\"$tgt\" \\\n\t\t| wc -l \\\n\t\t| read -r n;\n\n\t\ttest $n -gt 1;\n\tdo\n\t\tif\n\t\t\tgit merge-base HEAD \"$tgt\" \\\n\t\t\t| xargs -I{} git rev-list {}..\"$tgt\" \\\n\t\t\t| sed \"$(echo \"($n + 2) / 2\" | bc)!d\" \\\n\t\t\t| read -r mid;\n\n\t\t\techo \"$n commits left to test in the target branch (trying $mid)\";\n\n\t\t\tgit rebase $mid >/dev/null 2>/dev/null;\n\n\t\t\ttest $? -eq 0;\n\t\tthen\n\t\t\techo '[ok]';\n\t\telse\n\t\t\techo '[conflict]';\n\n\t\t\ttgt=\"$(git rev-list -1 \"$mid\")\";\n\t\t\tgit rebase --abort >/dev/null 2>/dev/null;\n\t\tfi;\n\tdone;\n\n\t## Perform the conflicting rebase\n\techo \"The conflict is at $tgt; about to rebase now.\";\n\tgit rebase \"$tgt\";\n\nAnd here's now it behaves:\n\n\t$ git bisect-rebase agetpass\n\t[conflict]\n\t215 commits left to test in the target branch (trying 0482fd5f353c473268aff39e38513df2fb589a52)\n\t[conflict]\n\t108 commits left to test in the target branch (trying b21a76f759492f88388840d69f85b8d27ad5dffe)\n\t[conflict]\n\t54 commits left to test in the target branch (trying db3ca9f917efff9e2dab2fe36fa02fd6ef81ab08)\n\t[ok]\n\t27 commits left to test in the target branch (trying 4df3f783c4d936e6985590981a2ddaf0377a3785)\n\t[ok]\n\t13 commits left to test in the target branch (trying 93c675ef030e4eb226f60a317f3759755cd5bc5d)\n\t[ok]\n\t6 commits left to test in the target branch (trying b4adbe6387ae8d95dbe0bd547a157492842bea12)\n\t[conflict]\n\t3 commits left to test in the target branch (trying f7c712c3ade10c1d14916ea44408e42495fd1a8a)\n\t[conflict]\n\t2 commits left to test in the target branch (trying 0bb39793716a2466aa1f477e4634e9d86532df80)\n\t[ok]\n\tThe conflict is at f7c712c3ade10c1d14916ea44408e42495fd1a8a; about to rebase now.\n\tAuto-merging src/gpasswd.c\n\tAuto-merging src/newgrp.c\n\tCONFLICT (content): Merge conflict in src/newgrp.c\n\tAuto-merging src/passwd.c\n\tCONFLICT (content): Merge conflict in src/passwd.c\n\terror: could not apply e22c98497c16... lib/, src/: Use getpassa()/passzero() instead of agetpass()/erase_pass()\n\thint: Resolve all conflicts manually, mark them as resolved with\n\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\thint: You can instead skip this commit: run \"git rebase --skip\".\n\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\tCould not apply e22c98497c16... # lib/, src/: Use getpassa()/passzero() instead of agetpass()/erase_pass()\n\nIt seems to work fine, and the source file uses 52 lines (including\nblank lines).  The behavior seems intuitive, and not too verbose.\n\nNow, compared to your script, the source length is similar (most of the\ndifference is printf calls).  I use more pipes, while you use shell\nfeatures like arrays (I have a very hard time reading shell code that\ndoes heavy use of shell features).  Other than that, they look\nfundamentally similar (except for the paragraph below).  :)\n\nOne thing I'm surprised, though, is that you take two parameters instead\nof just the target branch.  I very much prefer my script in this sense,\nwhich is like git-rebase(1), which rebases the active branch on top of\nthe target commit.  It's up to the caller to make sure that the active\nbranch is the right one.\n\n> > I'll certainly try your script; thanks!\n> > \n> > Out of curiosity, did you offer this script to git(1)?\n> \n> No, though I think I've mentioned it here before.  I'd be happy to\n> submit a patch, but I'd first have to get employer approval for it\n> (which is not a problem -- it will only take time).\n\nPlease!  :)\n\nOr I could send mine; I don't need to do any paperwork.\nActually, due to the difference in parameters, I prefer to send mine.\n\n> \n> > If not, why not?\n> \n> No real reason other than bureaucracy on my side.\n\nOk.\n\n> \n> > This is something that would clearly be helpful to people solving rebase\n> > conflicts in many projects.\n> \n> I agree!\n\n:)\n\n> \n> > Have a lovely night!\n> \n> Cheers!\n\nCheers,\nAlex\n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"553871","messageId":"ar7SG6UKJTu1EmJr@ubby","threadId":"66435","inReplyTo":"ar7KDbV2ra7Rtzl6@ubby","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-01T21:35:23Z","receivedAt":"2026-10-01T22:02:04Z","isPatch":false,"body":"On Thu, Oct 01, 2026 at 04:01:01PM -0500, Nico Williams wrote:\n>                                       though.. it's fairly obvious\n\nConcisely: repeatedly try to rebase to the new base, then fall back\non bisection to find the upstream commit that causes conflicts.\n\n`bisect-rebase` is kind of a misnomer, because the best-case behavior is\nO(1), and worst-case is O(N log N) when _every_ upstream commit\nintroduces conflicts, whereas one would expect O(log N).  Still, it's a\nreasonable name given the intent.\n\nNico\n-- \n"},{"id":"553874","messageId":"ar7KDbV2ra7Rtzl6@ubby","threadId":"66435","inReplyTo":"ar69ZZ4r9ZxISIHz@debian","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-01T21:01:01Z","receivedAt":"2026-10-01T22:16:28Z","isPatch":false,"body":"On Thu, Oct 01, 2026 at 10:29:41PM +0200, Alejandro Colomar wrote:\n> Here's the implementation:\n> \n> [...]\n> \n> It seems to work fine, and the source file uses 52 lines (including\n> blank lines).  The behavior seems intuitive, and not too verbose.\n\nYes, exactly.\n\n> Now, compared to your script, the source length is similar (most of the\n> difference is printf calls).  I use more pipes, while you use shell\n> features like arrays (I have a very hard time reading shell code that\n> does heavy use of shell features).  Other than that, they look\n> fundamentally similar (except for the paragraph below).  :)\n\nIndeed.  My script minus unnecessary vertical whitespace and printfs is\nvery similar in size.\n\n> One thing I'm surprised, though, is that you take two parameters instead\n> of just the target branch.  I very much prefer my script in this sense,\n> which is like git-rebase(1), which rebases the active branch on top of\n> the target commit.  It's up to the caller to make sure that the active\n> branch is the right one.\n\nOh, I know... I... was being paternalistic there.  It's completely\nunnecessary, I agree.  I'll remove it.\n\n> > > I'll certainly try your script; thanks!\n> > > \n> > > Out of curiosity, did you offer this script to git(1)?\n> > \n> > No, though I think I've mentioned it here before.  I'd be happy to\n> > submit a patch, but I'd first have to get employer approval for it\n> > (which is not a problem -- it will only take time).\n> \n> Please!  :)\n> \n> Or I could send mine; I don't need to do any paperwork.\n> Actually, due to the difference in parameters, I prefer to send mine.\n\nYou're there already, so go for it.  You can credit Vitor Dukhovni and\nme for this idea (he wrote slow-rebase.sh, and he and I rewrote it\ntogether into bisect-rebase.sh when I just didn't have the patience to\nbabysit a slow rebase of my PG work), though.. it's fairly obvious, so\nmuch so that there's also the three alternatives mentioned by @pabs3 in\na comment on my gist any or all of which you could credit as well, and\nprobably more if you look hard enough:\n\n    https://github.com/CTSRD-CHERI/git-mergify-rebase\n    https://github.com/mhagger/git-imerge/\n    https://github.com/brooksdavis/mergify/\n\nI agree with you: smaller and simpler is better, which is one reason I\nprefer bisect-rebase.sh over git-imerge.  But I confess I've not looked\na those three alternatives in much detail because, frankly,\nbisect-rebase.sh is so simple and easy to use, and since I [co-]wrote\nit, I know it well, so for me it's the best choice.  Since it seems to\nbe a best choice for someone other than me, it might actually be a good\nchoice for others.\n\nNico\n-- \n"},{"id":"553884","messageId":"f5859438-f91d-46d2-b80c-25d63937ed7c@hogyros.de","threadId":"66435","inReplyTo":"ar5KL4_IKXYbx3Sb@debian","subject":"Re: git-rebase-walk","fromName":"Simon Richter","fromEmail":"simon.richter@hogyros.de","sentAt":"2026-10-02T02:49:26Z","receivedAt":"2026-10-02T02:49:53Z","isPatch":false,"body":"Hi,\n\nOn 10/1/26 8:58 PM, Alejandro Colomar wrote:\n\n> I use this little command to apply iterative rebases, which are easier\n> to handle when there are large conflicts.  Are you interested in it?\n\nI use something similar:\n\n[alias]\n         slowrebase = \"!bash -c 'for i in $(git rev-list --reverse $(git \nmerge-base HEAD @{u})..@{u}); do git rebase $i || break; done'\"\n         slowrebasemerges = \"!bash -c 'for i in $(git rev-list --merges \n--reverse $(git merge-base HEAD @{u})..@{u}); do git rebase $i || break; \ndone'\"\n\nAlas, this breaks down with merges, and it is slow, so I've been \nthinking about only listing those revisions that modify the same files \nas the branch being rebased, and their immediate predecessors -- the \nlatter because the rebase should apply cleanly there.\n\nI wonder if it would make sense to have a rebase-bisect (bisect-rebase?) \ncommand that finds the first commit that the branch cannot be cleanly \nrebased onto, optionally with a test command to see if there are \nsemantic conflicts.\n\nSo given\n\n     A --- B --- C --- D --- E --- F (main)\n       \\\n         a --- b --- c (feature)\n\nI'd like to be able to use \"git bisect rebase main -x 'make check'\" to \nattempt rebasing onto D first, and continue on to B or E, depending on \nwhether the merge goes cleanly and \"make check\" succeeds, maybe with an \noption to try F first if the resolution is trivial.\n\n    Simon\n"},{"id":"553885","messageId":"ar8i1Pz3Rh5F8ngx@ubby","threadId":"66435","inReplyTo":"f5859438-f91d-46d2-b80c-25d63937ed7c@hogyros.de","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-02T03:19:48Z","receivedAt":"2026-10-02T03:19:57Z","isPatch":false,"body":"On Fri, Oct 02, 2026 at 11:49:26AM +0900, Simon Richter wrote:\n> On 10/1/26 8:58 PM, Alejandro Colomar wrote:\n> > I use this little command to apply iterative rebases, which are easier\n> > to handle when there are large conflicts.  Are you interested in it?\n> \n> I use something similar:\n> \n> [alias]\n>         slowrebase = \"!bash -c 'for i in $(git rev-list --reverse $(git\n> merge-base HEAD @{u})..@{u}); do git rebase $i || break; done'\"\n>         slowrebasemerges = \"!bash -c 'for i in $(git rev-list --merges\n> --reverse $(git merge-base HEAD @{u})..@{u}); do git rebase $i || break;\n> done'\"\n\nNice!\n\n> Alas, this breaks down with merges, and it is slow, so I've been thinking\n> [...]\n\nA slow-rebase or bisect-rebase works best when a) you follow a rebase\nworkflow, and b) the upstream has linear history (i.e., they also do a\nrebase workflow).  When the upstream has merges then... improving this\nexperience gets difficult, and the easiest thing to do is to treat the\nmerge as a single [large] commit and not try to bisect-rebase on the\nmerge author's branch side.  But if you're looking for a slow-rebase or\na bisect-rebase then chances are you're doing (a), and if the upstream\ndoesn't have linear history then you accept the trouble.\n\n> I wonder if it would make sense to have a rebase-bisect (bisect-rebase?)\n\nWe had a whole sub-thread on this thread about just that! :)\n\n> command that finds the first commit that the branch cannot be cleanly\n> rebased onto, optionally with a test command to see if there are semantic\n> conflicts.\n> \n> So given\n> \n>     A --- B --- C --- D --- E --- F (main)\n>       \\\n>         a --- b --- c (feature)\n> \n> I'd like to be able to use \"git bisect rebase main -x 'make check'\" to\n> attempt rebasing onto D first, and continue on to B or E, depending on\n> whether the merge goes cleanly and \"make check\" succeeds, maybe with an\n> option to try F first if the resolution is trivial.\n\nI linked to my version of this, then Alejandro re-wrote it, on this\nthread.\n\nI've used mine a few times to rebase across thousands of upstream\ncommits.  It works very well, IMO.\n\nNico\n-- \n"},{"id":"553888","messageId":"ar9TTB5nmPPAdABE@pks.im","threadId":"66435","inReplyTo":"ar5-7ZtM6C23H-8m@debian","subject":"Re: git-rebase-walk","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-10-02T06:46:36Z","receivedAt":"2026-10-02T06:46:44Z","isPatch":false,"body":"On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote:\n> Hi Patrick,\n> \n> > Date: 2026-10-01 15:22:02+0200\n> > From: Patrick Steinhardt <ps@pks.im>\n> >\n> > Hi,\n> > \n> > On Thu, Oct 01, 2026 at 01:58:42PM +0200, Alejandro Colomar wrote:\n> > > Hi!\n> > > \n> > > I use this little command to apply iterative rebases, which are easier\n> > > to handle when there are large conflicts.  Are you interested in it?\n> > > \n> > > \t$ cat $(which git-rebase-walk)\n> > > \t#!/bin/bash\n> > > \n> > > \tset -Eeufo pipefail;\n> > > \n> > > \tgit merge-base HEAD \"$1\" \\\n> > > \t| xargs -I{} git log --oneline {}..\"$1\" \\\n> > > \t| cut -f1 -d' ' \\\n> > > \t| tac \\\n> > > \t| while read -r c; do\n> > > \t\tgit rebase \"$c\";\n> > > \tdone;\n> > > \n> > > The source code is trivial, so I guess I don't need to explain much.\n> > > It behaves quite nicely, IME.\n> > > \n> > > You may of course want to adapt it a little bit for merging in git(1).\n> > > I could help improve it a little bit.\n> > \n> > this reminds me a bit of git-imerge [1]. What this tool does is to\n> > basically perform a merge between two branches incrementally using a\n> > matrix. The tool tries to address exactly your use case, which is to\n> > \"present the user with one pairwise conflict at a time for resolution\".\n> \n> Yup, from the description, it seems to do the same thing.  Thanks!\n> I've also seen at least one other tool that does the same thing.\n> \n> > Maybe that tool is interesting to you.\n> \n> Not much, because I prefer a 9-line shell script that's robust as a rock\n> vs. a 4k+ LoC python script for the same functionality.  :-)\n> \n> > But it's certainly fallen a bit\n> > out of date, as it hasn't received any updates for more than 6 years by\n> > now. Chances are it stll works alright though.\n> \n> My script I use it in shadow-utils and in the Linux man-pages project,\n> and is in use today.  I was wondering if there was interest in\n> integrating it to git(1). \n\nI guess the answer is \"maybe\". The fact that multiple folks have solved\nsimilar issues over the course of many years is an indicator that the\nfuncitonality may be more generally useful. But it probably shouldn't be\na separate script, so if we wanted to integrate it I'd think the best\nway forward would be to integrate it into git-rebase(1) directly.\n\nThat's of course more involved though, so I understand in case you're\nnot interested in doing that.\n\n> If not, I will likely provide it in the man-pages repository as a help\n> tool (which might end up packed by distros as part of manpages-utils).\n> Is that okay to you?  (I ask mainly because it's using the git-\n> namespace for commands, so you should at lease be aware of it.)\n\nI mean overall this is our primary way of extension, by picking up\nutilities that have the \"git-\" prefix. So arguably you don't have to ask\nus for permission to do that.\n\nWhether it makes sense to distribute such a tool as part of\nmanpages-utils is a different question, and one where I myself am of a\nsplit mind. But that feels more like a question for distributors rather\nthan for us in the Git project.\n\nThanks!\n\nPatrick\n"},{"id":"553900","messageId":"ar9ZRrVyr1-Fk2LZ@debian","threadId":"66435","inReplyTo":"ar9TTB5nmPPAdABE@pks.im","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-02T07:19:56Z","receivedAt":"2026-10-02T07:20:00Z","isPatch":false,"body":"Hi Patrick,\n\n> Date: 2026-10-02 08:46:36+0200\n> From: Patrick Steinhardt <ps@pks.im>\n>\n[...]\n> > My script I use it in shadow-utils and in the Linux man-pages project,\n> > and is in use today.  I was wondering if there was interest in\n> > integrating it to git(1). \n> \n> I guess the answer is \"maybe\". The fact that multiple folks have solved\n> similar issues over the course of many years is an indicator that the\n> funcitonality may be more generally useful.\n\nNice.  :)\n\n> But it probably shouldn't be\n> a separate script, so if we wanted to integrate it I'd think the best\n> way forward would be to integrate it into git-rebase(1) directly.\n\nFor a git-rebase(1) option, I guess it would have to be named something\nlike --first-conflict.  --first conflict because it doesn't really\nrebase on the target commit, but rather on the first commit of that\nbranch which causes conflict.\n\n> That's of course more involved though, so I understand in case you're\n> not interested in doing that.\n\nI'd still be interested, but it may take me time, and I'll probably need\nhelp.\n\n> > If not, I will likely provide it in the man-pages repository as a help\n> > tool (which might end up packed by distros as part of manpages-utils).\n> > Is that okay to you?  (I ask mainly because it's using the git-\n> > namespace for commands, so you should at lease be aware of it.)\n> \n> I mean overall this is our primary way of extension, by picking up\n> utilities that have the \"git-\" prefix. So arguably you don't have to ask\n> us for permission to do that.\n\nI think I'll do this to provide the command in the meantime as an easy\nextension, with the goal of deprecating it eventually once it lands in\ngit-rebase(1).\n\n> Whether it makes sense to distribute such a tool as part of\n> manpages-utils is a different question, and one where I myself am of a\n> split mind. But that feels more like a question for distributors rather\n> than for us in the Git project.\n\nWe already have other tools that are generally useful, such as grepc(1),\nwhich finds C source code with a grep(1)-like interface.  It's\nessentially similar to things like ctags, but it has a traditional\ncommand-line interface, and doesn't use any index or cache (yet it's\nvery fast).\n\nSo, it wouldn't hurt having this one.\n\n\nHave a lovely day!\nAlex\n\n> \n> Thanks!\n> \n> Patrick\n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"554081","messageId":"asFZZGzXgGtQ4A6X@ubby","threadId":"66435","inReplyTo":"ar9ZRrVyr1-Fk2LZ@debian","subject":"Re: git-rebase-walk","fromName":"Nico Williams","fromEmail":"nico@cryptonector.com","sentAt":"2026-10-03T19:37:08Z","receivedAt":"2026-10-03T20:56:44Z","isPatch":false,"body":"On Fri, Oct 02, 2026 at 09:19:56AM +0200, Alejandro Colomar wrote:\n> For a git-rebase(1) option, I guess it would have to be named something\n> like --first-conflict.  --first conflict because it doesn't really\n> rebase on the target commit, but rather on the first commit of that\n> branch which causes conflict.\n\nI really like this.  Or `git rebase --onto-first-conflict`.\n\nNico\n-- \n"},{"id":"554103","messageId":"95796d0d-5928-4108-bc27-b7ace4459d2a@gmail.com","threadId":"66435","inReplyTo":"ar9TTB5nmPPAdABE@pks.im","subject":"Re: git-rebase-walk","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2026-10-04T10:03:39Z","receivedAt":"2026-10-04T10:03:42Z","isPatch":false,"body":"On 02/10/2026 07:46, Patrick Steinhardt wrote:\n> On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote:\n>>\n>> My script I use it in shadow-utils and in the Linux man-pages project,\n>> and is in use today.  I was wondering if there was interest in\n>> integrating it to git(1).\n> \n> I guess the answer is \"maybe\". The fact that multiple folks have solved\n> similar issues over the course of many years is an indicator that the\n> funcitonality may be more generally useful. But it probably shouldn't be\n> a separate script, so if we wanted to integrate it I'd think the best\n> way forward would be to integrate it into git-rebase(1) directly.\n\nI agree that would be the best way forward. Adding an \"--incremental\", \nor \"--progressive\" option to rebase would be useful I think. For ease of \nuse, I have a strong preference for an implementation where \"rebase \n--continue\" handles rebasing onto progressively more recent bases, \nrather than the multi shot approach where the user has to run \"git \nrebase --incremental\" multiple times. Having a multi-shot approach makes \nit much less clear when we've successfully rebased onto the desired base.\n\nThanks\n\nPhillip\n\n\n> That's of course more involved though, so I understand in case you're\n> not interested in doing that.\n> \n>> If not, I will likely provide it in the man-pages repository as a help\n>> tool (which might end up packed by distros as part of manpages-utils).\n>> Is that okay to you?  (I ask mainly because it's using the git-\n>> namespace for commands, so you should at lease be aware of it.)\n> \n> I mean overall this is our primary way of extension, by picking up\n> utilities that have the \"git-\" prefix. So arguably you don't have to ask\n> us for permission to do that.\n> \n> Whether it makes sense to distribute such a tool as part of\n> manpages-utils is a different question, and one where I myself am of a\n> split mind. But that feels more like a question for distributors rather\n> than for us in the Git project.\n> \n> Thanks!\n> \n> Patrick\n\n"},{"id":"554176","messageId":"asOaLyiJUmINFFFH@debian","threadId":"66435","inReplyTo":"95796d0d-5928-4108-bc27-b7ace4459d2a@gmail.com","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-05T13:28:21Z","receivedAt":"2026-10-05T13:28:21Z","isPatch":false,"body":"Hi Phillip,\n\n> Date: 2026-10-04 11:03:39+0100\n> From: Phillip Wood <phillip.wood123@gmail.com>\n>\n> On 02/10/2026 07:46, Patrick Steinhardt wrote:\n> > On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote:\n> > > \n> > > My script I use it in shadow-utils and in the Linux man-pages project,\n> > > and is in use today.  I was wondering if there was interest in\n> > > integrating it to git(1).\n> > \n> > I guess the answer is \"maybe\". The fact that multiple folks have solved\n> > similar issues over the course of many years is an indicator that the\n> > funcitonality may be more generally useful. But it probably shouldn't be\n> > a separate script, so if we wanted to integrate it I'd think the best\n> > way forward would be to integrate it into git-rebase(1) directly.\n> \n> I agree that would be the best way forward. Adding an \"--incremental\", or\n> \"--progressive\" option to rebase would be useful I think. For ease of use, I\n> have a strong preference for an implementation where \"rebase --continue\"\n> handles rebasing onto progressively more recent bases, rather than the multi\n> shot approach where the user has to run \"git rebase --incremental\" multiple\n> times. Having a multi-shot approach makes it much less clear when we've\n> successfully rebased onto the desired base.\n\nFor rebasing a single branch, having --continue do what you suggest\nwouldn't be too problematic.\n\nHowever, for when rebasing a tree of branches, I really need a\nmulti-shot operation, since I want to advance branches in a very\nspecific order.\n\nBelow is a shell session performing such a rebase, which hopefully shows\nwhy I need this to be multi-shot.\n\nOn the simpler case of a single branch, I'd still prefer a multi-shot\napproach where --continue only advances one rebase operation, because at\nthe end of it I want to stop, and check git-range-diff(1) to make sure\nit all makes sense.\n\nI've indented the output of commands, so that they are easier to\ndistinguish.\n\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* G ada8aff4f08a (r/B, B) foo j\n\t\t* G d6163efdc2db bar i\n\t\t| * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n\t\t| * G f7309b21ebfa bar k\n\t\t|/  \n\t\t* G e949e24ba457 (HEAD -> A, r/A) bar h\n\t\t*   G 607b450498be bar g\n\t\t|\\  \n\t\t| * G b787bcd373d9 bar e\n\t\t* | G c496b325576f baz f\n\t\t|/  \n\t\t| * G dfd9156d099a (r/main, main) foo d\n\t\t| * G 4940c7d739be bar c\n\t\t| * G cebc8fde25bb foo b\n\t\t|/  \n\t\t* G 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n\t\tRebase: conflict\n\t\tBisecting: 0 revisions left to test after this (roughly 1 step)\n\t\t[4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n\t\t[cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: success\n\t\t4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit\n\t\tcommit 4940c7d739be44c0ca32c1d610b85fd5650e1528\n\t\tAuthor: Alejandro Colomar <alx@kernel.org>\n\t\tDate:   2026-10-05 14:42:32 +0200\n\n\t\t    bar c\n\n\t\t bar | 1 +\n\t\t 1 file changed, 1 insertion(+)\n\t\t create mode 100644 bar\n\t\tbisect found first 'bad' commit\n\t\tAuto-merging bar\n\t\tCONFLICT (add/add): Merge conflict in bar\n\t\terror: could not apply 899eeb5c4e32... bar e\n\t\thint: Resolve all conflicts manually, mark them as resolved with\n\t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\t\thint: You can instead skip this commit: run \"git rebase --skip\".\n\t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\t\tCould not apply 899eeb5c4e32... # bar e\n\talx@debian:~/tmp/brebase$ git rebase --abort \n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 655c38e3cee8 (HEAD -> A) bar h\n\t\t*   1ababced193d bar g\n\t\t|\\  \n\t\t| * 899eeb5c4e32 bar e\n\t\t* | 761c9dbcfa5b baz f\n\t\t|/  \n\t\t| * ada8aff4f08a (r/B, B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| * | c496b325576f baz f\n\t\t| |/  \n\t\t| | * dfd9156d099a (r/main, main) foo d\n\t\t| | * 4940c7d739be bar c\n\t\t| |/  \n\t\t|/|   \n\t\t* | cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git switch B \n\t\tSwitched to branch 'B'\n\t\tYour branch is up to date with 'r/B'.\n\talx@debian:~/tmp/brebase$ git brebase A\n\t\tRebase: conflict\n\t\tBisecting: 2 revisions left to test after this (roughly 1 step)\n\t\t[899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n\t\t[cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\tcebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit\n\t\tcommit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6\n\t\tAuthor: Alejandro Colomar <alx@kernel.org>\n\t\tDate:   2026-10-05 14:42:04 +0200\n\n\t\t    foo b\n\n\t\t foo | 2 +-\n\t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n\t\tbisect found first 'bad' commit\n\t\tAuto-merging foo\n\t\tCONFLICT (content): Merge conflict in foo\n\t\terror: could not apply ada8aff4f08a... foo j\n\t\thint: Resolve all conflicts manually, mark them as resolved with\n\t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\t\thint: You can instead skip this commit: run \"git rebase --skip\".\n\t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\t\tCould not apply ada8aff4f08a... # foo j\n\talx@debian:~/tmp/brebase$ echo j >foo\n\talx@debian:~/tmp/brebase$ git add foo \n\talx@debian:~/tmp/brebase$ git rebase --continue \n\t\t[detached HEAD 2e0b72e7440a] foo j\n\t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n\t\tSuccessfully rebased and updated refs/heads/B.\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 2e0b72e7440a (HEAD -> B) foo j\n\t\t* a1c6c1fb7ca2 bar i\n\t\t* d8fa6c4da463 bar h\n\t\t* bef9f1c4da4d bar e\n\t\t* 0bac26895b94 baz f\n\t\t| * 655c38e3cee8 (A) bar h\n\t\t| *   1ababced193d bar g\n\t\t| |\\  \n\t\t| | * 899eeb5c4e32 bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * 761c9dbcfa5b baz f\n\t\t|/  \n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| * | c496b325576f baz f\n\t\t| |/  \n\t\t| | * dfd9156d099a (r/main, main) foo d\n\t\t| | * 4940c7d739be bar c\n\t\t| |/  \n\t\t|/|   \n\t\t* | cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git brebase A\n\t\tRebase: success\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 5ff93a00f9f2 (HEAD -> B) foo j\n\t\t* 01522206a7bc bar i\n\t\t* 655c38e3cee8 (A) bar h\n\t\t*   1ababced193d bar g\n\t\t|\\  \n\t\t| * 899eeb5c4e32 bar e\n\t\t* | 761c9dbcfa5b baz f\n\t\t|/  \n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| * | c496b325576f baz f\n\t\t| |/  \n\t\t| | * dfd9156d099a (r/main, main) foo d\n\t\t| | * 4940c7d739be bar c\n\t\t| |/  \n\t\t|/|   \n\t\t* | cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git switch C\n\t\tSwitched to branch 'C'\n\talx@debian:~/tmp/brebase$ git brebase A\n\t\tRebase: success\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 06d462903420 (HEAD -> C) bar l\n\t\t* 20f0a887b83b bar k\n\t\t| * 5ff93a00f9f2 (B) foo j\n\t\t| * 01522206a7bc bar i\n\t\t|/  \n\t\t* 655c38e3cee8 (A) bar h\n\t\t*   1ababced193d bar g\n\t\t|\\  \n\t\t| * 899eeb5c4e32 bar e\n\t\t* | 761c9dbcfa5b baz f\n\t\t|/  \n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| * | c496b325576f baz f\n\t\t| |/  \n\t\t| | * dfd9156d099a (r/main, main) foo d\n\t\t| | * 4940c7d739be bar c\n\t\t| |/  \n\t\t|/|   \n\t\t* | cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git switch A\n\t\tSwitched to branch 'A'\n\talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n\t\tRebase: conflict\n\t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n\t\t[4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\t4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit\n\t\tcommit 4940c7d739be44c0ca32c1d610b85fd5650e1528\n\t\tAuthor: Alejandro Colomar <alx@kernel.org>\n\t\tDate:   2026-10-05 14:42:32 +0200\n\n\t\t    bar c\n\n\t\t bar | 1 +\n\t\t 1 file changed, 1 insertion(+)\n\t\t create mode 100644 bar\n\t\tbisect found first 'bad' commit\n\t\tAuto-merging bar\n\t\tCONFLICT (add/add): Merge conflict in bar\n\t\terror: could not apply 899eeb5c4e32... bar e\n\t\thint: Resolve all conflicts manually, mark them as resolved with\n\t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\t\thint: You can instead skip this commit: run \"git rebase --skip\".\n\t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\t\tCould not apply 899eeb5c4e32... # bar e\n\talx@debian:~/tmp/brebase$ echo e >bar\n\talx@debian:~/tmp/brebase$ git add bar \n\talx@debian:~/tmp/brebase$ git rebase --continue \n\t\t[detached HEAD 2a4fa7fe2f44] bar e\n\t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n\t\tSuccessfully rebased and updated refs/heads/A.\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 0954f3d9b9e1 (HEAD -> A) bar h\n\t\t*   4f09c21bf2ca bar g\n\t\t|\\  \n\t\t| * 2a4fa7fe2f44 bar e\n\t\t* | e42246e75159 baz f\n\t\t|/  \n\t\t| * 06d462903420 (C) bar l\n\t\t| * 20f0a887b83b bar k\n\t\t| | * 5ff93a00f9f2 (B) foo j\n\t\t| | * 01522206a7bc bar i\n\t\t| |/  \n\t\t| * 655c38e3cee8 bar h\n\t\t| *   1ababced193d bar g\n\t\t| |\\  \n\t\t| | * 899eeb5c4e32 bar e\n\t\t| * | 761c9dbcfa5b baz f\n\t\t| |/  \n\t\t| | * ada8aff4f08a (r/B) foo j\n\t\t| | * d6163efdc2db bar i\n\t\t| | | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | | * f7309b21ebfa bar k\n\t\t| | |/  \n\t\t| | * e949e24ba457 (r/A) bar h\n\t\t| | *   607b450498be bar g\n\t\t| | |\\  \n\t\t| | | * b787bcd373d9 bar e\n\t\t| | * | c496b325576f baz f\n\t\t| | |/  \n\t\t| | | * dfd9156d099a (r/main, main) foo d\n\t\t| |_|/  \n\t\t|/| |   \n\t\t* | | 4940c7d739be bar c\n\t\t|/ /  \n\t\t* / cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B\n\t\tSuccessfully rebased and updated refs/heads/B.\n\talx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C\n\t\tSuccessfully rebased and updated refs/heads/C.\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 4a4ba76f55a4 (HEAD -> C) bar l\n\t\t* 86350e1490f3 bar k\n\t\t| * 4b6b40b14255 (B) foo j\n\t\t| * ba5a233ee4bc bar i\n\t\t|/  \n\t\t* 0954f3d9b9e1 (A) bar h\n\t\t*   4f09c21bf2ca bar g\n\t\t|\\  \n\t\t| * 2a4fa7fe2f44 bar e\n\t\t* | e42246e75159 baz f\n\t\t|/  \n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| * | c496b325576f baz f\n\t\t| |/  \n\t\t| | * dfd9156d099a (r/main, main) foo d\n\t\t| |/  \n\t\t|/|   \n\t\t* | 4940c7d739be bar c\n\t\t* | cebc8fde25bb foo b\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git switch A\n\t\tSwitched to branch 'A'\n\talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n\t\tRebase: success\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 30e2d96b3da5 (HEAD -> A) bar h\n\t\t*   01702a5b5d6b bar g\n\t\t|\\  \n\t\t| * c961883d543a bar e\n\t\t* | e17aadb725c4 baz f\n\t\t|/  \n\t\t* dfd9156d099a (r/main, main) foo d\n\t\t| * 4a4ba76f55a4 (C) bar l\n\t\t| * 86350e1490f3 bar k\n\t\t| | * 4b6b40b14255 (B) foo j\n\t\t| | * ba5a233ee4bc bar i\n\t\t| |/  \n\t\t| * 0954f3d9b9e1 bar h\n\t\t| *   4f09c21bf2ca bar g\n\t\t| |\\  \n\t\t| | * 2a4fa7fe2f44 bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * e42246e75159 baz f\n\t\t|/  \n\t\t* 4940c7d739be bar c\n\t\t* cebc8fde25bb foo b\n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * c496b325576f baz f\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C\n\t\tSuccessfully rebased and updated refs/heads/C.\n\talx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B\n\t\tAuto-merging foo\n\t\tCONFLICT (content): Merge conflict in foo\n\t\terror: could not apply 4b6b40b14255... foo j\n\t\thint: Resolve all conflicts manually, mark them as resolved with\n\t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\t\thint: You can instead skip this commit: run \"git rebase --skip\".\n\t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\t\tCould not apply 4b6b40b14255... # foo j\n\talx@debian:~/tmp/brebase$ git rebase --abort \n\talx@debian:~/tmp/brebase$ git switch B\n\t\tAlready on 'B'\n\t\tYour branch and 'r/B' have diverged,\n\t\tand have 8 and 6 different commits each, respectively.\n\t\t  (use \"git pull\" if you want to integrate the remote branch with yours)\n\talx@debian:~/tmp/brebase$ git brebase A\n\t\tRebase: conflict\n\t\tBisecting: 2 revisions left to test after this (roughly 1 step)\n\t\t[c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n\t\t[dfd9156d099ad3507a2850294c7a584b80712f04] foo d\n\t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n\t\tRebase: conflict\n\t\tdfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit\n\t\tcommit dfd9156d099ad3507a2850294c7a584b80712f04\n\t\tAuthor: Alejandro Colomar <alx@kernel.org>\n\t\tDate:   2026-10-05 14:42:50 +0200\n\n\t\t    foo d\n\n\t\t foo | 2 +-\n\t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n\t\tbisect found first 'bad' commit\n\t\tAuto-merging foo\n\t\tCONFLICT (content): Merge conflict in foo\n\t\terror: could not apply 4b6b40b14255... foo j\n\t\thint: Resolve all conflicts manually, mark them as resolved with\n\t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n\t\thint: You can instead skip this commit: run \"git rebase --skip\".\n\t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n\t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n\t\tCould not apply 4b6b40b14255... # foo j\n\talx@debian:~/tmp/brebase$ echo j >foo\n\talx@debian:~/tmp/brebase$ git add foo \n\talx@debian:~/tmp/brebase$ git rebase --continue \n\t\t[detached HEAD e7fdf07fd077] foo j\n\t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n\t\tSuccessfully rebased and updated refs/heads/B.\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* e7fdf07fd077 (HEAD -> B) foo j\n\t\t* dddf632a735f bar i\n\t\t* 7ac284de12ba bar h\n\t\t* e4541508ab3e bar e\n\t\t* cefec5878c67 baz f\n\t\t| * 6c7952d6fec5 (C) bar l\n\t\t| * bd43684f73c8 bar k\n\t\t| * 30e2d96b3da5 (A) bar h\n\t\t| *   01702a5b5d6b bar g\n\t\t| |\\  \n\t\t| | * c961883d543a bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * e17aadb725c4 baz f\n\t\t|/  \n\t\t* dfd9156d099a (r/main, main) foo d\n\t\t* 4940c7d739be bar c\n\t\t* cebc8fde25bb foo b\n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * c496b325576f baz f\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\talx@debian:~/tmp/brebase$ git brebase A\n\t\tRebase: success\n\talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n\t\t* 1201c4f20b19 (HEAD -> B) foo j\n\t\t* 44103f51a783 bar i\n\t\t| * 6c7952d6fec5 (C) bar l\n\t\t| * bd43684f73c8 bar k\n\t\t|/  \n\t\t* 30e2d96b3da5 (A) bar h\n\t\t*   01702a5b5d6b bar g\n\t\t|\\  \n\t\t| * c961883d543a bar e\n\t\t* | e17aadb725c4 baz f\n\t\t|/  \n\t\t* dfd9156d099a (r/main, main) foo d\n\t\t* 4940c7d739be bar c\n\t\t* cebc8fde25bb foo b\n\t\t| * ada8aff4f08a (r/B) foo j\n\t\t| * d6163efdc2db bar i\n\t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n\t\t| | * f7309b21ebfa bar k\n\t\t| |/  \n\t\t| * e949e24ba457 (r/A) bar h\n\t\t| *   607b450498be bar g\n\t\t| |\\  \n\t\t| | * b787bcd373d9 bar e\n\t\t| |/  \n\t\t|/|   \n\t\t| * c496b325576f baz f\n\t\t|/  \n\t\t* 1dcb901ebf60 foo a\n\nThis would be impossible with an approach that handles all the way until\nthe end.  I need to be able to stop a bisect-rebase operation on one\nbranch in the middle, then do a bisect-rebase on its descendants, then\ncome back to bisect-rebase the parent branch.  Does this make sense?\n\n\nHave a lovely day!\nAlex\n\n\n> \n> Thanks\n> \n> Phillip\n> \n> \n> > That's of course more involved though, so I understand in case you're\n> > not interested in doing that.\n> > \n> > > If not, I will likely provide it in the man-pages repository as a help\n> > > tool (which might end up packed by distros as part of manpages-utils).\n> > > Is that okay to you?  (I ask mainly because it's using the git-\n> > > namespace for commands, so you should at lease be aware of it.)\n> > \n> > I mean overall this is our primary way of extension, by picking up\n> > utilities that have the \"git-\" prefix. So arguably you don't have to ask\n> > us for permission to do that.\n> > \n> > Whether it makes sense to distribute such a tool as part of\n> > manpages-utils is a different question, and one where I myself am of a\n> > split mind. But that feels more like a question for distributors rather\n> > than for us in the Git project.\n> > \n> > Thanks!\n> > \n> > Patrick\n> \n\n-- \n<https://www.alejandro-colomar.es>\n"},{"id":"554177","messageId":"asOnp8ed6AGStH60@debian","threadId":"66435","inReplyTo":"asOaLyiJUmINFFFH@debian","subject":"Re: git-rebase-walk","fromName":"Alejandro Colomar","fromEmail":"alx@kernel.org","sentAt":"2026-10-05T13:37:21Z","receivedAt":"2026-10-05T13:37:21Z","isPatch":false,"body":"> Date: 2026-10-05 15:28:28+0200\n> From: Alejandro Colomar <alx@kernel.org>\n>\n> Hi Phillip,\n> \n> > Date: 2026-10-04 11:03:39+0100\n> > From: Phillip Wood <phillip.wood123@gmail.com>\n> >\n> > On 02/10/2026 07:46, Patrick Steinhardt wrote:\n> > > On Thu, Oct 01, 2026 at 05:51:58PM +0200, Alejandro Colomar wrote:\n> > > > \n> > > > My script I use it in shadow-utils and in the Linux man-pages project,\n> > > > and is in use today.  I was wondering if there was interest in\n> > > > integrating it to git(1).\n> > > \n> > > I guess the answer is \"maybe\". The fact that multiple folks have solved\n> > > similar issues over the course of many years is an indicator that the\n> > > funcitonality may be more generally useful. But it probably shouldn't be\n> > > a separate script, so if we wanted to integrate it I'd think the best\n> > > way forward would be to integrate it into git-rebase(1) directly.\n> > \n> > I agree that would be the best way forward. Adding an \"--incremental\", or\n> > \"--progressive\" option to rebase would be useful I think. For ease of use, I\n> > have a strong preference for an implementation where \"rebase --continue\"\n> > handles rebasing onto progressively more recent bases, rather than the multi\n> > shot approach where the user has to run \"git rebase --incremental\" multiple\n> > times. Having a multi-shot approach makes it much less clear when we've\n> > successfully rebased onto the desired base.\n> \n> For rebasing a single branch, having --continue do what you suggest\n> wouldn't be too problematic.\n> \n> However, for when rebasing a tree of branches, I really need a\n> multi-shot operation, since I want to advance branches in a very\n> specific order.\n> \n> Below is a shell session performing such a rebase, which hopefully shows\n> why I need this to be multi-shot.\n> \n> On the simpler case of a single branch, I'd still prefer a multi-shot\n> approach where --continue only advances one rebase operation, because at\n> the end of it I want to stop, and check git-range-diff(1) to make sure\n> it all makes sense.\n> \n> I've indented the output of commands, so that they are easier to\n> distinguish.\n> \n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* G ada8aff4f08a (r/B, B) foo j\n> \t\t* G d6163efdc2db bar i\n> \t\t| * G 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n> \t\t| * G f7309b21ebfa bar k\n> \t\t|/  \n> \t\t* G e949e24ba457 (HEAD -> A, r/A) bar h\n> \t\t*   G 607b450498be bar g\n> \t\t|\\  \n> \t\t| * G b787bcd373d9 bar e\n> \t\t* | G c496b325576f baz f\n> \t\t|/  \n> \t\t| * G dfd9156d099a (r/main, main) foo d\n> \t\t| * G 4940c7d739be bar c\n> \t\t| * G cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* G 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n> \t\tRebase: conflict\n> \t\tBisecting: 0 revisions left to test after this (roughly 1 step)\n> \t\t[4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n> \t\t[cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: success\n> \t\t4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit\n> \t\tcommit 4940c7d739be44c0ca32c1d610b85fd5650e1528\n> \t\tAuthor: Alejandro Colomar <alx@kernel.org>\n> \t\tDate:   2026-10-05 14:42:32 +0200\n> \n> \t\t    bar c\n> \n> \t\t bar | 1 +\n> \t\t 1 file changed, 1 insertion(+)\n> \t\t create mode 100644 bar\n> \t\tbisect found first 'bad' commit\n> \t\tAuto-merging bar\n> \t\tCONFLICT (add/add): Merge conflict in bar\n> \t\terror: could not apply 899eeb5c4e32... bar e\n> \t\thint: Resolve all conflicts manually, mark them as resolved with\n> \t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n> \t\thint: You can instead skip this commit: run \"git rebase --skip\".\n> \t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n> \t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n> \t\tCould not apply 899eeb5c4e32... # bar e\n> \talx@debian:~/tmp/brebase$ git rebase --abort \n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 655c38e3cee8 (HEAD -> A) bar h\n> \t\t*   1ababced193d bar g\n> \t\t|\\  \n> \t\t| * 899eeb5c4e32 bar e\n> \t\t* | 761c9dbcfa5b baz f\n> \t\t|/  \n> \t\t| * ada8aff4f08a (r/B, B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| * | c496b325576f baz f\n> \t\t| |/  \n> \t\t| | * dfd9156d099a (r/main, main) foo d\n> \t\t| | * 4940c7d739be bar c\n> \t\t| |/  \n> \t\t|/|   \n> \t\t* | cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git switch B \n> \t\tSwitched to branch 'B'\n> \t\tYour branch is up to date with 'r/B'.\n> \talx@debian:~/tmp/brebase$ git brebase A\n> \t\tRebase: conflict\n> \t\tBisecting: 2 revisions left to test after this (roughly 1 step)\n> \t\t[899eeb5c4e32397f0fe138c5b9f486d4682939cb] bar e\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n> \t\t[cebc8fde25bbe16c0f5f48e39642b3551f4f56e6] foo b\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\tcebc8fde25bbe16c0f5f48e39642b3551f4f56e6 is the first 'bad' commit\n> \t\tcommit cebc8fde25bbe16c0f5f48e39642b3551f4f56e6\n> \t\tAuthor: Alejandro Colomar <alx@kernel.org>\n> \t\tDate:   2026-10-05 14:42:04 +0200\n> \n> \t\t    foo b\n> \n> \t\t foo | 2 +-\n> \t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n> \t\tbisect found first 'bad' commit\n> \t\tAuto-merging foo\n> \t\tCONFLICT (content): Merge conflict in foo\n> \t\terror: could not apply ada8aff4f08a... foo j\n> \t\thint: Resolve all conflicts manually, mark them as resolved with\n> \t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n> \t\thint: You can instead skip this commit: run \"git rebase --skip\".\n> \t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n> \t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n> \t\tCould not apply ada8aff4f08a... # foo j\n> \talx@debian:~/tmp/brebase$ echo j >foo\n> \talx@debian:~/tmp/brebase$ git add foo \n> \talx@debian:~/tmp/brebase$ git rebase --continue \n> \t\t[detached HEAD 2e0b72e7440a] foo j\n> \t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n> \t\tSuccessfully rebased and updated refs/heads/B.\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 2e0b72e7440a (HEAD -> B) foo j\n> \t\t* a1c6c1fb7ca2 bar i\n> \t\t* d8fa6c4da463 bar h\n> \t\t* bef9f1c4da4d bar e\n> \t\t* 0bac26895b94 baz f\n> \t\t| * 655c38e3cee8 (A) bar h\n> \t\t| *   1ababced193d bar g\n> \t\t| |\\  \n> \t\t| | * 899eeb5c4e32 bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * 761c9dbcfa5b baz f\n> \t\t|/  \n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| * | c496b325576f baz f\n> \t\t| |/  \n> \t\t| | * dfd9156d099a (r/main, main) foo d\n> \t\t| | * 4940c7d739be bar c\n> \t\t| |/  \n> \t\t|/|   \n> \t\t* | cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git brebase A\n> \t\tRebase: success\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 5ff93a00f9f2 (HEAD -> B) foo j\n> \t\t* 01522206a7bc bar i\n> \t\t* 655c38e3cee8 (A) bar h\n> \t\t*   1ababced193d bar g\n> \t\t|\\  \n> \t\t| * 899eeb5c4e32 bar e\n> \t\t* | 761c9dbcfa5b baz f\n> \t\t|/  \n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C, C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| * | c496b325576f baz f\n> \t\t| |/  \n> \t\t| | * dfd9156d099a (r/main, main) foo d\n> \t\t| | * 4940c7d739be bar c\n> \t\t| |/  \n> \t\t|/|   \n> \t\t* | cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git switch C\n> \t\tSwitched to branch 'C'\n> \talx@debian:~/tmp/brebase$ git brebase A\n> \t\tRebase: success\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 06d462903420 (HEAD -> C) bar l\n> \t\t* 20f0a887b83b bar k\n> \t\t| * 5ff93a00f9f2 (B) foo j\n> \t\t| * 01522206a7bc bar i\n> \t\t|/  \n> \t\t* 655c38e3cee8 (A) bar h\n> \t\t*   1ababced193d bar g\n> \t\t|\\  \n> \t\t| * 899eeb5c4e32 bar e\n> \t\t* | 761c9dbcfa5b baz f\n> \t\t|/  \n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| * | c496b325576f baz f\n> \t\t| |/  \n> \t\t| | * dfd9156d099a (r/main, main) foo d\n> \t\t| | * 4940c7d739be bar c\n> \t\t| |/  \n> \t\t|/|   \n> \t\t* | cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git switch A\n> \t\tSwitched to branch 'A'\n> \talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n> \t\tRebase: conflict\n> \t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n> \t\t[4940c7d739be44c0ca32c1d610b85fd5650e1528] bar c\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\t4940c7d739be44c0ca32c1d610b85fd5650e1528 is the first 'bad' commit\n> \t\tcommit 4940c7d739be44c0ca32c1d610b85fd5650e1528\n> \t\tAuthor: Alejandro Colomar <alx@kernel.org>\n> \t\tDate:   2026-10-05 14:42:32 +0200\n> \n> \t\t    bar c\n> \n> \t\t bar | 1 +\n> \t\t 1 file changed, 1 insertion(+)\n> \t\t create mode 100644 bar\n> \t\tbisect found first 'bad' commit\n> \t\tAuto-merging bar\n> \t\tCONFLICT (add/add): Merge conflict in bar\n> \t\terror: could not apply 899eeb5c4e32... bar e\n> \t\thint: Resolve all conflicts manually, mark them as resolved with\n> \t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n> \t\thint: You can instead skip this commit: run \"git rebase --skip\".\n> \t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n> \t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n> \t\tCould not apply 899eeb5c4e32... # bar e\n> \talx@debian:~/tmp/brebase$ echo e >bar\n> \talx@debian:~/tmp/brebase$ git add bar \n> \talx@debian:~/tmp/brebase$ git rebase --continue \n> \t\t[detached HEAD 2a4fa7fe2f44] bar e\n> \t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n> \t\tSuccessfully rebased and updated refs/heads/A.\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 0954f3d9b9e1 (HEAD -> A) bar h\n> \t\t*   4f09c21bf2ca bar g\n> \t\t|\\  \n> \t\t| * 2a4fa7fe2f44 bar e\n> \t\t* | e42246e75159 baz f\n> \t\t|/  \n> \t\t| * 06d462903420 (C) bar l\n> \t\t| * 20f0a887b83b bar k\n> \t\t| | * 5ff93a00f9f2 (B) foo j\n> \t\t| | * 01522206a7bc bar i\n> \t\t| |/  \n> \t\t| * 655c38e3cee8 bar h\n> \t\t| *   1ababced193d bar g\n> \t\t| |\\  \n> \t\t| | * 899eeb5c4e32 bar e\n> \t\t| * | 761c9dbcfa5b baz f\n> \t\t| |/  \n> \t\t| | * ada8aff4f08a (r/B) foo j\n> \t\t| | * d6163efdc2db bar i\n> \t\t| | | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | | * f7309b21ebfa bar k\n> \t\t| | |/  \n> \t\t| | * e949e24ba457 (r/A) bar h\n> \t\t| | *   607b450498be bar g\n> \t\t| | |\\  \n> \t\t| | | * b787bcd373d9 bar e\n> \t\t| | * | c496b325576f baz f\n> \t\t| | |/  \n> \t\t| | | * dfd9156d099a (r/main, main) foo d\n> \t\t| |_|/  \n> \t\t|/| |   \n> \t\t* | | 4940c7d739be bar c\n> \t\t|/ /  \n> \t\t* / cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 B\n> \t\tSuccessfully rebased and updated refs/heads/B.\n> \talx@debian:~/tmp/brebase$ git rebase --onto A 655c38e3cee8 C\n> \t\tSuccessfully rebased and updated refs/heads/C.\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 4a4ba76f55a4 (HEAD -> C) bar l\n> \t\t* 86350e1490f3 bar k\n> \t\t| * 4b6b40b14255 (B) foo j\n> \t\t| * ba5a233ee4bc bar i\n> \t\t|/  \n> \t\t* 0954f3d9b9e1 (A) bar h\n> \t\t*   4f09c21bf2ca bar g\n> \t\t|\\  \n> \t\t| * 2a4fa7fe2f44 bar e\n> \t\t* | e42246e75159 baz f\n> \t\t|/  \n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| * | c496b325576f baz f\n> \t\t| |/  \n> \t\t| | * dfd9156d099a (r/main, main) foo d\n> \t\t| |/  \n> \t\t|/|   \n> \t\t* | 4940c7d739be bar c\n> \t\t* | cebc8fde25bb foo b\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git switch A\n> \t\tSwitched to branch 'A'\n> \talx@debian:~/tmp/brebase$ git brebase --rebase-merges main\n> \t\tRebase: success\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 30e2d96b3da5 (HEAD -> A) bar h\n> \t\t*   01702a5b5d6b bar g\n> \t\t|\\  \n> \t\t| * c961883d543a bar e\n> \t\t* | e17aadb725c4 baz f\n> \t\t|/  \n> \t\t* dfd9156d099a (r/main, main) foo d\n> \t\t| * 4a4ba76f55a4 (C) bar l\n> \t\t| * 86350e1490f3 bar k\n> \t\t| | * 4b6b40b14255 (B) foo j\n> \t\t| | * ba5a233ee4bc bar i\n> \t\t| |/  \n> \t\t| * 0954f3d9b9e1 bar h\n> \t\t| *   4f09c21bf2ca bar g\n> \t\t| |\\  \n> \t\t| | * 2a4fa7fe2f44 bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * e42246e75159 baz f\n> \t\t|/  \n> \t\t* 4940c7d739be bar c\n> \t\t* cebc8fde25bb foo b\n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * c496b325576f baz f\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 C\n> \t\tSuccessfully rebased and updated refs/heads/C.\n> \talx@debian:~/tmp/brebase$ git rebase --onto A 0954f3d9b9e1 B\n> \t\tAuto-merging foo\n> \t\tCONFLICT (content): Merge conflict in foo\n> \t\terror: could not apply 4b6b40b14255... foo j\n> \t\thint: Resolve all conflicts manually, mark them as resolved with\n> \t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n> \t\thint: You can instead skip this commit: run \"git rebase --skip\".\n> \t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n> \t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n> \t\tCould not apply 4b6b40b14255... # foo j\n> \talx@debian:~/tmp/brebase$ git rebase --abort \n\nOh, this was a mistake;  I should have resolved the conflict here\ninstead of using brebase below.  (brebase produced the same exact\nconflict).  :)\n\n\nCheers,\nAlex\n\n> \talx@debian:~/tmp/brebase$ git switch B\n> \t\tAlready on 'B'\n> \t\tYour branch and 'r/B' have diverged,\n> \t\tand have 8 and 6 different commits each, respectively.\n> \t\t  (use \"git pull\" if you want to integrate the remote branch with yours)\n> \talx@debian:~/tmp/brebase$ git brebase A\n> \t\tRebase: conflict\n> \t\tBisecting: 2 revisions left to test after this (roughly 1 step)\n> \t\t[c961883d543a2393aacfd6a8345e1d29e6857f7f] bar e\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\tBisecting: 0 revisions left to test after this (roughly 0 steps)\n> \t\t[dfd9156d099ad3507a2850294c7a584b80712f04] foo d\n> \t\trunning '.git/bisect-rebase/git-bisect-run-callback'\n> \t\tRebase: conflict\n> \t\tdfd9156d099ad3507a2850294c7a584b80712f04 is the first 'bad' commit\n> \t\tcommit dfd9156d099ad3507a2850294c7a584b80712f04\n> \t\tAuthor: Alejandro Colomar <alx@kernel.org>\n> \t\tDate:   2026-10-05 14:42:50 +0200\n> \n> \t\t    foo d\n> \n> \t\t foo | 2 +-\n> \t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n> \t\tbisect found first 'bad' commit\n> \t\tAuto-merging foo\n> \t\tCONFLICT (content): Merge conflict in foo\n> \t\terror: could not apply 4b6b40b14255... foo j\n> \t\thint: Resolve all conflicts manually, mark them as resolved with\n> \t\thint: \"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n> \t\thint: You can instead skip this commit: run \"git rebase --skip\".\n> \t\thint: To abort and get back to the state before \"git rebase\", run \"git rebase --abort\".\n> \t\thint: Disable this message with \"git config set advice.mergeConflict false\"\n> \t\tCould not apply 4b6b40b14255... # foo j\n> \talx@debian:~/tmp/brebase$ echo j >foo\n> \talx@debian:~/tmp/brebase$ git add foo \n> \talx@debian:~/tmp/brebase$ git rebase --continue \n> \t\t[detached HEAD e7fdf07fd077] foo j\n> \t\t 1 file changed, 1 insertion(+), 1 deletion(-)\n> \t\tSuccessfully rebased and updated refs/heads/B.\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* e7fdf07fd077 (HEAD -> B) foo j\n> \t\t* dddf632a735f bar i\n> \t\t* 7ac284de12ba bar h\n> \t\t* e4541508ab3e bar e\n> \t\t* cefec5878c67 baz f\n> \t\t| * 6c7952d6fec5 (C) bar l\n> \t\t| * bd43684f73c8 bar k\n> \t\t| * 30e2d96b3da5 (A) bar h\n> \t\t| *   01702a5b5d6b bar g\n> \t\t| |\\  \n> \t\t| | * c961883d543a bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * e17aadb725c4 baz f\n> \t\t|/  \n> \t\t* dfd9156d099a (r/main, main) foo d\n> \t\t* 4940c7d739be bar c\n> \t\t* cebc8fde25bb foo b\n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * c496b325576f baz f\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \talx@debian:~/tmp/brebase$ git brebase A\n> \t\tRebase: success\n> \talx@debian:~/tmp/brebase$ git log --all --graph --oneline\n> \t\t* 1201c4f20b19 (HEAD -> B) foo j\n> \t\t* 44103f51a783 bar i\n> \t\t| * 6c7952d6fec5 (C) bar l\n> \t\t| * bd43684f73c8 bar k\n> \t\t|/  \n> \t\t* 30e2d96b3da5 (A) bar h\n> \t\t*   01702a5b5d6b bar g\n> \t\t|\\  \n> \t\t| * c961883d543a bar e\n> \t\t* | e17aadb725c4 baz f\n> \t\t|/  \n> \t\t* dfd9156d099a (r/main, main) foo d\n> \t\t* 4940c7d739be bar c\n> \t\t* cebc8fde25bb foo b\n> \t\t| * ada8aff4f08a (r/B) foo j\n> \t\t| * d6163efdc2db bar i\n> \t\t| | * 450f3a7f4f25 (r/HEAD, r/C) bar l\n> \t\t| | * f7309b21ebfa bar k\n> \t\t| |/  \n> \t\t| * e949e24ba457 (r/A) bar h\n> \t\t| *   607b450498be bar g\n> \t\t| |\\  \n> \t\t| | * b787bcd373d9 bar e\n> \t\t| |/  \n> \t\t|/|   \n> \t\t| * c496b325576f baz f\n> \t\t|/  \n> \t\t* 1dcb901ebf60 foo a\n> \n> This would be impossible with an approach that handles all the way until\n> the end.  I need to be able to stop a bisect-rebase operation on one\n> branch in the middle, then do a bisect-rebase on its descendants, then\n> come back to bisect-rebase the parent branch.  Does this make sense?\n> \n> \n> Have a lovely day!\n> Alex\n> \n> \n> > \n> > Thanks\n> > \n> > Phillip\n> > \n> > \n> > > That's of course more involved though, so I understand in case you're\n> > > not interested in doing that.\n> > > \n> > > > If not, I will likely provide it in the man-pages repository as a help\n> > > > tool (which might end up packed by distros as part of manpages-utils).\n> > > > Is that okay to you?  (I ask mainly because it's using the git-\n> > > > namespace for commands, so you should at lease be aware of it.)\n> > > \n> > > I mean overall this is our primary way of extension, by picking up\n> > > utilities that have the \"git-\" prefix. So arguably you don't have to ask\n> > > us for permission to do that.\n> > > \n> > > Whether it makes sense to distribute such a tool as part of\n> > > manpages-utils is a different question, and one where I myself am of a\n> > > split mind. But that feels more like a question for distributors rather\n> > > than for us in the Git project.\n> > > \n> > > Thanks!\n> > > \n> > > Patrick\n> > \n> \n> -- \n> <https://www.alejandro-colomar.es>\n\n\n\n-- \n<https://www.alejandro-colomar.es>\n"}]}