* [PATCH] rebase: ignore non-branch update-refs
@ 2026-05-06 2:39 mail
2026-05-07 16:08 ` Phillip Wood
` (2 more replies)
0 siblings, 3 replies; 14+ messages in thread
From: mail @ 2026-05-06 2:39 UTC (permalink / raw)
To: git; +Cc: Abhinav Gupta, Derrick Stolee, Junio C Hamano
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(+)
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
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-06 2:39 [PATCH] rebase: ignore non-branch update-refs mail
@ 2026-05-07 16:08 ` Phillip Wood
2026-05-08 1:58 ` [PATCH v2] " mail
2026-05-10 1:11 ` [PATCH] " Junio C Hamano
2 siblings, 0 replies; 14+ messages in thread
From: Phillip Wood @ 2026-05-07 16:08 UTC (permalink / raw)
To: mail, git; +Cc: Derrick Stolee, Junio C Hamano
Hi Abhinav
On 06/05/2026 03:39, mail@abhinavg.net wrote:
> 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
> 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
> + 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v2] rebase: ignore non-branch update-refs
2026-05-06 2:39 [PATCH] rebase: ignore non-branch update-refs mail
2026-05-07 16:08 ` Phillip Wood
@ 2026-05-08 1:58 ` mail
2026-05-08 10:07 ` Phillip Wood
2026-05-10 22:41 ` [PATCH v3 0/1] " mail
2026-05-10 1:11 ` [PATCH] " Junio C Hamano
2 siblings, 2 replies; 14+ messages in thread
From: mail @ 2026-05-08 1:58 UTC (permalink / raw)
To: git, Phillip Wood; +Cc: Abhinav Gupta, Derrick Stolee, Junio C Hamano
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
--
2.54.0
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH v2] rebase: ignore non-branch update-refs
2026-05-08 1:58 ` [PATCH v2] " mail
@ 2026-05-08 10:07 ` Phillip Wood
2026-05-10 22:41 ` [PATCH v3 0/1] " mail
1 sibling, 0 replies; 14+ messages in thread
From: Phillip Wood @ 2026-05-08 10:07 UTC (permalink / raw)
To: mail, git, Phillip Wood; +Cc: Derrick Stolee, Junio C Hamano
Hi Abhinav
Thanks for re-working the test - this looks great.
Phillip
On 08/05/2026 02:58, mail@abhinavg.net wrote:
> 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-06 2:39 [PATCH] rebase: ignore non-branch update-refs mail
2026-05-07 16:08 ` Phillip Wood
2026-05-08 1:58 ` [PATCH v2] " mail
@ 2026-05-10 1:11 ` Junio C Hamano
2026-05-10 13:37 ` Phillip Wood
2 siblings, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2026-05-10 1:11 UTC (permalink / raw)
To: mail; +Cc: git, Derrick Stolee
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?
> + 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(-)
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;
}
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-10 1:11 ` [PATCH] " Junio C Hamano
@ 2026-05-10 13:37 ` Phillip Wood
2026-05-10 23:37 ` Junio C Hamano
2026-05-15 15:40 ` Phillip Wood
0 siblings, 2 replies; 14+ messages in thread
From: Phillip Wood @ 2026-05-10 13:37 UTC (permalink / raw)
To: Junio C Hamano, mail; +Cc: git, Derrick Stolee
On 10/05/2026 02:11, Junio C Hamano wrote:
> 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< ----
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/",
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 0/1] rebase: ignore non-branch update-refs
2026-05-08 1:58 ` [PATCH v2] " mail
2026-05-08 10:07 ` Phillip Wood
@ 2026-05-10 22:41 ` mail
2026-05-10 22:41 ` [PATCH v3 1/1] " mail
1 sibling, 1 reply; 14+ messages in thread
From: mail @ 2026-05-10 22:41 UTC (permalink / raw)
To: git, Phillip Wood, gitster; +Cc: Abhinav Gupta, Derrick Stolee
From: Abhinav Gupta <mail@abhinavg.net>
Updated per suggestion to merge the conditionals.
Phillip wrote:
> 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH v3 1/1] rebase: ignore non-branch update-refs
2026-05-10 22:41 ` [PATCH v3 0/1] " mail
@ 2026-05-10 22:41 ` mail
0 siblings, 0 replies; 14+ messages in thread
From: mail @ 2026-05-10 22:41 UTC (permalink / raw)
To: git, Phillip Wood, gitster; +Cc: Abhinav Gupta
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(-)
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
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-10 13:37 ` Phillip Wood
@ 2026-05-10 23:37 ` Junio C Hamano
2026-05-11 0:15 ` Abhinav Gupta
2026-05-15 15:40 ` Phillip Wood
1 sibling, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2026-05-10 23:37 UTC (permalink / raw)
To: Phillip Wood; +Cc: mail, git, Derrick Stolee
Phillip Wood <phillip.wood123@gmail.com> writes:
>> 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.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-10 23:37 ` Junio C Hamano
@ 2026-05-11 0:15 ` Abhinav Gupta
2026-05-11 0:20 ` Junio C Hamano
2026-05-12 15:10 ` Phillip Wood
0 siblings, 2 replies; 14+ messages in thread
From: Abhinav Gupta @ 2026-05-11 0:15 UTC (permalink / raw)
To: Junio C Hamano, Phillip Wood; +Cc: git, Derrick Stolee
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.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-11 0:15 ` Abhinav Gupta
@ 2026-05-11 0:20 ` Junio C Hamano
2026-05-11 0:33 ` Abhinav Gupta
2026-05-12 15:10 ` Phillip Wood
1 sibling, 1 reply; 14+ messages in thread
From: Junio C Hamano @ 2026-05-11 0:20 UTC (permalink / raw)
To: Abhinav Gupta; +Cc: Phillip Wood, git, Derrick Stolee
"Abhinav Gupta" <mail@abhinavg.net> writes:
> 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.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-11 0:20 ` Junio C Hamano
@ 2026-05-11 0:33 ` Abhinav Gupta
0 siblings, 0 replies; 14+ messages in thread
From: Abhinav Gupta @ 2026-05-11 0:33 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Phillip Wood, git, Derrick Stolee
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.
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-11 0:15 ` Abhinav Gupta
2026-05-11 0:20 ` Junio C Hamano
@ 2026-05-12 15:10 ` Phillip Wood
1 sibling, 0 replies; 14+ messages in thread
From: Phillip Wood @ 2026-05-12 15:10 UTC (permalink / raw)
To: Abhinav Gupta, Junio C Hamano; +Cc: git, Derrick Stolee
On 11/05/2026 01:15, Abhinav Gupta wrote:
>
> 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.
> 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
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH] rebase: ignore non-branch update-refs
2026-05-10 13:37 ` Phillip Wood
2026-05-10 23:37 ` Junio C Hamano
@ 2026-05-15 15:40 ` Phillip Wood
1 sibling, 0 replies; 14+ messages in thread
From: Phillip Wood @ 2026-05-15 15:40 UTC (permalink / raw)
To: Junio C Hamano, mail; +Cc: git, Derrick Stolee
On 10/05/2026 14:37, Phillip Wood wrote:
>
> 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
>
> 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/",
>
>
^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2026-05-15 15:40 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-06 2:39 [PATCH] rebase: ignore non-branch update-refs mail
2026-05-07 16:08 ` Phillip Wood
2026-05-08 1:58 ` [PATCH v2] " mail
2026-05-08 10:07 ` Phillip Wood
2026-05-10 22:41 ` [PATCH v3 0/1] " mail
2026-05-10 22:41 ` [PATCH v3 1/1] " mail
2026-05-10 1:11 ` [PATCH] " Junio C Hamano
2026-05-10 13:37 ` Phillip Wood
2026-05-10 23:37 ` Junio C Hamano
2026-05-11 0:15 ` Abhinav Gupta
2026-05-11 0:20 ` Junio C Hamano
2026-05-11 0:33 ` Abhinav Gupta
2026-05-12 15:10 ` Phillip Wood
2026-05-15 15:40 ` Phillip Wood
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox