reset: introduce ability to skip updating HEAD

In a subsequent commit we'll introduce a new caller to `reset_working_tree()` that really only wants to update the index and working tree, without updating any references. Introduce a new flag that makes the caller opt in to updating HEAD and adapt all callers to set that flag. Note that in a previous iteration we instead introduced a flag that made callers opt out of updating any references. This was somewhat awkward though because we already have the `UPDATE_ORIG_HEAD` flag, so the result was somewhat inconsistent. Suggested-by: Phillip Wood <phillip.wood123@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> [jc: fixed-up a typo pointed out by Christian] Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Jul 1, 2026 at 13:35 UTC b2ebb7803bafb581649de1b51eb3184ab7fe3463
4 files changed +26 -10
builtin/rebase.c
+10 -4
@@ -607,7 +607,8 @@ static int move_to_original_branch(struct rebase_options *opts)
607 strbuf_addf(&head_reflog, "%s (finish): returning to %s",
608 opts->reflog_action, opts->head_name);
609 ropts.branch = opts->head_name;
610 - ropts.flags = RESET_WORKING_TREE_REFS_ONLY;
610 + ropts.flags = RESET_WORKING_TREE_REFS_ONLY |
611 + RESET_WORKING_TREE_UPDATE_HEAD;
612 ropts.branch_msg = branch_reflog.buf;
613 ropts.head_msg = head_reflog.buf;
614 ret = reset_working_tree(the_repository, &ropts);
@@ -693,6 +694,7 @@ static int run_am(struct rebase_options *opts)
694 ropts.oid = &opts->orig_head->object.oid;
695 ropts.branch = opts->head_name;
696 ropts.default_reflog_action = opts->reflog_action;
697 + ropts.flags = RESET_WORKING_TREE_UPDATE_HEAD;
698 reset_working_tree(the_repository, &ropts);
699 error(_("\ngit encountered an error while preparing the "
700 "patches to replay\n"
@@ -862,7 +864,8 @@ static int checkout_up_to_date(struct rebase_options *options)
864 options->reflog_action, options->switch_to);
865 ropts.oid = &options->orig_head->object.oid;
866 ropts.branch = options->head_name;
865 - ropts.flags = RESET_WORKING_TREE_RUN_POST_CHECKOUT_HOOK;
867 + ropts.flags = RESET_WORKING_TREE_RUN_POST_CHECKOUT_HOOK |
868 + RESET_WORKING_TREE_UPDATE_HEAD;
869 if (!ropts.branch)
870 ropts.flags |= RESET_WORKING_TREE_DETACH;
871 ropts.head_msg = buf.buf;
@@ -1384,7 +1387,8 @@ int cmd_rebase(int argc,
1387
1388 rerere_clear(the_repository, &merge_rr);
1389 string_list_clear(&merge_rr, 1);
1387 - ropts.flags = RESET_WORKING_TREE_HARD;
1390 + ropts.flags = RESET_WORKING_TREE_HARD |
1391 + RESET_WORKING_TREE_UPDATE_HEAD;
1392 if (reset_working_tree(the_repository, &ropts) < 0)
1393 die(_("could not discard worktree changes"));
1394 remove_branch_state(the_repository, 0);
@@ -1409,7 +1413,8 @@ int cmd_rebase(int argc,
1413 ropts.oid = &options.orig_head->object.oid;
1414 ropts.head_msg = head_msg.buf;
1415 ropts.branch = options.head_name;
1412 - ropts.flags = RESET_WORKING_TREE_HARD;
1416 + ropts.flags = RESET_WORKING_TREE_HARD |
1417 + RESET_WORKING_TREE_UPDATE_HEAD;
1418 if (reset_working_tree(the_repository, &ropts) < 0)
1419 die(_("could not move back to %s"),
1420 oid_to_hex(&options.orig_head->object.oid));
@@ -1877,6 +1882,7 @@ int cmd_rebase(int argc,
1882 ropts.oid = &options.onto->object.oid;
1883 ropts.orig_head = &options.orig_head->object.oid;
1884 ropts.flags = RESET_WORKING_TREE_DETACH |
1885 + RESET_WORKING_TREE_UPDATE_HEAD |
1886 RESET_WORKING_TREE_UPDATE_ORIG_HEAD |
1887 RESET_WORKING_TREE_RUN_POST_CHECKOUT_HOOK;
1888 ropts.head_msg = msg.buf;
reset.c
+7 -2
@@ -92,6 +92,7 @@ int reset_working_tree(struct repository *r,
92 const char *switch_to_branch = opts->branch;
93 unsigned reset_hard = opts->flags & RESET_WORKING_TREE_HARD;
94 unsigned refs_only = opts->flags & RESET_WORKING_TREE_REFS_ONLY;
95 + unsigned update_head = opts->flags & RESET_WORKING_TREE_UPDATE_HEAD;
96 unsigned update_orig_head = opts->flags & RESET_WORKING_TREE_UPDATE_ORIG_HEAD;
97 unsigned dry_run = opts->flags & RESET_WORKING_TREE_DRY_RUN;
98 struct object_id *head = NULL, head_oid;
@@ -113,6 +114,9 @@ int reset_working_tree(struct repository *r,
114 if (opts->branch_msg && !opts->branch)
115 BUG("branch reflog message given without a branch");
116
117 + if (update_orig_head && !update_head)
118 + BUG("cannot update ORIG_HEAD without updating HEAD");
119 +
120 if (!refs_only && !dry_run && repo_hold_locked_index(r, &lock, LOCK_REPORT_ON_ERROR) < 0) {
121 ret = -1;
122 goto leave_reset_head;
@@ -129,7 +133,7 @@ int reset_working_tree(struct repository *r,
133 oid = &head_oid;
134
135 if (refs_only) {
132 - if (!dry_run)
136 + if (!dry_run && update_head)
137 return update_refs(r, opts, oid, head);
138 return 0;
139 }
@@ -197,7 +201,8 @@ int reset_working_tree(struct repository *r,
201 goto leave_reset_head;
202 }
203
200 - if (oid != &head_oid || update_orig_head || switch_to_branch)
204 + if (update_head &&
205 + (oid != &head_oid || update_orig_head || switch_to_branch))
206 ret = update_refs(r, opts, oid, head);
207
208 leave_reset_head:
reset.h
+6 -3
@@ -19,14 +19,17 @@ enum reset_working_tree_flags {
19 /* Only update refs, do not touch the worktree */
20 RESET_WORKING_TREE_REFS_ONLY = (1 << 3),
21
22 - /* Update ORIG_HEAD as well as HEAD */
23 - RESET_WORKING_TREE_UPDATE_ORIG_HEAD = (1 << 4),
22 + /* Update HEAD */
23 + RESET_WORKING_TREE_UPDATE_HEAD = (1 << 4),
24 +
25 + /* Update ORIG_HEAD */
26 + RESET_WORKING_TREE_UPDATE_ORIG_HEAD = (1 << 5),
27
28 /*
29 * Perform a dry-run by performing the operation without updating
30 * any user-visible state.
31 */
29 - RESET_WORKING_TREE_DRY_RUN = (1 << 5),
32 + RESET_WORKING_TREE_DRY_RUN = (1 << 6),
33 };
34
35 struct reset_working_tree_options {
sequencer.c
+3 -1
@@ -4678,7 +4678,8 @@ static void create_autostash_internal(struct repository *r,
4678 has_uncommitted_changes(r, 1)) {
4679 struct child_process stash = CHILD_PROCESS_INIT;
4680 struct reset_working_tree_options ropts = {
4681 - .flags = RESET_WORKING_TREE_HARD,
4681 + .flags = RESET_WORKING_TREE_HARD |
4682 + RESET_WORKING_TREE_UPDATE_HEAD,
4683 };
4684 struct object_id oid;
4685
@@ -4873,6 +4874,7 @@ static int checkout_onto(struct repository *r, struct replay_opts *opts,
4874 .oid = onto,
4875 .orig_head = orig_head,
4876 .flags = RESET_WORKING_TREE_DETACH |
4877 + RESET_WORKING_TREE_UPDATE_HEAD |
4878 RESET_WORKING_TREE_UPDATE_ORIG_HEAD |
4879 RESET_WORKING_TREE_RUN_POST_CHECKOUT_HOOK,
4880 .head_msg = reflog_message(opts, "start", "checkout %s",