Skip to content

fix: libgit2 branch checkout to avoid half-switched HEAD#332

Merged
Dimillian merged 1 commit intoDimillian:mainfrom
ishanray:fix/branch-switcher-checkout-head
Feb 4, 2026
Merged

fix: libgit2 branch checkout to avoid half-switched HEAD#332
Dimillian merged 1 commit intoDimillian:mainfrom
ishanray:fix/branch-switcher-checkout-head

Conversation

@ishanray
Copy link
Contributor

@ishanray ishanray commented Feb 4, 2026

Problem

When checkout_branch encountered an error (e.g., dirty working tree conflicts or missing target branch), the repository could be left in an inconsistent state with HEAD pointing to a branch that was never actually checked out.

This happened because the previous implementation called set_head() before checkout_head(). If the checkout failed, HEAD was already updated, leaving the repo in a half-switched state.

Solution

Reorder the libgit2 operations:

  1. Resolve the target ref first — validate the branch exists via revparse_single()
  2. Checkout the tree — use checkout_tree() to switch the working directory
  3. Update HEAD last — only call set_head() after a successful checkout

This ensures HEAD is never updated unless the checkout succeeds, making the operation atomic from the user's perspective.

How to Reproduce (Before Fix)

  1. Open a workspace in CodexMonitor
  2. Have uncommitted changes that would conflict with a target branch
  3. Use the branch switcher (Cmd+B) to switch branches
  4. Observe that if the checkout fails due to conflicts, git status may show you on the new branch but with the old tree, or vice versa

Alternatively:

  1. Try to switch to a branch name that doesn't exist
  2. Before this fix, HEAD could be set to an invalid ref before the error was raised

Testing

Added a unit test checkout_branch_missing_does_not_change_head that:

  • Creates a temp repo with an initial commit
  • Attempts to checkout a non-existent branch
  • Asserts HEAD remains unchanged after the error

@ishanray ishanray force-pushed the fix/branch-switcher-checkout-head branch from d907a4b to bda70ac Compare February 4, 2026 04:05
@Dimillian
Copy link
Owner

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Keep them coming!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@Dimillian Dimillian changed the title Fix libgit2 branch checkout to avoid half-switched HEAD fix: libgit2 branch checkout to avoid half-switched HEAD Feb 4, 2026
@Dimillian Dimillian merged commit b1cd287 into Dimillian:main Feb 4, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants