[clang] e89830d - Add option to format a whole file using git-clang-format (#204336)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 31 22:22:19 PDT 2026
Author: eoineoineoin
Date: 2026-07-31T22:22:14-07:00
New Revision: e89830da7f4e6656b9ff54ea7695c31435a53ee4
URL: https://github.com/llvm/llvm-project/commit/e89830da7f4e6656b9ff54ea7695c31435a53ee4
DIFF: https://github.com/llvm/llvm-project/commit/e89830da7f4e6656b9ff54ea7695c31435a53ee4.diff
LOG: Add option to format a whole file using git-clang-format (#204336)
Today, git-clang-format will only format lines which have been modified.
However, in some cases, that's not sufficient to get a "clean" file
which would be unmodified by running `clang-format` manually.
I've got a minimal repro using the default clang-format rules. Setup a
new git repository and create a commit with an empty file:
```
mkdir /tmp/bla
cd /tmp/bla
git init
touch t.cpp
git add t.cpp
git commit -m "V1"
```
Add a line to that file containing a comment:
```
echo "int x = 0; // Comment describing x" > t.cpp
git add t.cpp
git clang-format --staged # Reports "clang-format did not modify any files"
git commit -m "V2"
```
There's nothing wrong with this file yet, and it's working as expected.
Problem arises when we add a new line with a comment which is not
aligned with the comment we've already added:
```
echo "int longerThanX = 0; // Should cause above to become aligned" >> t.cpp
git add t.cpp
git clang-format --staged # Reports "clang-format did not modify any files"
```
git-clang-format didn't change the staged file here as it's only
inspecting the modified lines, but according to the default formatting
rules, this new line actually has an effect on the preceding line. i.e.,
if you run `clang-format t.cpp`, you'll see that whitespace is added
before the "Comment describing x" to align with the "Should cause..."
It's not limited to _just_ the preceding line (e.g. in the case where we
have multiple lines like the first with comments which become
unaligned,) so can't just add more lines of context to the diff. This PR
just adds an option to format the whole file, instead of just the
modified sections.
Added:
Modified:
clang/tools/clang-format/git-clang-format
Removed:
################################################################################
diff --git a/clang/tools/clang-format/git-clang-format b/clang/tools/clang-format/git-clang-format
index d79b57e7f6e10..c9319c55213a3 100755
--- a/clang/tools/clang-format/git-clang-format
+++ b/clang/tools/clang-format/git-clang-format
@@ -202,6 +202,11 @@ def main():
default=0,
help="print extra information",
)
+ p.add_argument(
+ "--whole-file",
+ action="store_true",
+ help="format whole file instead of only modified lines",
+ )
p.add_argument(
"--
diff _from_common_commit",
action="store_true",
@@ -231,8 +236,8 @@ def main():
# When no commits are given explicitly and the pre-commit CI framework's
# environment variables are set, use them to define the
diff range.
if not opts.args and not dash_dash:
- from_ref = os.environ.get('PRE_COMMIT_FROM_REF')
- to_ref = os.environ.get('PRE_COMMIT_TO_REF')
+ from_ref = os.environ.get("PRE_COMMIT_FROM_REF")
+ to_ref = os.environ.get("PRE_COMMIT_TO_REF")
if from_ref and to_ref:
opts.args = [from_ref, to_ref]
if not opts.
diff and not opts.
diff stat:
@@ -256,7 +261,7 @@ def main():
opts.binary = os.path.abspath(opts.binary)
changed_lines = compute_
diff _and_extract_lines(
- commits, files, opts.staged, opts.
diff _from_common_commit
+ commits, files, opts.staged, opts.whole_file, opts.
diff _from_common_commit
)
if opts.verbose >= 1:
ignored_files = set(changed_lines)
@@ -410,10 +415,12 @@ def get_object_type(value):
return convert_string(stdout.strip())
-def compute_
diff _and_extract_lines(commits, files, staged,
diff _common_commit):
+def compute_
diff _and_extract_lines(
+ commits, files, staged, whole_file,
diff _common_commit
+):
"""Calls compute_
diff () followed by extract_lines()."""
diff _process = compute_
diff (commits, files, staged,
diff _common_commit)
- changed_lines = extract_lines(
diff _process.stdout)
+ changed_lines = extract_lines(
diff _process.stdout, whole_file)
diff _process.stdout.close()
diff _process.wait()
if
diff _process.returncode != 0:
@@ -446,7 +453,7 @@ def compute_
diff (commits, files, staged,
diff _common_commit):
return p
-def extract_lines(patch_file):
+def extract_lines(patch_file, whole_file):
"""Extract the changed lines in `patch_file`.
The return value is a dictionary mapping filename to a list of (start_line,
@@ -461,17 +468,23 @@ def extract_lines(patch_file):
match = re.search(r"^\+\+\+\ [^/]+/(.*)", line)
if match:
filename = match.group(1).rstrip("\r\n\t")
- match = re.search(r"^@@ -[0-9,]+ \+(\d+)(,(\d+))?", line)
- if match:
- start_line = int(match.group(1))
- line_count = 1
- if match.group(3):
- line_count = int(match.group(3))
- if line_count == 0:
- line_count = 1
- if start_line == 0:
+ if whole_file:
+ # Initialize the key for filename but ensure ranges is an empty
+ # list. This will prevent any filtering in clang_format_to_blob().
+ matches[filename] = []
continue
- matches.setdefault(filename, []).append(Range(start_line, line_count))
+ if not whole_file:
+ match = re.search(r"^@@ -[0-9,]+ \+(\d+)(,(\d+))?", line)
+ if match:
+ start_line = int(match.group(1))
+ line_count = 1
+ if match.group(3):
+ line_count = int(match.group(3))
+ if line_count == 0:
+ line_count = 1
+ if start_line == 0:
+ continue
+ matches.setdefault(filename, []).append(Range(start_line, line_count))
return matches
More information about the cfe-commits
mailing list