https://github.com/DiamonDinoia created 
https://github.com/llvm/llvm-project/pull/187379

Dear team, this is my first contribution. I used Claude to investigate the 
problem as I do not know the codebase too well. I read the policy and AI 
assistance is allowed. Let me know if I am violating any policy or  if there 
are any problems I am more than happy to fix them. 

Thanks for you patience. 

`git-clang-format` uses a fixed path (`.git/clang-format-index`) for its 
temporary index file. When concurrent git operations interact with this file 
(most commonly via the [pre-commit](https://pre-commit.com/) framework), git's 
internal locking creates `.git/clang-format-index.lock` which persists after 
abnormal exits, **blocking all subsequent commits**.

The fix replaces the fixed path with a unique temporary file via 
`tempfile.mkstemp()`.

## How to reproduce

1. Add `git-clang-format --staged` as a [pre-commit](https://pre-commit.com/) 
hook:

```yaml
# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: clang-format-staged
        name: clang-format (staged hunks)
        entry: git-clang-format --binary clang-format --staged
        language: python
        additional_dependencies: [clang-format==22.*]
        pass_filenames: true
        types_or: [c++, c, cuda]
        files: \.(c|cc|cpp|h|hpp|cu|cuh)$
```
2. Stage C/C++ files and run git commit repeatedly. After a few commits 
(especially ones where clang-format modifies files), the hook leaves behind
.git/clang-format-index.lock.
3. All subsequent commits fail with:
```
fatal: Unable to create '/path/to/repo/.git/clang-format-index.lock': File 
exists.

Another git process seems to be running in this repository, e.g.
an editor opened by 'git commit'. Please make sure all processes
are terminated then try again. If it still fails, a git process
may have crashed in this repository earlier:
remove the file manually to continue.
error: `git update-index --add -z --index-info` failed
```
The only recovery is rm .git/clang-format-index.lock.

### Root cause

create_temporary_index() in clang/tools/clang-format/git-clang-format writes to 
a fixed, non-unique path:
```
path = os.path.join(gitdir, temp_index_basename)  # always 
".git/clang-format-index"
```
When git update-index operates on this file, git creates 
clang-format-index.lock. If the process is interrupted (pre-commit timeout, 
signal, or concurrent git operations from other hooks in the same pipeline), 
the lock file is never cleaned up. The temporary_index_file() context manager 
removes the index file on exit but not the .lock file that git creates 
alongside it.

### Fix:

Replace the fixed path with tempfile.mkstemp(), so each invocation gets a 
unique filename. This eliminates both the stale lock problem and any potential 
race between concurrent invocations.
```

>From 4a7bb884776889fddc4053bb856f4459a867610c Mon Sep 17 00:00:00 2001
From: Marco Barbone <[email protected]>
Date: Wed, 18 Mar 2026 16:58:11 -0400
Subject: [PATCH] [clang-format] Fix stale .lock files in git-clang-format temp
 index

git-clang-format uses a fixed path (.git/clang-format-index) for its
temporary index file. When invoked from pre-commit hooks or other
concurrent git operations, the .lock file that git creates alongside
it can persist after abnormal exits, blocking all subsequent commits
with "Unable to create .git/clang-format-index.lock: File exists".

Replace the fixed path with a unique temporary file via
tempfile.mkstemp(), so concurrent invocations don't collide and stale
locks from crashed runs don't block future operations.

Assisted-by: Claude <[email protected]>
---
 clang/tools/clang-format/git-clang-format | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/clang/tools/clang-format/git-clang-format 
b/clang/tools/clang-format/git-clang-format
index dcc0a5347f5d2..ef578467bbc5d 100755
--- a/clang/tools/clang-format/git-clang-format
+++ b/clang/tools/clang-format/git-clang-format
@@ -31,6 +31,7 @@ import os
 import re
 import subprocess
 import sys
+import tempfile
 
 usage = "git clang-format [OPTIONS] [<commit>] [<commit>|--staged] [--] 
[<file>...]"
 
@@ -707,7 +708,12 @@ def create_temporary_index(tree=None):
     If `tree` is not None, use that as the tree to read in.  Otherwise, an
     empty index is created."""
     gitdir = run("git", "rev-parse", "--git-dir")
-    path = os.path.join(gitdir, temp_index_basename)
+    # Use a unique filename to avoid stale .lock files when concurrent git
+    # operations (e.g. pre-commit hooks) race with this process.
+    fd, path = tempfile.mkstemp(
+        prefix=temp_index_basename + "-", dir=gitdir
+    )
+    os.close(fd)
     if tree is None:
         tree = "--empty"
     run("git", "read-tree", "--index-output=" + path, tree)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to