All of lore.kernel.org
 help / color / mirror / Atom feed
From: Alejandro Colomar <alx@kernel.org>
To: Nico Williams <nico@cryptonector.com>
Cc: git@vger.kernel.org
Subject: Re: git-rebase-walk
Date: Thu, 1 Oct 2026 22:29:41 +0200	[thread overview]
Message-ID: <ar69ZZ4r9ZxISIHz@debian> (raw)
In-Reply-To: <ar6a8OkGhmYVoM7E@ubby>

[-- 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 --]

  reply	other threads:[~2026-10-01 20:29 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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       ` Alejandro Colomar [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ar69ZZ4r9ZxISIHz@debian \
    --to=alx@kernel.org \
    --cc=git@vger.kernel.org \
    --cc=nico@cryptonector.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.