I am become race condition, destroyer of merges

Mar 08, 2026

OK, so I write software for a living and do open source, and this means two things:

  • I deal with a lot of repositories, big and small,
  • I spend a lot of time in the terminal.

But for the past couple of years, every now and then I would get this bogus error when interacting with some git repositories:

error: Unable to create '…/.git/index.lock': File exists.

Needless to say, nothing was interacting with my repository at the time.
Worse yet, immediately retrying the same operation would succeed. The file never existed when I checked for it, either.

Since this issue had been around long enough to earn squatter's rights, I couldn't help but start to pick up on a few patterns:

  • It was more likely to happen in large repositories (think >1M LOC).
  • It would happen most often during interactive rebases, which I do a lot (no judge, okay?).
  • It was not limited to rebases only, though.

The amount of times this caused me to have to redo a merge conflict resolution eventually added up enough to let me rewatch the entire Freeza saga, twice. I decided it was finally time to debug it.

A few hypotheses from my coworkers taking turns to mock my setup, and my defensive rebuttals:

  • This happens because you're on a network filesystem: no, I mostly work with local code.
  • This happens because you're running your machine from a floppy disk: actually, it's an NVMe, and unless someone's smuggling alien tech, that's about as fast as mortal hardware gets.
  • You're just using weird git config: how is it legal that even the most cursed .gitconfig can twist Git into spawning Heisenbugs out of plain old merges?
  • Weird aliases: nope – it's all normal commands going chaotic neutral.
  • Something writes to your directory: nope; it's just me and this process called git.

I figured it's either something wrong about my filesystem after all, or it's a bug in git itself (gasp!). I decided to read through the manpages and examine some more exotic settings to tweak first. Here's what I ended up with, having no idea what on earth I'm doing:

[core]
    filesRefLockTimeout = 1000
    packedRefsTimeout = 1000
    fsync = added
    multiPackIndex = false
    preloadIndex = false

[index]
    threads = 1

[reftable]
    lockTimeout = 1000

At first it seemed to have worked!
But no more than 2 days after, it happened again.
Sighhh.

So maybe it's a bug? But how is this possible?

I then figured I could force it to manifest by running some pointless rebases endlessly until it fails with this error, and the idea was to run strace on it. I did that and boom! Hit it after like half a minute. I looked at the strace output, and it really did look as if git had an internal bug and would just conflict with itself.

Then I had an epiphany.
For the first time in months, I looked at the top right corner of my tmux session. Lo and behold:

Look. I'm a nerd. I am supposed to have cool powerline‑looking crap in my terminal – a sleek prompt that tells you the branch you're on, what you're doing, what time it is, the current Mercury retrograde and all sorts of useful information. This is my attempt at it.

Except, I'd totally forgotten about it. Apparently, I don't need my terminal constantly whispering "you're on develop, sweetie". I'm pretty good at remembering that. The changed/unchanged file counts only matter when I'm actually poking the tree – when I run git status myself, with actual useful output like paths instead of just numbers. Or the current commit hash or tag – cute, but why?

And the problem with all of this is, that line doesn't appear by magic – it spawns a git status every few seconds as tmux refreshes the bar. So while I'm doing interactive rebases, it's sneaking in behind me, poking the same repo. That's when it clicked: even though git status only reads stuff, it still grabs a lock on the index. There's an --no‑optional‑locks flag for that, but I chose to just go the zen way.

I went to my dotfiles teahouse, and there it was: git-status, being ran every few seconds for years. RIP my near-alien-grade drive! I held a small rm -rf ceremony for it and I reran the smoke script.

This time, it didn't trigger anything for 10 minutes.

So… yeah. "Nothing's touching the repo", I said, unaware that I was playing a turbo-mode of hide‑and‑seek against myself. Shit game, BTW, about 2/10.