From ff7d12a55366a69cbd1e0b3278861b5c42994c06 Mon Sep 17 00:00:00 2001 From: Harald Nordgren Date: Wed, 2 Sep 2026 18:29:03 +0000 Subject: [PATCH] checkout: separate autostash conflict advice from branch-switch message "git checkout -m" stashes the user's local changes when it cannot perform the checkout, and then applies the stash. When applying the stash results in conflicts, the advice on how to deal with them is printed directly on top of the branch-switch message ("Switched to branch ..."), making the two hard to tell apart. Print a blank line in between so that the advice and the branch-switch message are visually distinct. apply_autostash_ref() reports whether applying the stash resulted in conflicts via its enum stash_apply_result return value, so only print the blank line in the conflicted case. Signed-off-by: Harald Nordgren Signed-off-by: Junio C Hamano --- builtin/checkout.c | 15 +++++++++------ t/t7201-co.sh | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/builtin/checkout.c b/builtin/checkout.c index b78b3a1d16..9cb3e6d0ee 100644 --- a/builtin/checkout.c +++ b/builtin/checkout.c @@ -1163,6 +1163,7 @@ static int switch_branches(const struct checkout_opts *opts, int flag, writeout_error = 0; int do_merge = 1; int created_autostash = 0; + enum stash_apply_result autostash_res = STASH_APPLY_CLEAN; struct strbuf old_commit_shortname = STRBUF_INIT; struct strbuf autostash_msg = STRBUF_INIT; const char *stash_label_base = NULL; @@ -1234,12 +1235,12 @@ static int switch_branches(const struct checkout_opts *opts, git_config_push_parameter(cfg.buf); strbuf_release(&cfg); } - apply_autostash_ref(the_repository, - "CHECKOUT_AUTOSTASH_HEAD", - new_branch_info->name, - "local", - stash_label_base, - autostash_msg.buf); + autostash_res = apply_autostash_ref(the_repository, + "CHECKOUT_AUTOSTASH_HEAD", + new_branch_info->name, + "local", + stash_label_base, + autostash_msg.buf); } if (ret) { branch_info_release(&old_branch_info); @@ -1252,6 +1253,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_res == STASH_APPLY_CONFLICT && !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 7613b1d2a4..641d6239dc 100755 --- a/t/t7201-co.sh +++ b/t/t7201-co.sh @@ -236,10 +236,18 @@ test_expect_success 'checkout -m creates a recoverable stash on conflict' ' test_must_fail git checkout side 2>stderr && test_grep "Your local changes" stderr && git checkout -m side >actual 2>&1 && - test_grep "resulted in conflicts" actual && - test_grep "git stash drop" actual && - test_grep "git stash pop" actual && - test_grep "The following paths have local changes" actual && + cat >expect <<-EOF && + Your local changes are stashed, however applying them + resulted in conflicts. You can either resolve the conflicts + and then discard the stash with "git stash drop", or, if you + do not want to resolve them now, run "git reset --hard" and + apply the local changes later by running "git stash pop". + + Switched to branch ${SQ}side${SQ} + The following paths have local changes: + M one + EOF + test_cmp expect 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 &&