Volume XXII, number 280Wednesday, October 7, 2026Latest message 48 minutes ago

The Git List

News and archive of git@vger.kernel.org, since April 2005

patchrebase: ignore non-branch update-refs

14 messages between May 6, 2026 and May 15, 2026, from mail@abhinavg.net, Phillip Wood, Junio C Hamano, Abhinav Gupta.

Plain Markdown or JSON for tools and agents. Diffs are folded; open one to read it.

mail@abhinavg.netMay 6, 2026, 02:39 UTC on lore
From: Abhinav Gupta <mail@abhinavg.net>
The following Git configuration breaks git rebase --update-refs:
    [rebase]
        instructionFormat = %s%d

The '%d' format requests all available decorations for a commit, filling the global decoration table with all of them, which --update-refs then uses to populate 'update-ref' instructions in the rebase todo list.

Specifically, this results in the following instruction:
    update-ref HEAD
The todo parser then rejects the instruction:
    error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
    error: invalid line 3: update-ref HEAD

To fix, ignore decorations that are not local branches when scanning through the table.

This filtering matches the documented contract:
    Automatically force-update any branches that point to commits [..]
Signed-off-by: Abhinav Gupta <mail@abhinavg.net>
---
 sequencer.c                   | 10 ++++++++++
 t/t3404-rebase-interactive.sh | 22 ++++++++++++++++++++++
 2 files changed, 32 insertions(+)
Show changes to 2 files +32 −0

sequencer.c, t/t3404-rebase-interactive.sh

diff --git a/sequencer.c b/sequencer.c
index b7d8dca47f..25bcfc5da0 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -6428,6 +6428,16 @@ static int add_decorations_to_list(const struct commit *commit,
 		const char *path;
 		size_t base_offset = ctx->buf->len;
 
+		/*
+		 * The global decoration table may contain names loaded by
+		 * a previous pretty format such as "%d".
+		 * This will result in refs such as "HEAD" being present.
+		 */
+		if (decoration->type != DECORATION_REF_LOCAL) {
+			decoration = decoration->next;
+			continue;
+		}
+
 		/*
 		 * If the branch is the current HEAD, then it will be
 		 * updated by the default rebase behavior.
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 3e44562afa..d58236f0eb 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1960,6 +1960,28 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
 	)
 '
 
+test_expect_success '--update-refs ignores non-branch decorations' '
+	test_when_finished "git branch -D update-refs" &&
+	test_when_finished "git branch -D third" &&
+	test_when_finished "git checkout primary" &&
+	git checkout -B update-refs no-conflict-branch &&
+	git branch -f third HEAD~1 &&
+	(
+		set_cat_todo_editor &&
+
+		# rebase.instructionFormat=%d loads normal log decorations before
+		# --update-refs adds its branch placeholders.
+		# The placeholder scan must still ignore symbolic decorations,
+		# because "update-ref HEAD" is not a valid branch update.
+		test_must_fail git -c rebase.instructionFormat="%s%d" \
+			rebase -i --update-refs primary >todo &&
+
+		test_grep "^update-ref refs/heads/third$" todo &&
+		test_grep ! "^update-ref refs/heads/update-refs$" todo &&
+		test_grep ! "^update-ref HEAD$" todo
+	)
+'
+
 test_expect_success '--update-refs updates refs correctly' '
 	git checkout -B update-refs no-conflict-branch &&
 	git branch -f base HEAD~4 &&

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
2.54.0
Phillip WoodMay 7, 2026, 16:08 UTC in reply to mail@abhinavg.net on lore

Re: [PATCH] rebase: ignore non-branch update-refs

Hi Abhinav
On 06/05/2026 03:39, mail@abhinavg.net wrote:
Show 23 quoted lines
> From: Abhinav Gupta <mail@abhinavg.net>
> 
> The following Git configuration breaks git rebase --update-refs:
> 
>      [rebase]
>          instructionFormat = %s%d
> 
> The '%d' format requests all available decorations for a commit,
> filling the global decoration table with all of them,
> which --update-refs then uses to populate 'update-ref' instructions
> in the rebase todo list.
> 
> Specifically, this results in the following instruction:
> 
>      update-ref HEAD
> 
> The todo parser then rejects the instruction:
> 
>      error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
>      error: invalid line 3: update-ref HEAD
> 
> To fix, ignore decorations that are not local branches
> when scanning through the table.
Thanks for the clear explanation, the solution makes sense
Show 11 quoted lines
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 3e44562afa..d58236f0eb 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -1960,6 +1960,28 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
>   	)
>   '
>   
> +test_expect_success '--update-refs ignores non-branch decorations' '
> +	test_when_finished "git branch -D update-refs" &&
> +	test_when_finished "git branch -D third" &&

I'm not sure that we really need to create this branch in the first place. We already create update-refs from no-conflict-branch so we can check that no-conflict-branch appears and update-refs does not. In addition to checking that HEAD does not appear we should also check that we don't try to update any tags (HEAD matches tag M). I think the simplest way is to check the output of "grep ^update-ref todo" so we'd have

test_expect_success '--update-refs ignores non-branch decorations' '
	test_when_finished "git branch -D update-refs" &&
	test_when_finished "git checkout primary" &&
	git checkout -B update-refs no-conflict-branch &&
	(
		set_cat_todo_editor &&
		# rebase.instructionFormat=%d loads normal log decorations before
		# --update-refs adds its branch placeholders so we must ignore
		# all non-local decorations.
		test_must_fail git -c rebase.instructionFormat="%s%d" \
			rebase -i --update-refs HEAD^ >todo
	) &&
	grep ^update-ref todo >actual &&
	test_write_lines "update-ref refs/heads/no-conflict-branch" >expect &&
	test_cmp expect actual
'
Thanks for working on this
Phillip
Show 24 quoted lines
> +	test_when_finished "git checkout primary" &&
> +	git checkout -B update-refs no-conflict-branch &&
> +	git branch -f third HEAD~1 &&
> +	(
> +		set_cat_todo_editor &&
> +
> +		# rebase.instructionFormat=%d loads normal log decorations before
> +		# --update-refs adds its branch placeholders.
> +		# The placeholder scan must still ignore symbolic decorations,
> +		# because "update-ref HEAD" is not a valid branch update.
> +		test_must_fail git -c rebase.instructionFormat="%s%d" \
> +			rebase -i --update-refs primary >todo &&
> +
> +		test_grep "^update-ref refs/heads/third$" todo &&
> +		test_grep ! "^update-ref refs/heads/update-refs$" todo &&
> +		test_grep ! "^update-ref HEAD$" todo
> +	)
> +'
> +
>   test_expect_success '--update-refs updates refs correctly' '
>   	git checkout -B update-refs no-conflict-branch &&
>   	git branch -f base HEAD~4 &&
> 
> base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
mail@abhinavg.netMay 8, 2026, 01:58 UTC in reply to mail@abhinavg.net on lore

[PATCH v2] rebase: ignore non-branch update-refs

From: Abhinav Gupta <mail@abhinavg.net>
The following Git configuration breaks git rebase --update-refs:
    [rebase]
        instructionFormat = %s%d

The '%d' format requests all available decorations for a commit, filling the global decoration table with all of them, which --update-refs then uses to populate 'update-ref' instructions in the rebase todo list.

Specifically, this results in the following instruction:
    update-ref HEAD
The todo parser then rejects the instruction:
    error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
    error: invalid line 3: update-ref HEAD

To fix, ignore decorations that are not local branches when scanning through the table.

This matches the documented contract: it moves branch refs under refs/heads/ and leaves display-only decorations (HEAD, tags, etc.) alone.

Verification: A regression test that fails without this fix is included.

Signed-off-by: Abhinav Gupta <mail@abhinavg.net>
---
Updates:
    v2: incorporate suggestions to simplify the test
 sequencer.c                   | 10 ++++++++++
 t/t3404-rebase-interactive.sh | 18 ++++++++++++++++++
 2 files changed, 28 insertions(+)
Show changes to 2 files +28 −0

sequencer.c, t/t3404-rebase-interactive.sh

diff --git a/sequencer.c b/sequencer.c
index b7d8dca47f..25bcfc5da0 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -6428,6 +6428,16 @@ static int add_decorations_to_list(const struct commit *commit,
 		const char *path;
 		size_t base_offset = ctx->buf->len;
 
+		/*
+		 * The global decoration table may contain names loaded by
+		 * a previous pretty format such as "%d".
+		 * This will result in refs such as "HEAD" being present.
+		 */
+		if (decoration->type != DECORATION_REF_LOCAL) {
+			decoration = decoration->next;
+			continue;
+		}
+
 		/*
 		 * If the branch is the current HEAD, then it will be
 		 * updated by the default rebase behavior.
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 3e44562afa..58b3bb0c27 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1960,6 +1960,24 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
 	)
 '
 
+test_expect_success '--update-refs ignores non-branch decorations' '
+	test_when_finished "git branch -D update-refs" &&
+	test_when_finished "git checkout primary" &&
+	git checkout -B update-refs no-conflict-branch &&
+	(
+		set_cat_todo_editor &&
+
+		# rebase.instructionFormat=%d loads normal log decorations before
+		# --update-refs adds its branch placeholders so we must ignore
+		# all non-local decorations.
+		test_must_fail git -c rebase.instructionFormat="%s%d" \
+			rebase -i --update-refs HEAD^ >todo
+	) &&
+	grep ^update-ref todo >actual &&
+	test_write_lines "update-ref refs/heads/no-conflict-branch" >expect &&
+	test_cmp expect actual
+'
+
 test_expect_success '--update-refs updates refs correctly' '
 	git checkout -B update-refs no-conflict-branch &&
 	git branch -f base HEAD~4 &&

base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
2.54.0
Phillip WoodMay 8, 2026, 10:07 UTC in reply to mail@abhinavg.net on lore

Re: [PATCH v2] rebase: ignore non-branch update-refs

Hi Abhinav
Thanks for re-working the test - this looks great.
Phillip
On 08/05/2026 02:58, mail@abhinavg.net wrote:
Show 92 quoted lines
> From: Abhinav Gupta <mail@abhinavg.net>
> 
> The following Git configuration breaks git rebase --update-refs:
> 
>      [rebase]
>          instructionFormat = %s%d
> 
> The '%d' format requests all available decorations for a commit,
> filling the global decoration table with all of them,
> which --update-refs then uses to populate 'update-ref' instructions
> in the rebase todo list.
> 
> Specifically, this results in the following instruction:
> 
>      update-ref HEAD
> 
> The todo parser then rejects the instruction:
> 
>      error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
>      error: invalid line 3: update-ref HEAD
> 
> To fix, ignore decorations that are not local branches
> when scanning through the table.
> 
> This matches the documented contract:
> it moves branch refs under refs/heads/
> and leaves display-only decorations (HEAD, tags, etc.) alone.
> 
> Verification:
> A regression test that fails without this fix is included.
> 
> Signed-off-by: Abhinav Gupta <mail@abhinavg.net>
> ---
> Updates:
>      v2: incorporate suggestions to simplify the test
> 
>   sequencer.c                   | 10 ++++++++++
>   t/t3404-rebase-interactive.sh | 18 ++++++++++++++++++
>   2 files changed, 28 insertions(+)
> 
> diff --git a/sequencer.c b/sequencer.c
> index b7d8dca47f..25bcfc5da0 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -6428,6 +6428,16 @@ static int add_decorations_to_list(const struct commit *commit,
>   		const char *path;
>   		size_t base_offset = ctx->buf->len;
>   
> +		/*
> +		 * The global decoration table may contain names loaded by
> +		 * a previous pretty format such as "%d".
> +		 * This will result in refs such as "HEAD" being present.
> +		 */
> +		if (decoration->type != DECORATION_REF_LOCAL) {
> +			decoration = decoration->next;
> +			continue;
> +		}
> +
>   		/*
>   		 * If the branch is the current HEAD, then it will be
>   		 * updated by the default rebase behavior.
> diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
> index 3e44562afa..58b3bb0c27 100755
> --- a/t/t3404-rebase-interactive.sh
> +++ b/t/t3404-rebase-interactive.sh
> @@ -1960,6 +1960,24 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
>   	)
>   '
>   
> +test_expect_success '--update-refs ignores non-branch decorations' '
> +	test_when_finished "git branch -D update-refs" &&
> +	test_when_finished "git checkout primary" &&
> +	git checkout -B update-refs no-conflict-branch &&
> +	(
> +		set_cat_todo_editor &&
> +
> +		# rebase.instructionFormat=%d loads normal log decorations before
> +		# --update-refs adds its branch placeholders so we must ignore
> +		# all non-local decorations.
> +		test_must_fail git -c rebase.instructionFormat="%s%d" \
> +			rebase -i --update-refs HEAD^ >todo
> +	) &&
> +	grep ^update-ref todo >actual &&
> +	test_write_lines "update-ref refs/heads/no-conflict-branch" >expect &&
> +	test_cmp expect actual
> +'
> +
>   test_expect_success '--update-refs updates refs correctly' '
>   	git checkout -B update-refs no-conflict-branch &&
>   	git branch -f base HEAD~4 &&
> 
> base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
Junio C HamanoMay 10, 2026, 01:11 UTC in reply to mail@abhinavg.net on lore

Re: [PATCH] rebase: ignore non-branch update-refs

mail@abhinavg.net writes:
Show 13 quoted lines
> diff --git a/sequencer.c b/sequencer.c
> index b7d8dca47f..25bcfc5da0 100644
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -6428,6 +6428,16 @@ static int add_decorations_to_list(const struct commit *commit,
>  		const char *path;
>  		size_t base_offset = ctx->buf->len;
>  
> +		/*
> +		 * The global decoration table may contain names loaded by
> +		 * a previous pretty format such as "%d".
> +		 * This will result in refs such as "HEAD" being present.
> +		 */

Your long topic branch may have local unannotated tags that point into the middle of it, marking strategic points in the topic.

With this change, the command no longer moves them when it rebases the entire topic. Isn't it a regression?

> +		if (decoration->type != DECORATION_REF_LOCAL) {
> +			decoration = decoration->next;
> +			continue;
> +		}

In other words, what you want to prevent from appearing in the insn stream may be "HEAD", but if so, "must be DECORATION_REF_LOCAL" is too broad a net to catch it, and causing unintended collateral damage.

As to the style, as the body of the new conditional works identically with the existing code to exclude the current branch, I wonder why it shouldn't read more like this? The following illustration still uses "must be DECORATION_REF_LOCAL" and that may have to be corrected, of course.

 sequencer.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
Show changes to diff +5 −3
diff --git i/sequencer.c w/sequencer.c
index b7d8dca47f..1ba95fbae1 100644
--- i/sequencer.c
+++ w/sequencer.c
@@ -6429,10 +6429,12 @@ static int add_decorations_to_list(const struct commit *commit,
 		size_t base_offset = ctx->buf->len;
 
 		/*
-		 * If the branch is the current HEAD, then it will be
-		 * updated by the default rebase behavior.
+		 * Exclude the "current" branch, which will be updated
+		 * by the default rebase behavior.  Exclude non-branch
+		 * decorations as well.
 		 */
-		if (head_ref && !strcmp(head_ref, decoration->name)) {
+		if ((head_ref && !strcmp(head_ref, decoration->name)) ||
+		    (decoration->type != DECORATION_REF_LOCAL)) {
 			decoration = decoration->next;
 			continue;
 		}
Phillip WoodMay 10, 2026, 13:37 UTC in reply to Junio C Hamano on lore

Re: [PATCH] rebase: ignore non-branch update-refs

On 10/05/2026 02:11, Junio C Hamano wrote:
Show 21 quoted lines
> mail@abhinavg.net writes:
> 
>> diff --git a/sequencer.c b/sequencer.c
>> index b7d8dca47f..25bcfc5da0 100644
>> --- a/sequencer.c
>> +++ b/sequencer.c
>> @@ -6428,6 +6428,16 @@ static int add_decorations_to_list(const struct commit *commit,
>>   		const char *path;
>>   		size_t base_offset = ctx->buf->len;
>>   
>> +		/*
>> +		 * The global decoration table may contain names loaded by
>> +		 * a previous pretty format such as "%d".
>> +		 * This will result in refs such as "HEAD" being present.
>> +		 */
> 
> Your long topic branch may have local unannotated tags that point
> into the middle of it, marking strategic points in the topic.
> 
> With this change, the command no longer moves them when it rebases
> the entire topic.  Isn't it a regression?

sequencer.c:todo_list_add_update_ref_commands() calls load_branch_decorations() so it does not update tags and the patch is correct.

Looking at make_script_with_merges() it also calls load_branch_decorations() so we should probably add something like the diff below. Having said that this patch is a strict improvement so we can always fix make_script_with_merges() as a follow up.

Thanks
Phillip
---- 8< ----
Show changes to sequencer.c +9 −0
diff --git b/sequencer.c b/sequencer.c
--- a/sequencer.c
+++ b/sequencer.c
@@ -5982,6 +5982,15 @@ static int make_script_with_merges(struct 
pretty_print_context *pp,
  			const char *label = label_from_message.buf;
  			const struct name_decoration *decoration =
  				get_name_decoration(&to_merge->item->object);
+
+			/*
+			 * If rebase.instructionFormat includes "%d"
+			 * then we to skip non-local decorations as
+			 * we're only interested in branch names
+			 */
+			while (decoration &&
+			       decoration->type != DECORATION_REF_LOCAL)
+				decoration = decoration->next;

  			if (decoration)
  				skip_prefix(decoration->name, "refs/heads/",
mail@abhinavg.netMay 10, 2026, 22:41 UTC in reply to mail@abhinavg.net on lore

[PATCH v3 0/1] rebase: ignore non-branch update-refs

From: Abhinav Gupta <mail@abhinavg.net>
Updated per suggestion to merge the conditionals.
Phillip wrote:
Show 10 quoted lines
> On 10/05/2026 02:11, Junio C Hamano wrote:
> > Your long topic branch may have local unannotated tags that point
> > into the middle of it, marking strategic points in the topic.
> >
> > With this change, the command no longer moves them when it rebases
> > the entire topic.  Isn't it a regression?
>
> sequencer.c:todo_list_add_update_ref_commands() calls
> load_branch_decorations() so it does not update tags and the patch is
> correct.

That's right, the documented contract is that only branches are updated. Without '%d' triggering a load_ref_decorations, load_branch_decorations would be called and only branch refs would be added to the rebase todo list.

Phillip wrote:
> Looking at make_script_with_merges() it also calls
> load_branch_decorations() so we should probably add something like the
> diff below.

Thinking out loud: Instead of caller-side filtering, another option might be to replace load_branch_decorations with a branch-specialized iterator that relies on load_ref_decorations and silently skips non-branch decorations. That's a more invasive change, though.

Thanks!
Abhinav Gupta (1):
  rebase: ignore non-branch update-refs
 sequencer.c                   |  8 +++++++-
 t/t3404-rebase-interactive.sh | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)
base-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0
-- 
2.54.0
mail@abhinavg.netMay 10, 2026, 22:41 UTC in reply to mail@abhinavg.net on lore

[PATCH v3 1/1] rebase: ignore non-branch update-refs

From: Abhinav Gupta <mail@abhinavg.net>
The following Git configuration breaks git rebase --update-refs:
    [rebase]
        instructionFormat = %s%d

The '%d' format requests all available decorations for a commit, filling the global decoration table with all of them, which --update-refs then uses to populate 'update-ref' instructions in the rebase todo list.

Specifically, this results in the following instruction:
    update-ref HEAD
The todo parser then rejects the instruction:
    error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
    error: invalid line 3: update-ref HEAD

To fix, ignore decorations that are not local branches when scanning through the table.

This matches the documented contract: it moves branch refs under refs/heads/ and leaves display-only decorations (HEAD, tags, etc.) alone.

Verification: A regression test that fails without this fix is included.

Signed-off-by: Abhinav Gupta <mail@abhinavg.net>
---
Updates:
    v2: incorporate suggestions to simplify the test
    v3: merge two if statements into one
 sequencer.c                   |  8 +++++++-
 t/t3404-rebase-interactive.sh | 18 ++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)
Show changes to 2 files +25 −1

sequencer.c, t/t3404-rebase-interactive.sh

diff --git a/sequencer.c b/sequencer.c
index b7d8dca47f..ca3ea863d6 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -6431,8 +6431,14 @@ static int add_decorations_to_list(const struct commit *commit,
 		/*
 		 * If the branch is the current HEAD, then it will be
 		 * updated by the default rebase behavior.
+		 * Exclude it from the list of refs to update,
+		 * as well as any non-branch decorations.
+		 * Non-branch decorations may be present if the pretty format
+		 * includes "%d", which would have loaded all refs
+		 * into the global decoration table.
 		 */
-		if (head_ref && !strcmp(head_ref, decoration->name)) {
+		if ((head_ref && !strcmp(head_ref, decoration->name)) ||
+		    (decoration->type != DECORATION_REF_LOCAL)) {
 			decoration = decoration->next;
 			continue;
 		}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 3e44562afa..58b3bb0c27 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1960,6 +1960,24 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
 	)
 '
 
+test_expect_success '--update-refs ignores non-branch decorations' '
+	test_when_finished "git branch -D update-refs" &&
+	test_when_finished "git checkout primary" &&
+	git checkout -B update-refs no-conflict-branch &&
+	(
+		set_cat_todo_editor &&
+
+		# rebase.instructionFormat=%d loads normal log decorations before
+		# --update-refs adds its branch placeholders so we must ignore
+		# all non-local decorations.
+		test_must_fail git -c rebase.instructionFormat="%s%d" \
+			rebase -i --update-refs HEAD^ >todo
+	) &&
+	grep ^update-ref todo >actual &&
+	test_write_lines "update-ref refs/heads/no-conflict-branch" >expect &&
+	test_cmp expect actual
+'
+
 test_expect_success '--update-refs updates refs correctly' '
 	git checkout -B update-refs no-conflict-branch &&
 	git branch -f base HEAD~4 &&
-- 
2.54.0
Junio C HamanoMay 10, 2026, 23:37 UTC in reply to Phillip Wood on lore

Re: [PATCH] rebase: ignore non-branch update-refs

Phillip Wood <phillip.wood123@gmail.com> writes:
Show 9 quoted lines
>> Your long topic branch may have local unannotated tags that point
>> into the middle of it, marking strategic points in the topic.
>> 
>> With this change, the command no longer moves them when it rebases
>> the entire topic.  Isn't it a regression?
>
> sequencer.c:todo_list_add_update_ref_commands() calls 
> load_branch_decorations() so it does not update tags and the patch is 
> correct.

OK. And with "%d", the existing versions of Git would have produced something like

    pick 31e8fcabd8 # rebase: update-refs (HEAD -> rebase, tag: mark)
    update-ref HEAD
    update-ref refs/heads/rebase
    update-ref refs/tags/mark

it would have failed to work due to the "HEAD" thing, so even though existing versions of Git may have added such local tags to the insn sequence, it would not have been a workable configuration anyway.

OK. If we never supported such a workflow to use local tags as markers, then the strategy taken by the posted patch to limit us to local branch refs is a very good thing, I think.

Abhinav GuptaMay 11, 2026, 00:15 UTC in reply to Junio C Hamano on lore

Re: [PATCH] rebase: ignore non-branch update-refs

On Sun, May 10, 2026, at 16:37, Junio C Hamano wrote:
> it would have failed to work due to the "HEAD" thing, so even though
> existing versions of Git may have added such local tags to the insn
> sequence, it would not have been a workable configuration anyway.

Yeah. One additional data point: non-interactive rebase is also broken under this configuration. Given a branch off main~1, it runs into the same issue:

    $ git checkout -b foo main~1
    $ git commit --allow-empty -m 'do things'
    $ git rebase main
      # ...
    error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
    error: invalid line 2: update-ref HEAD
    You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
    Or you can abort the rebase with 'git rebase --abort'.
I'm guessing non-interactive rebase works off the same todo list so that makes sense.
Junio C HamanoMay 11, 2026, 00:20 UTC in reply to Abhinav Gupta on lore

Re: [PATCH] rebase: ignore non-branch update-refs

"Abhinav Gupta" <mail@abhinavg.net> writes:
Show 19 quoted lines
> On Sun, May 10, 2026, at 16:37, Junio C Hamano wrote:
>> it would have failed to work due to the "HEAD" thing, so even though
>> existing versions of Git may have added such local tags to the insn
>> sequence, it would not have been a workable configuration anyway.
>
> Yeah. One additional data point:
> non-interactive rebase is also broken under this configuration.
> Given a branch off main~1, it runs into the same issue:
>
>     $ git checkout -b foo main~1
>     $ git commit --allow-empty -m 'do things'
>     $ git rebase main
>       # ...
>     error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
>     error: invalid line 2: update-ref HEAD
>     You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>     Or you can abort the rebase with 'git rebase --abort'.
>
> I'm guessing non-interactive rebase works off the same todo list so that makes sense.

I smell that you'd be suggesting to replace the patch we have discussed with another one that declares that it is a bug to use %d in insn format? I do not think how well it would fly.

Abhinav GuptaMay 11, 2026, 00:33 UTC in reply to Junio C Hamano on lore

Re: [PATCH] rebase: ignore non-branch update-refs

On Sun, May 10, 2026, at 17:20, Junio C Hamano wrote:
> I smell that you'd be suggesting to replace the patch we have
> discussed with another one that declares that it is a bug to use %d
> in insn format?  I do not think how well it would fly.
No, I didn't meant to imply that. I'm happy with the patch as-is.

Using %d in insn format is desirable, and I would not try to remove that. I ran into this issue because of my own use of %d in insn format.

I was sharing an additional example for how this currently misbehaves: not only does it generate the 'update-ref HEAD' in interactive contexts, but it also breaks all non-interactive rebases with a non-empty todo list.

Phillip WoodMay 12, 2026, 15:10 UTC in reply to Abhinav Gupta on lore

Re: [PATCH] rebase: ignore non-branch update-refs

On 11/05/2026 01:15, Abhinav Gupta wrote:
Show 8 quoted lines
> 
> On Sun, May 10, 2026, at 16:37, Junio C Hamano wrote:
>> it would have failed to work due to the "HEAD" thing, so even though
>> existing versions of Git may have added such local tags to the insn
>> sequence, it would not have been a workable configuration anyway.
> 
> Yeah. One additional data point:
> non-interactive rebase is also broken under this configuration.

I assume you mean that rebase.instructionFormat includes "%d" and rebase.updateRefs is true below.

Show 12 quoted lines
> Given a branch off main~1, it runs into the same issue:
> 
>      $ git checkout -b foo main~1
>      $ git commit --allow-empty -m 'do things'
>      $ git rebase main
>        # ...
>      error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
>      error: invalid line 2: update-ref HEAD
>      You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
>      Or you can abort the rebase with 'git rebase --abort'.
> 
> I'm guessing non-interactive rebase works off the same todo list so that makes sense.
Yes, barring some special cases where we don't support updating refs
	"git rebase <options>"
is essentially
	GIT_SEQUENCE_EDITOR=: git rebase -i <options>
Thanks
Phillip
Phillip WoodMay 15, 2026, 15:40 UTC in reply to Phillip Wood on lore

Re: [PATCH] rebase: ignore non-branch update-refs

On 10/05/2026 14:37, Phillip Wood wrote:
Show 5 quoted lines
> 
> Looking at make_script_with_merges() it also calls 
> load_branch_decorations() so we should probably add something like the 
> diff below. Having said that this patch is a strict improvement so we 
> can always fix make_script_with_merges() as a follow up.

I've just had another look at this and even though we call load_branch_decorations() after calling setup_revisions_from_strvec() and prepare_revision_walk() we only load branch decorations. It turns out that "%d" calls load_ref_decorations() the first time it formats a commit and because we call load_branch_decorations() before the first call to get_revisions() we haven't formatted any commits yet. So we don't need to worry about rebase.instructionFormat changing the decorations that get loaded when generating the todo list with make_script_with_merges(). "rebase --update-refs" without "-r" only calls load_branch_decorations() after we've formatted a commit which is why it is affected.

Thanks
Phillip
Show 29 quoted lines
> 
> Thanks
> 
> Phillip
> 
> ---- 8< ----
> 
> diff --git b/sequencer.c b/sequencer.c
> --- a/sequencer.c
> +++ b/sequencer.c
> @@ -5982,6 +5982,15 @@ static int make_script_with_merges(struct 
> pretty_print_context *pp,
>               const char *label = label_from_message.buf;
>               const struct name_decoration *decoration =
>                   get_name_decoration(&to_merge->item->object);
> +
> +            /*
> +             * If rebase.instructionFormat includes "%d"
> +             * then we to skip non-local decorations as
> +             * we're only interested in branch names
> +             */
> +            while (decoration &&
> +                   decoration->type != DECORATION_REF_LOCAL)
> +                decoration = decoration->next;
> 
>               if (decoration)
>                   skip_prefix(decoration->name, "refs/heads/",
> 
> 

Back to recent threads