Git branch switch fails on Windows: Cursor holds .git/HEAD open ("couldn't set HEAD") even after reload and git.enabled=false

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

On Windows, Cursor keeps an open handle on .git/HEAD, which prevents Git from updating the current branch pointer. Any git switch / git checkout fails with:
error: couldn’t set ‘HEAD’ fatal: unable to update HEAD

This happens even when:

  • terminal.integrated.shellIntegration.enabled is set to false (global)
  • git.autorefresh: false, git.autofetch: false (global + workspace)
  • files.watcherExclude: { "**/.git/**": true } (global + workspace)
  • Developer: Reload Window was performed (issue persists after reload)
  • git.enabled: false was temporarily set in workspace settings (HEAD still locked while Cursor is running)

Exclusive write test on .git/HEAD fails with “file is being used by another process” while Cursor is open.

Branch switch only succeeds after fully quitting Cursor (all windows + tray) and running git switch <branch> from an external PowerShell window.

This appears related to / a regression of:

Steps to Reproduce

  1. Open a Git repository in Cursor on Windows
  2. Ensure Cursor is running (Agent/terminal may be used but issue also blocks manual git in integrated terminal)
  3. Run in terminal: git switch etp20-9521 (or any existing local branch)
  4. Observe: error: couldn't set 'HEAD'
  5. Try Developer: Reload Window → run git switch again → same error
  6. Fully quit Cursor (verify no Cursor.exe in Task Manager)
  7. Run git switch etp20-9521 in external PowerShell → succeeds
  8. Reopen Cursor → git branch --show-current shows correct branch; .git/HEAD is writable again

Expected Behavior

Git branch switching should work from Cursor’s integrated terminal (and Agent shell) without requiring a full IDE shutdown.

Operating System

Windows 10/11

Version Information

  • Cursor Version: 3.18.9
  • OS: Windows 10 (10.0.26200)
  • Git: 2.47.1.windows.2
  • Shell: PowerShell 5.1

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey @skatoy, thanks for the detailed report.

I haven’t been able to reproduce this. Running git switch while in a Git repo works fine on my Windows VM.

Could you try this while the issue is happening (Cursor open, git switch failing)?

  1. Press Win+R, type resmon, and press Enter to open Resource Monitor.
  2. Go to the CPU tab.
  3. In the “Associated Handles” section, type HEAD into the search box and press Enter.
  4. Find the row whose Handle Name ends with \.git\HEAD and note the Image (process name) and PID.
  5. Open PowerShell and run: (Get-CimInstance Win32_Process -Filter "ProcessId=<PID>").CommandLine (replace <PID> with the number from step 4).
  6. Reply with the process name, the PID, and the command line from step 5.

Cursor runs several helper processes, so that command line is what tells us exactly which component has the file open. Thanks!

(post deleted by author)

Hi Colin, here are the diagnostics while the issue is active (Cursor open, git switch master failing):

Error: couldn’t set ‘HEAD’ fatal: unable to update HEAD

Environment:

  • Cursor 3.18.9
  • Windows 10.0.26200
  • Git 2.47.1.windows.2
  • Repo: C:\Users\dy.alekseev\AutoTests\at-etp20
  • Current branch stays on etp20-8005 after failed switch to master

Handle (from handle64 / Resource Monitor equivalent):
C:\Users\dy.alekseev\AutoTests\at-etp20\.git\HEAD

Processes holding the file: 12 separate Cursor.exe processes, each with 3 open handles on .git\HEAD.

Example (PID 7776):

  • Image: Cursor.exe
  • PID: 7776
  • CommandLine: "C:\Users\dy.alekseev\AppData\Local\Programs\cursor\Cursor.exe" --type=utility --utility-sub-type=node.mojom.NodeService --lang=en-US --service-sandbox-type=none ...

All 12 PIDs show the same pattern: --type=utility --utility-sub-type=node.mojom.NodeService (not git.exe, not renderer).

Other PIDs with the same command line pattern: 2576, 13896, 25632, 7936, 25048, 21400, 19036, 25844, 2720, 19572, 21872

Note: Git settings were restored to defaults (no git.enabled=false, no files.watcherExclude for .git). Issue still reproduces.

Let me know if you need full command lines for all PIDs or a screenshot from resmon.

Thanks @skatoy!

Those processes are Cursor’s Node.js helper services (extension hosts, the terminal host, file watchers, and similar). They all share that exact command line, so the last step is to map each PID to its role using Cursor’s built-in process viewer:

  1. Reproduce the failure (Cursor open, git switch failing).
  2. Re-run your handle check so you have a current list of the PIDs holding .git\HEAD.
  3. In Cursor, press Ctrl+Shift+P to open the Command Palette.
  4. Type Process Explorer and press Enter. A separate window opens listing every Cursor process with its PID and a name such as extensionHost, fileWatcher, ptyHost, or shared-process.
  5. Find each PID from step 2 in that window and note the name shown for it. A screenshot of the Process Explorer window is also fine.
  6. Reply with that PID-to-name mapping.

Also helpful: how many Cursor windows you had open at the time, and which extensions you have installed (especially git related ones).

If the holders turn out to be extension host processes, one more test would tell us a lot: close all Cursor windows except the one with this repo, run “Developer: Reload With Extensions Disabled” from the Command Palette, then try git switch again and let us know if it still fails.

Thanks for sticking with this!