Re: [RFC] git-brebase
- From
- Alejandro Colomar <alx@kernel.org>
- Date
- Oct 3, 2026, 21:38 UTC
- Message-ID
- <asF0DkNtlnJ9-Sng@debian>
- In-Reply-To
- <asFv9QcpLgzPnnFb@ubby>
Hi Nico,
Show 16 quoted lines
> Date: 2026-10-03 16:13:25-0500 > From: Nico Williams <nico@cryptonector.com> > > On Sat, Oct 03, 2026 at 10:56:25PM +0200, Alejandro Colomar wrote: > > > I also have a getopts_long-like function (see my gists) for bash if you > > > like. > > > > I think getopts(1) is not usable for git(1)-related scripts, because > > getopts(1) interprets '--' as the end of the options, but git(1) uses it > > for distinguishing commits from paths. If anyone shows me how it can be > > used, I'd be interested, because I've hit this issue in the past with > > other script. > > https://gist.github.com/nicowilliams/f3fe2b10b380aecdef403acb246dced2 > > Though there's many ways to do this.
That one still consumes the '--', but we don't want to consume it. We want it to remain there in $@ after the options have been parsed.
Show 15 quoted lines
> > > > cat >"$callback" <<__EOF__ > > > > #!/bin/bash > > > > ... > > > > __EOF__ > > > > chmod +x "$callback"; > > > > > > Here what might be better is to have a command-line option to execute > > > this callback without having to write it to a file, > > > > How would you do it? > > I'd have an option or sub-command of the main script that says "do the > callback thing", then when you run `git bisect run ...` put in the name > of this script as the command and the "do the callback thing" option > next.
I'd need to see some code. I'm not seeing it. :)
Show 8 quoted lines
> > > and use environment > > > variables to pass arguments to it. > > > > The callback doesn't really need any arguments, since 'git bisect run' > > won't pass any arguments to it. > > But you're embedding values into the temp executable script -- if you > don't have that any more you'll have to pass those in.
But why would we want to not have it? That would complicate the script, no?
Show 38 quoted lines
> > > which means I can't use this in detached HEAD mode :( > > > > Oh! I wasn't aware that git-rebase(1) supported detached HEAD mode. > > Sure does! > > > > I work in detached HEAD mode almost exclusively. I know, that's.. > > > weird. But it works for me. > > > > Ouch! Indeed. :) > > Out of curiosity, are there any interesting reasons for such > > self-implied pain? > > I often do: > > : ; git checkout origin/master > : ; <do some work> > : ; git add ...; git commit -m '...' > : ; git push myfork HEAD:refs/heads/the-branch-name-here # <-- I name it here > > then open a PR. > > Now I don't have a branch here, but who cares? If I switch to other > work and later want to come back to this work I'll either a) create a > local branch then, and/or b) when I resume work on the first thing I'll > `git checkout myfork/the-branch-name-here` and... once more work in > detached HEAD mode. > > And if I need to see "what was I doing?" then I use `git log --oneline` > and `git reflog` and I quickly see the remote branch of interest. > > The remote branches are the symbolic names I need to preserve, and my > clone will know them, so I only need local branch names for things I > work on w/o a network or over a long time. > > I do exaggerate a bit. I do this a lot, but maybe not quite "almost > exclusively". Often I'm forced to have a local branch by opinionated > tools other than git itself.
Hmmm, actually resembles what I do. I use branches, then push to a remote, and once it's in the remote, I remove the local branch. I try to remove the local branches as soon as I can, because that way I don't need to remember whether there was something I forgot to push, or I wanted to explicitly discard it. If there's no local branch, there's no confusion. Since I work with two local computers, having the source of truth be the remote makes it less ambiguous. But while working locally, the branch helps a lot.
Anyway, I've patched it to work with detached HEAD. (I need to remember to add two traps, now.)
diff --git i/src/bin/git-brebase w/src/bin/git-brebase
index d652c37ef08d..a57acc350d7e 100755
--- i/src/bin/git-brebase
+++ w/src/bin/git-brebase
@@ -50,8 +50,16 @@ if test $# -gt 1; then
fi;
git rev-list -1 "$1" \
| read -r tgt;
-git rev-parse --abbrev-ref HEAD \
+
+mktemp \
| read -r branch;
+{
+ git rev-parse --abbrev-ref HEAD;
+ git rev-list -1 HEAD;
+} \
+| sed '/^HEAD$/d' \
+| sed '1!d' \
+>"$branch";
# Set up the callback script for 'git rebase run'.
mktemp \
@@ -91,7 +99,8 @@ cat >"$callback" <<__EOF__
fi;
fi;
- git switch '$branch' >/dev/null 2>/dev/null;
+ cat '$branch' \
+ | xargs -I{} git checkout {} >/dev/null 2>/dev/null;
git rev-list -1 HEAD \
| read -r old_head;
printf '%s' 'Rebase: ';
@@ -103,6 +112,13 @@ cat >"$callback" <<__EOF__
git checkout --detach "\$bisect_head" 2>/dev/null;
exit 1;
fi;
+ {
+ git rev-parse --abbrev-ref HEAD;
+ git rev-list -1 HEAD;
+ } \
+ | sed '/^HEAD$/d' \
+ | sed '1!d' \
+ >"$branch";
if test -n '$post'; then
printf '%s' 'Post-rebase exec: ';
@@ -146,7 +162,8 @@ fi;
# shellcheck disable=SC2248 # gbopts may hold multiple options
git bisect start $gbopts >/dev/null;
git bisect bad "$tgt" >/dev/null;
-git merge-base "$branch" "$tgt" \
+cat "$branch" \
+| xargs -I{} git merge-base {} "$tgt" \
| xargs -I{} git bisect good {};
git bisect run "$callback";
git rev-list -1 bisect/bad \
@@ -154,7 +171,8 @@ git rev-list -1 bisect/bad \
git bisect reset >/dev/null 2>/dev/null;
# Perform the conflicting rebase
-git switch "$branch";
+cat "$branch" \
+| xargs -I{} git checkout {};
# shellcheck disable=SC2086 # gropts may hold multiple options
git rebase $gropts "$bad";
if test -v post; thenI've tested it, and it works fine with a detached HEAD.
Cheers, Alex
> > Nico > --
-- <https://www.alejandro-colomar.es>