* [PATCH 0/2] checkout -m: refine autostash fallback
@ 2026-07-25 15:34 Harald Nordgren via GitGitGadget
2026-07-25 15:34 ` [PATCH 1/2] sequencer: teach autostash apply to report conflicts Harald Nordgren via GitGitGadget
` (2 more replies)
0 siblings, 3 replies; 8+ messages in thread
From: Harald Nordgren via GitGitGadget @ 2026-07-25 15:34 UTC (permalink / raw)
To: git; +Cc: Harald Nordgren
Avoiding checkout -m autostash retries when no tracked local changes exist
and visually separating autostash conflict advice from the subsequent
branch-switch message.
Addresses #leftoverbits from here:
https://lore.kernel.org/git/cfd09dbf-8d77-4464-8030-3a0ffb4aeae7@gmail.com/
Harald Nordgren (2):
sequencer: teach autostash apply to report conflicts
checkout -m: refine autostash fallback
builtin/checkout.c | 18 ++++++++++++++----
builtin/commit.c | 2 +-
builtin/merge.c | 6 +++---
sequencer.c | 29 +++++++++++++++++++----------
sequencer.h | 3 ++-
t/t7201-co.sh | 17 ++++++++++++++++-
6 files changed, 55 insertions(+), 20 deletions(-)
base-commit: 9a0c4701dcd5725c4184599322b52933ff5005ca
Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2364%2FHaraldNordgren%2Fhn%2Fgit-checkout-m-leftoverbits-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2364/HaraldNordgren/hn/git-checkout-m-leftoverbits-v1
Pull-Request: https://github.com/git/git/pull/2364
--
gitgitgadget
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] sequencer: teach autostash apply to report conflicts 2026-07-25 15:34 [PATCH 0/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget @ 2026-07-25 15:34 ` Harald Nordgren via GitGitGadget 2026-08-27 13:01 ` Phillip Wood 2026-07-25 15:34 ` [PATCH 2/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-08-26 19:14 ` [PATCH 0/2] " Junio C Hamano 2 siblings, 1 reply; 8+ messages in thread From: Harald Nordgren via GitGitGadget @ 2026-07-25 15:34 UTC (permalink / raw) To: git; +Cc: Harald Nordgren, Harald Nordgren From: Harald Nordgren <haraldnordgren@gmail.com> Add a conflicted parameter to apply_save_autostash_oid() and apply_save_autostash_ref() so callers can learn whether applying the stash resulted in conflicts. Thread the parameter through apply_autostash_ref() and update existing callers to pass NULL. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> --- builtin/checkout.c | 3 ++- builtin/commit.c | 2 +- builtin/merge.c | 6 +++--- sequencer.c | 29 +++++++++++++++++++---------- sequencer.h | 3 ++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index aee84ca897..72aafa4049 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1242,7 +1242,8 @@ static int switch_branches(const struct checkout_opts *opts, new_branch_info->name, "local", stash_label_base, - autostash_msg.buf); + autostash_msg.buf, + NULL); } if (ret) { branch_info_release(&old_branch_info); diff --git a/builtin/commit.c b/builtin/commit.c index 28f6174503..d678a81865 100644 --- a/builtin/commit.c +++ b/builtin/commit.c @@ -1980,7 +1980,7 @@ int cmd_commit(int argc, } apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); cleanup: free_commit_extra_headers(extra); diff --git a/builtin/merge.c b/builtin/merge.c index 5b46a596f0..cecb8fb716 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -538,7 +538,7 @@ static void finish(struct commit *head_commit, if (new_head) apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); strbuf_release(&reflog_message); } @@ -1680,7 +1680,7 @@ int cmd_merge(int argc, &commit->object.oid, overwrite_ignore)) { apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); ret = 1; goto done; } @@ -1844,7 +1844,7 @@ int cmd_merge(int argc, fprintf(stderr, _("Merge with strategy %s failed.\n"), use_strategies[0]->name); apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); ret = 2; goto done; } else if (best_strategy == wt_strategy) diff --git a/sequencer.c b/sequencer.c index 1355a99a09..91a70e39a1 100644 --- a/sequencer.c +++ b/sequencer.c @@ -4748,7 +4748,8 @@ void create_autostash_ref(struct repository *r, const char *refname, static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply, const char *label_ours, const char *label_theirs, const char *label_base, - const char *stash_msg) + const char *stash_msg, + bool *conflicted) { struct child_process child = CHILD_PROCESS_INIT; int ret = 0; @@ -4783,14 +4784,16 @@ static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply, strvec_push(&store.args, stash_oid); if (run_command(&store)) ret = error(_("cannot store %s"), stash_oid); - else if (attempt_apply) + else if (attempt_apply) { + if (conflicted) + *conflicted = true; fprintf(stderr, _("Your local changes are stashed, however applying them\n" "resulted in conflicts. You can either resolve the conflicts\n" "and then discard the stash with \"git stash drop\", or, if you\n" "do not want to resolve them now, run \"git reset --hard\" and\n" "apply the local changes later by running \"git stash pop\".\n")); - else + } else fprintf(stderr, _("Autostash exists; creating a new stash entry.\n" "Your changes are safe in the stash.\n" @@ -4814,7 +4817,7 @@ static int apply_save_autostash(const char *path, int attempt_apply) strbuf_trim(&stash_oid); ret = apply_save_autostash_oid(stash_oid.buf, attempt_apply, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); unlink(path); strbuf_release(&stash_oid); @@ -4833,19 +4836,24 @@ int apply_autostash(const char *path) int apply_autostash_oid(const char *stash_oid) { - return apply_save_autostash_oid(stash_oid, 1, NULL, NULL, NULL, NULL); + return apply_save_autostash_oid(stash_oid, 1, NULL, NULL, NULL, NULL, + NULL); } static int apply_save_autostash_ref(struct repository *r, const char *refname, int attempt_apply, const char *label_ours, const char *label_theirs, const char *label_base, - const char *stash_msg) + const char *stash_msg, + bool *conflicted) { struct object_id stash_oid; char stash_oid_hex[GIT_MAX_HEXSZ + 1]; int flag, ret; + if (conflicted) + *conflicted = false; + if (!refs_ref_exists(get_main_ref_store(r), refname)) return 0; @@ -4858,7 +4866,7 @@ static int apply_save_autostash_ref(struct repository *r, const char *refname, oid_to_hex_r(stash_oid_hex, &stash_oid); ret = apply_save_autostash_oid(stash_oid_hex, attempt_apply, label_ours, label_theirs, label_base, - stash_msg); + stash_msg, conflicted); refs_delete_ref(get_main_ref_store(r), "", refname, &stash_oid, REF_NO_DEREF); @@ -4869,16 +4877,17 @@ static int apply_save_autostash_ref(struct repository *r, const char *refname, int save_autostash_ref(struct repository *r, const char *refname) { return apply_save_autostash_ref(r, refname, 0, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } int apply_autostash_ref(struct repository *r, const char *refname, const char *label_ours, const char *label_theirs, - const char *label_base, const char *stash_msg) + const char *label_base, const char *stash_msg, + bool *conflicted) { return apply_save_autostash_ref(r, refname, 1, label_ours, label_theirs, label_base, - stash_msg); + stash_msg, conflicted); } static int checkout_onto(struct repository *r, struct replay_opts *opts, diff --git a/sequencer.h b/sequencer.h index 64a9c7fb1b..b39528b6d0 100644 --- a/sequencer.h +++ b/sequencer.h @@ -237,7 +237,8 @@ int apply_autostash(const char *path); int apply_autostash_oid(const char *stash_oid); int apply_autostash_ref(struct repository *r, const char *refname, const char *label_ours, const char *label_theirs, - const char *label_base, const char *stash_msg); + const char *label_base, const char *stash_msg, + bool *conflicted); #define SUMMARY_INITIAL_COMMIT (1 << 0) #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1) -- gitgitgadget ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 1/2] sequencer: teach autostash apply to report conflicts 2026-07-25 15:34 ` [PATCH 1/2] sequencer: teach autostash apply to report conflicts Harald Nordgren via GitGitGadget @ 2026-08-27 13:01 ` Phillip Wood 0 siblings, 0 replies; 8+ messages in thread From: Phillip Wood @ 2026-08-27 13:01 UTC (permalink / raw) To: Harald Nordgren via GitGitGadget, git; +Cc: Harald Nordgren, Junio C Hamano Hi Harald On 25/07/2026 16:34, Harald Nordgren via GitGitGadget wrote: > From: Harald Nordgren <haraldnordgren@gmail.com> > > Add a conflicted parameter to apply_save_autostash_oid() and > apply_save_autostash_ref() so callers can learn whether applying the > stash resulted in conflicts. Thread the parameter through > apply_autostash_ref() and update existing callers to pass NULL. It would be nicer to use the return value to indicate success/error/conflicts rather than adding yet another parameter. Apart from that this looks good. Thanks Phillip > Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> > --- > builtin/checkout.c | 3 ++- > builtin/commit.c | 2 +- > builtin/merge.c | 6 +++--- > sequencer.c | 29 +++++++++++++++++++---------- > sequencer.h | 3 ++- > 5 files changed, 27 insertions(+), 16 deletions(-) > > diff --git a/builtin/checkout.c b/builtin/checkout.c > index aee84ca897..72aafa4049 100644 > --- a/builtin/checkout.c > +++ b/builtin/checkout.c > @@ -1242,7 +1242,8 @@ static int switch_branches(const struct checkout_opts *opts, > new_branch_info->name, > "local", > stash_label_base, > - autostash_msg.buf); > + autostash_msg.buf, > + NULL); > } > if (ret) { > branch_info_release(&old_branch_info); > diff --git a/builtin/commit.c b/builtin/commit.c > index 28f6174503..d678a81865 100644 > --- a/builtin/commit.c > +++ b/builtin/commit.c > @@ -1980,7 +1980,7 @@ int cmd_commit(int argc, > } > > apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > > cleanup: > free_commit_extra_headers(extra); > diff --git a/builtin/merge.c b/builtin/merge.c > index 5b46a596f0..cecb8fb716 100644 > --- a/builtin/merge.c > +++ b/builtin/merge.c > @@ -538,7 +538,7 @@ static void finish(struct commit *head_commit, > > if (new_head) > apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > strbuf_release(&reflog_message); > } > > @@ -1680,7 +1680,7 @@ int cmd_merge(int argc, > &commit->object.oid, > overwrite_ignore)) { > apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > ret = 1; > goto done; > } > @@ -1844,7 +1844,7 @@ int cmd_merge(int argc, > fprintf(stderr, _("Merge with strategy %s failed.\n"), > use_strategies[0]->name); > apply_autostash_ref(the_repository, "MERGE_AUTOSTASH", > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > ret = 2; > goto done; > } else if (best_strategy == wt_strategy) > diff --git a/sequencer.c b/sequencer.c > index 1355a99a09..91a70e39a1 100644 > --- a/sequencer.c > +++ b/sequencer.c > @@ -4748,7 +4748,8 @@ void create_autostash_ref(struct repository *r, const char *refname, > static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply, > const char *label_ours, const char *label_theirs, > const char *label_base, > - const char *stash_msg) > + const char *stash_msg, > + bool *conflicted) > { > struct child_process child = CHILD_PROCESS_INIT; > int ret = 0; > @@ -4783,14 +4784,16 @@ static int apply_save_autostash_oid(const char *stash_oid, int attempt_apply, > strvec_push(&store.args, stash_oid); > if (run_command(&store)) > ret = error(_("cannot store %s"), stash_oid); > - else if (attempt_apply) > + else if (attempt_apply) { > + if (conflicted) > + *conflicted = true; > fprintf(stderr, > _("Your local changes are stashed, however applying them\n" > "resulted in conflicts. You can either resolve the conflicts\n" > "and then discard the stash with \"git stash drop\", or, if you\n" > "do not want to resolve them now, run \"git reset --hard\" and\n" > "apply the local changes later by running \"git stash pop\".\n")); > - else > + } else > fprintf(stderr, > _("Autostash exists; creating a new stash entry.\n" > "Your changes are safe in the stash.\n" > @@ -4814,7 +4817,7 @@ static int apply_save_autostash(const char *path, int attempt_apply) > strbuf_trim(&stash_oid); > > ret = apply_save_autostash_oid(stash_oid.buf, attempt_apply, > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > > unlink(path); > strbuf_release(&stash_oid); > @@ -4833,19 +4836,24 @@ int apply_autostash(const char *path) > > int apply_autostash_oid(const char *stash_oid) > { > - return apply_save_autostash_oid(stash_oid, 1, NULL, NULL, NULL, NULL); > + return apply_save_autostash_oid(stash_oid, 1, NULL, NULL, NULL, NULL, > + NULL); > } > > static int apply_save_autostash_ref(struct repository *r, const char *refname, > int attempt_apply, > const char *label_ours, const char *label_theirs, > const char *label_base, > - const char *stash_msg) > + const char *stash_msg, > + bool *conflicted) > { > struct object_id stash_oid; > char stash_oid_hex[GIT_MAX_HEXSZ + 1]; > int flag, ret; > > + if (conflicted) > + *conflicted = false; > + > if (!refs_ref_exists(get_main_ref_store(r), refname)) > return 0; > > @@ -4858,7 +4866,7 @@ static int apply_save_autostash_ref(struct repository *r, const char *refname, > oid_to_hex_r(stash_oid_hex, &stash_oid); > ret = apply_save_autostash_oid(stash_oid_hex, attempt_apply, > label_ours, label_theirs, label_base, > - stash_msg); > + stash_msg, conflicted); > > refs_delete_ref(get_main_ref_store(r), "", refname, > &stash_oid, REF_NO_DEREF); > @@ -4869,16 +4877,17 @@ static int apply_save_autostash_ref(struct repository *r, const char *refname, > int save_autostash_ref(struct repository *r, const char *refname) > { > return apply_save_autostash_ref(r, refname, 0, > - NULL, NULL, NULL, NULL); > + NULL, NULL, NULL, NULL, NULL); > } > > int apply_autostash_ref(struct repository *r, const char *refname, > const char *label_ours, const char *label_theirs, > - const char *label_base, const char *stash_msg) > + const char *label_base, const char *stash_msg, > + bool *conflicted) > { > return apply_save_autostash_ref(r, refname, 1, > label_ours, label_theirs, label_base, > - stash_msg); > + stash_msg, conflicted); > } > > static int checkout_onto(struct repository *r, struct replay_opts *opts, > diff --git a/sequencer.h b/sequencer.h > index 64a9c7fb1b..b39528b6d0 100644 > --- a/sequencer.h > +++ b/sequencer.h > @@ -237,7 +237,8 @@ int apply_autostash(const char *path); > int apply_autostash_oid(const char *stash_oid); > int apply_autostash_ref(struct repository *r, const char *refname, > const char *label_ours, const char *label_theirs, > - const char *label_base, const char *stash_msg); > + const char *label_base, const char *stash_msg, > + bool *conflicted); > > #define SUMMARY_INITIAL_COMMIT (1 << 0) > #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1) ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] checkout -m: refine autostash fallback 2026-07-25 15:34 [PATCH 0/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-07-25 15:34 ` [PATCH 1/2] sequencer: teach autostash apply to report conflicts Harald Nordgren via GitGitGadget @ 2026-07-25 15:34 ` Harald Nordgren via GitGitGadget 2026-07-28 22:49 ` Junio C Hamano 2026-08-27 13:05 ` Phillip Wood 2026-08-26 19:14 ` [PATCH 0/2] " Junio C Hamano 2 siblings, 2 replies; 8+ messages in thread From: Harald Nordgren via GitGitGadget @ 2026-07-25 15:34 UTC (permalink / raw) To: git; +Cc: Harald Nordgren, Harald Nordgren From: Harald Nordgren <haraldnordgren@gmail.com> When unpack_trees() fails under "git checkout -m", only create an autostash and retry if there are tracked local changes. Without such changes, the fallback cannot help and merely repeats the same failure. Use the conflict result from apply_autostash_ref() to print a blank line before the branch-switch message, visually separating it from the conflict advice. Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> --- builtin/checkout.c | 17 +++++++++++++---- t/t7201-co.sh | 17 ++++++++++++++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index 72aafa4049..2e8b2a2348 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -838,10 +838,11 @@ static void init_topts(struct unpack_trees_options *topts, static int merge_working_tree(const struct checkout_opts *opts, struct branch_info *old_branch_info, struct branch_info *new_branch_info, - bool quiet, + bool allow_autostash, int *writeout_error) { int ret; + bool can_autostash = false; struct lock_file lock_file = LOCK_INIT; struct tree *new_tree; @@ -888,9 +889,13 @@ static int merge_working_tree(const struct checkout_opts *opts, return 1; } + if (allow_autostash) + can_autostash = has_unstaged_changes(the_repository, 1) || + has_uncommitted_changes(the_repository, 1); + /* 2-way merge to the new branch */ init_topts(&topts, opts->show_progress, - opts->overwrite_ignore, quiet); + opts->overwrite_ignore, can_autostash); init_checkout_metadata(&topts.meta, new_branch_info->refname, new_branch_info->commit ? &new_branch_info->commit->object.oid : @@ -917,7 +922,8 @@ static int merge_working_tree(const struct checkout_opts *opts, clear_unpack_trees_porcelain(&topts); if (ret == -1) { rollback_lock_file(&lock_file); - return MERGE_WORKING_TREE_UNPACK_FAILED; + return can_autostash ? + MERGE_WORKING_TREE_UNPACK_FAILED : 1; } } @@ -1166,6 +1172,7 @@ static int switch_branches(const struct checkout_opts *opts, int flag, writeout_error = 0; int do_merge = 1; int created_autostash = 0; + bool autostash_conflicted = false; struct strbuf old_commit_shortname = STRBUF_INIT; struct strbuf autostash_msg = STRBUF_INIT; const char *stash_label_base = NULL; @@ -1243,7 +1250,7 @@ static int switch_branches(const struct checkout_opts *opts, "local", stash_label_base, autostash_msg.buf, - NULL); + &autostash_conflicted); } if (ret) { branch_info_release(&old_branch_info); @@ -1256,6 +1263,8 @@ static int switch_branches(const struct checkout_opts *opts, if (!opts->quiet && !old_branch_info.path && old_branch_info.commit && new_branch_info->commit != old_branch_info.commit) orphaned_commit_warning(old_branch_info.commit, new_branch_info->commit); + if (autostash_conflicted && !opts->quiet) + fputc('\n', stderr); update_refs_for_switch(opts, &old_branch_info, new_branch_info); if (created_autostash) { diff --git a/t/t7201-co.sh b/t/t7201-co.sh index 0ddd1ad7aa..f9696dab36 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -240,6 +240,14 @@ test_expect_success 'checkout -m creates a recoverable stash on conflict' ' test_grep "git stash drop" actual && test_grep "git stash pop" actual && test_grep "The following paths have local changes" actual && + sed -n "/apply the local changes later/,/Switched to branch/p" \ + actual >separator.actual && + cat >separator.expect <<-EOF && + apply the local changes later by running "git stash pop". + + Switched to branch ${SQ}side${SQ} + EOF + test_cmp separator.expect separator.actual && git log -p -1 --format="%gs%n%B" -g --diff-merges=1 refs/stash >actual && sed /^index/d actual >actual.trimmed && cat >expect <<-EOF && @@ -262,11 +270,18 @@ test_expect_success 'checkout -m creates a recoverable stash on conflict' ' git reset --hard ' -test_expect_success 'checkout -m which would overwrite untracked file' ' +test_expect_success 'checkout -m only retries untracked-file failure with local changes' ' git checkout -f --detach main && test_commit another-file && git checkout HEAD^ && >another-file.t && + test_must_fail env GIT_TRACE2_EVENT="$(pwd)/trace" \ + git checkout -m @{-1} 2>err && + test_grep "untracked working tree files" err && + grep "\"region_enter\".*\"category\":\"index\",\"label\":\"refresh\"" \ + trace >refresh.events && + test_line_count = 1 refresh.events && + fill 1 2 3 4 5 >one && test_must_fail git checkout -m @{-1} 2>err && q_to_tab >expect <<-\EOF && -- gitgitgadget ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] checkout -m: refine autostash fallback 2026-07-25 15:34 ` [PATCH 2/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget @ 2026-07-28 22:49 ` Junio C Hamano 2026-08-27 13:05 ` Phillip Wood 1 sibling, 0 replies; 8+ messages in thread From: Junio C Hamano @ 2026-07-28 22:49 UTC (permalink / raw) To: Harald Nordgren via GitGitGadget; +Cc: git, Harald Nordgren "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com> writes: > From: Harald Nordgren <haraldnordgren@gmail.com> > > When unpack_trees() fails under "git checkout -m", only create an > autostash and retry if there are tracked local changes. Without such > changes, the fallback cannot help and merely repeats the same failure. > > Use the conflict result from apply_autostash_ref() to print a blank line > before the branch-switch message, visually separating it from the > conflict advice. > > Signed-off-by: Harald Nordgren <haraldnordgren@gmail.com> > --- > builtin/checkout.c | 17 +++++++++++++---- > t/t7201-co.sh | 17 ++++++++++++++++- > 2 files changed, 29 insertions(+), 5 deletions(-) Thanks. Will queue. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] checkout -m: refine autostash fallback 2026-07-25 15:34 ` [PATCH 2/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-07-28 22:49 ` Junio C Hamano @ 2026-08-27 13:05 ` Phillip Wood 1 sibling, 0 replies; 8+ messages in thread From: Phillip Wood @ 2026-08-27 13:05 UTC (permalink / raw) To: Harald Nordgren via GitGitGadget, git; +Cc: Harald Nordgren, Junio C Hamano Hi Harald On 25/07/2026 16:34, Harald Nordgren via GitGitGadget wrote: > From: Harald Nordgren <haraldnordgren@gmail.com> > > When unpack_trees() fails under "git checkout -m", only create an > autostash and retry if there are tracked local changes. Without such > changes, the fallback cannot help and merely repeats the same failure. Unfortunately to do that we have to look for local changes before the first call to unpack_trees() so we're trading an occasional inconvenience of an unnecessary stash and unstash for the cost of looking for local changes on every invocation of "git checkout -m". I don't think that is a good trade off, especially as there is no guarantee that stashing the local changes will make unpack_trees() succeed. To do this effectively would require refactoring unpack_trees() to write its error messages to a buffer and return an error flag that indicates all the errors that were encountered. We could then check if the only thing that prevented upack_trees() from succeeding was local changes to files and stash them, or if there are other errors print the error message. I suspect such a change is far from straight forward. > Use the conflict result from apply_autostash_ref() to print a blank line > before the branch-switch message, visually separating it from the > conflict advice. This change is very welcome and could happily be squashed into the first patch as it motivates the changes in it. > diff --git a/t/t7201-co.sh b/t/t7201-co.sh > index 0ddd1ad7aa..f9696dab36 100755 > --- a/t/t7201-co.sh > +++ b/t/t7201-co.sh > @@ -240,6 +240,14 @@ test_expect_success 'checkout -m creates a recoverable stash on conflict' ' > test_grep "git stash drop" actual && > test_grep "git stash pop" actual && > test_grep "The following paths have local changes" actual && > + sed -n "/apply the local changes later/,/Switched to branch/p" \ > + actual >separator.actual && > + cat >separator.expect <<-EOF && > + apply the local changes later by running "git stash pop". > + > + Switched to branch ${SQ}side${SQ} > + EOF > + test_cmp separator.expect separator.actual && I wonder whether we should just bite the bullet and check what gets printed to the screen with test_cmp, rather than grepping for all these separate parts of the message. Is there something in the message that makes that difficult? Thanks Phillip > git log -p -1 --format="%gs%n%B" -g --diff-merges=1 refs/stash >actual && > sed /^index/d actual >actual.trimmed && > cat >expect <<-EOF && > @@ -262,11 +270,18 @@ test_expect_success 'checkout -m creates a recoverable stash on conflict' ' > git reset --hard > ' > > -test_expect_success 'checkout -m which would overwrite untracked file' ' > +test_expect_success 'checkout -m only retries untracked-file failure with local changes' ' > git checkout -f --detach main && > test_commit another-file && > git checkout HEAD^ && > >another-file.t && > + test_must_fail env GIT_TRACE2_EVENT="$(pwd)/trace" \ > + git checkout -m @{-1} 2>err && > + test_grep "untracked working tree files" err && > + grep "\"region_enter\".*\"category\":\"index\",\"label\":\"refresh\"" \ > + trace >refresh.events && > + test_line_count = 1 refresh.events && > + > fill 1 2 3 4 5 >one && > test_must_fail git checkout -m @{-1} 2>err && > q_to_tab >expect <<-\EOF && ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] checkout -m: refine autostash fallback 2026-07-25 15:34 [PATCH 0/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-07-25 15:34 ` [PATCH 1/2] sequencer: teach autostash apply to report conflicts Harald Nordgren via GitGitGadget 2026-07-25 15:34 ` [PATCH 2/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget @ 2026-08-26 19:14 ` Junio C Hamano 2026-08-27 13:12 ` Phillip Wood 2 siblings, 1 reply; 8+ messages in thread From: Junio C Hamano @ 2026-08-26 19:14 UTC (permalink / raw) To: Phillip Wood; +Cc: git, Harald Nordgren "Harald Nordgren via GitGitGadget" <gitgitgadget@gmail.com> writes: > Avoiding checkout -m autostash retries when no tracked local changes exist > and visually separating autostash conflict advice from the subsequent > branch-switch message. > > Addresses #leftoverbits from here: > https://lore.kernel.org/git/cfd09dbf-8d77-4464-8030-3a0ffb4aeae7@gmail.com/ > > Harald Nordgren (2): > sequencer: teach autostash apply to report conflicts > checkout -m: refine autostash fallback > > builtin/checkout.c | 18 ++++++++++++++---- > builtin/commit.c | 2 +- > builtin/merge.c | 6 +++--- > sequencer.c | 29 +++++++++++++++++++---------- > sequencer.h | 3 ++- > t/t7201-co.sh | 17 ++++++++++++++++- > 6 files changed, 55 insertions(+), 20 deletions(-) > > > base-commit: 9a0c4701dcd5725c4184599322b52933ff5005ca > Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2364%2FHaraldNordgren%2Fhn%2Fgit-checkout-m-leftoverbits-v1 > Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2364/HaraldNordgren/hn/git-checkout-m-leftoverbits-v1 > Pull-Request: https://github.com/git/git/pull/2364 This topic unfortunately has seen no interests from others on the list. Asking Phillip for help, as the leftoverbits comment cited in the cover letter is from him. Thanks. ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] checkout -m: refine autostash fallback 2026-08-26 19:14 ` [PATCH 0/2] " Junio C Hamano @ 2026-08-27 13:12 ` Phillip Wood 0 siblings, 0 replies; 8+ messages in thread From: Phillip Wood @ 2026-08-27 13:12 UTC (permalink / raw) To: Junio C Hamano, Phillip Wood; +Cc: git, Harald Nordgren On 26/08/2026 20:14, Junio C Hamano wrote: > > This topic unfortunately has seen no interests from others on the > list. Asking Phillip for help, as the leftoverbits comment cited in > the cover letter is from him. That'll teach me to make suggestions for further work when I'm reviewing patches! Thanks for following up on those comments Harald. I've left some comments, in short I think the changes to the error message are a good idea, but I'm not sure sure about the other change in patch 2 though. Thanks Phillip ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-27 13:12 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-07-25 15:34 [PATCH 0/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-07-25 15:34 ` [PATCH 1/2] sequencer: teach autostash apply to report conflicts Harald Nordgren via GitGitGadget 2026-08-27 13:01 ` Phillip Wood 2026-07-25 15:34 ` [PATCH 2/2] checkout -m: refine autostash fallback Harald Nordgren via GitGitGadget 2026-07-28 22:49 ` Junio C Hamano 2026-08-27 13:05 ` Phillip Wood 2026-08-26 19:14 ` [PATCH 0/2] " Junio C Hamano 2026-08-27 13:12 ` Phillip Wood
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox