All of lore.kernel.org
 help / color / mirror / Atom feed
* switch/checkout stops halfway when it fails to write tracking config
@ 2026-10-20  1:39 井上司
  2026-10-20  4:11 ` Junio C Hamano
  2026-10-20 13:06 ` D. Ben Knoble
  0 siblings, 2 replies; 5+ messages in thread
From: 井上司 @ 2026-10-20  1:39 UTC (permalink / raw)
  To: git

1. What happened
When writing the tracking config fails (e.g. .git/config.lock exists) while
switch or checkout creates a new branch, the command exits with code 1 in the
middle of the switch. The worktree and index are already updated for the new
branch, but HEAD still points to the old branch. The user then sees unrelated
staged changes.

2. Reproduction
git init -q -b main up
cd up
echo one >file && git add file && git commit -q -m one
git branch feat
cd ..
git clone -q up work
cd up
git switch -q feat
echo two >>file && git commit -q -a -m two
cd ../work
git fetch -q
touch .git/config.lock
git switch feat; echo "exit=$?"
git symbolic-ref HEAD
git status --short

Output (git 2.43.0):
error: could not lock config file .git/config: File exists
error: unable to write upstream branch configuration
hint:
hint: After fixing the error cause you may try to fix up
hint: the remote tracking information by invoking:
hint:   git branch --set-upstream-to=origin/refs/heads/feat
exit=1
refs/heads/main
M  file

3. Expectation
I expected it to either complete the switch, or fail without changing anything.

4. Scope
The reproduction above uses DWIM (git switch feat). The same happens with
switch -c, checkout -b, and --track. With -C on another existing branch, that
branch is reset before the failure, so its old commits can only be found in
the reflog.

5. Root cause
update_refs_for_switch() -> create_branch() -> setup_tracking() fails to write
the config, and the code calls exit(1) in setup_tracking() (branch.c). At that
point the worktree and the branch have been changed, but HEAD has not. This
exit was introduced in 27852b2c53 (branch: report errors in tracking branch
setup, 2016-02-22).

6. Related
The wrong hint printed for the same failure is fixed separately in
<lore URL>. That patch does not fix this problem.

7. Next steps
I would like to work on a fix. Should checkout finish the switch and only
report the tracking error, or should it fail before touching the worktree?

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: switch/checkout stops halfway when it fails to write tracking config
  2026-10-20  1:39 switch/checkout stops halfway when it fails to write tracking config 井上司
@ 2026-10-20  4:11 ` Junio C Hamano
  2026-10-20  6:33   ` 井上司
  2026-10-20 13:06 ` D. Ben Knoble
  1 sibling, 1 reply; 5+ messages in thread
From: Junio C Hamano @ 2026-10-20  4:11 UTC (permalink / raw)
  To: 井上司; +Cc: git

井上司 <inoue.tsukasa.4@gmail.com> writes:

> 7. Next steps
> I would like to work on a fix. Should checkout finish the switch and only
> report the tracking error, or should it fail before touching the worktree?

Either would be an improvement over the reported behaviour, but if
we can make it atomic "all-or-none" matter, that would be more
preferrable than switching without setting up the tracking.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: switch/checkout stops halfway when it fails to write tracking config
  2026-10-20  4:11 ` Junio C Hamano
@ 2026-10-20  6:33   ` 井上司
  0 siblings, 0 replies; 5+ messages in thread
From: 井上司 @ 2026-10-20  6:33 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Thanks for the reply.

I agree with your point. However, implementing full atomicity now would
be a large change, for two reasons:

- push -u, clone and fetch continue even when writing the tracking config
  fails, but setup_tracking() calls exit() and aborts the process.
- For full atomicity, we would need to undo the worktree, the ref and the
  config. We would also need to handle the die() calls in checkout.

So I propose to make setup_tracking() return an error instead of calling
exit(), so that switch and checkout can behave like the other callers,
and to leave full atomicity as a separate topic.

2026年10月20日(火) 13:11 Junio C Hamano <gitster@pobox.com>:
>
> 井上司 <inoue.tsukasa.4@gmail.com> writes:
>
> > 7. Next steps
> > I would like to work on a fix. Should checkout finish the switch and only
> > report the tracking error, or should it fail before touching the worktree?
>
> Either would be an improvement over the reported behaviour, but if
> we can make it atomic "all-or-none" matter, that would be more
> preferrable than switching without setting up the tracking.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: switch/checkout stops halfway when it fails to write tracking config
  2026-10-20  1:39 switch/checkout stops halfway when it fails to write tracking config 井上司
  2026-10-20  4:11 ` Junio C Hamano
@ 2026-10-20 13:06 ` D. Ben Knoble
  2026-10-20 15:08   ` 井上司
  1 sibling, 1 reply; 5+ messages in thread
From: D. Ben Knoble @ 2026-10-20 13:06 UTC (permalink / raw)
  To: 井上司; +Cc: git

On Mon, Oct 19, 2026 at 9:41 PM 井上司 <inoue.tsukasa.4@gmail.com> wrote:
>
> 5. Root cause
> update_refs_for_switch() -> create_branch() -> setup_tracking() fails to write
> the config, and the code calls exit(1) in setup_tracking() (branch.c). At that
> point the worktree and the branch have been changed, but HEAD has not. This
> exit was introduced in 27852b2c53 (branch: report errors in tracking branch
> setup, 2016-02-22).

I can see where create_branch() is called prior to setting up HEAD,
but I'm mildly confused about the index/wt updates prior to either! It
seems to me that should be one of the last steps, hm. Unfortunately,
I'm having a hard time finding the responsible code outside of the
"merge" case (which probably has a similar issue).

-- 
D. Ben Knoble

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: switch/checkout stops halfway when it fails to write tracking config
  2026-10-20 13:06 ` D. Ben Knoble
@ 2026-10-20 15:08   ` 井上司
  0 siblings, 0 replies; 5+ messages in thread
From: 井上司 @ 2026-10-20 15:08 UTC (permalink / raw)
  To: D. Ben Knoble; +Cc: git

> I can see where create_branch() is called prior to setting up HEAD,
> but I'm mildly confused about the index/wt updates prior to either! It
> seems to me that should be one of the last steps, hm. Unfortunately,
> I'm having a hard time finding the responsible code outside of the
> "merge" case (which probably has a similar issue).


- merge_working_tree() updates the worktree and the index. It is called
  from switch_branches() on every branch switch, not only with -m,
  because do_merge starts at 1.
- The "merge" here is not -m. It is the 2-way merge in unpack_trees().
  -m only adds an autostash step for when that 2-way merge fails.
- The order is: update the worktree, create the ref, write the tracking
  config (which fails), then update HEAD. As you noticed, the worktree
  and index are updated before the ref and HEAD, so a failure later
  leaves those changes in place.
- As you guessed, the -m case has the same problem. I tried
  "git switch -m -c y origin/main" with the lock present (v2.56.0 plus
  my hint patch, which only changes the hint text). It stops in the same
  place. If local changes conflict, HEAD stays on main, the file is left
  conflicted, and the changes remain in the stash.
- Running the same command again in that conflicted state stops with
  "a branch named 'y' already exists". Switching to the existing branch
  y stops with "you need to resolve your current index first"
  (checkout.c:887 in v2.56.0). Neither run changes the state.

2026年10月20日(火) 22:07 D. Ben Knoble <ben.knoble@gmail.com>:
>
> On Mon, Oct 19, 2026 at 9:41 PM 井上司 <inoue.tsukasa.4@gmail.com> wrote:
> >
> > 5. Root cause
> > update_refs_for_switch() -> create_branch() -> setup_tracking() fails to write
> > the config, and the code calls exit(1) in setup_tracking() (branch.c). At that
> > point the worktree and the branch have been changed, but HEAD has not. This
> > exit was introduced in 27852b2c53 (branch: report errors in tracking branch
> > setup, 2016-02-22).
>
> I can see where create_branch() is called prior to setting up HEAD,
> but I'm mildly confused about the index/wt updates prior to either! It
> seems to me that should be one of the last steps, hm. Unfortunately,
> I'm having a hard time finding the responsible code outside of the
> "merge" case (which probably has a similar issue).
>
> --
> D. Ben Knoble

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-10-20 15:09 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-20  1:39 switch/checkout stops halfway when it fails to write tracking config 井上司
2026-10-20  4:11 ` Junio C Hamano
2026-10-20  6:33   ` 井上司
2026-10-20 13:06 ` D. Ben Knoble
2026-10-20 15:08   ` 井上司

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.