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
.gitconfigcan 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:
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.