10

I am new to commit hooks as well as Clang formatting and am attempting to integrate the two. I have the pre-commit hook set up and I know how to run the Clang formatting on the command line, but am unsure of how to add it to the file.

This is the code I run in the command line for formatting: clang-format -i -style=llvm fileName

I am also trying to run this on all files that are staged for commit. git diff --cached --name-only

This is my pre-commit file:

hook_enabled=true

# Redirect output to stderr.
exec 1>&2

# If the hook is enabled and there are one or more files added to the commit run
# code formatting.
if [ "$hook_enabled" != "false" ] &&
    test $(git diff --cached --name-only $against | wc -c) != 0
then
    cat <<\EOF
  Code formatting changed some files, please review and re-add files with git add
EOF
    exit 1

I also added the clang-formatting to package.json:

    "pre-commit": "check-clang-format",
    "format": "git-clang-format",

Please help me integrate the clang-formatting.

Martina
  • 103
  • 1
  • 1
  • 5
  • Check here https://stackoverflow.com/questions/427207/can-git-hook-scripts-be-managed-along-with-the-repository for what hooks are all about. Understand how githooks work before using them. – Lovato May 06 '19 at 19:52

4 Answers4

8

I'm adding the following to the top of my REPO_ROOT/.git/hooks/pre-commit file:

for FILE in $(git diff --cached --name-only)
do
        clang-format -i $FILE
done

The .clang-format file is placed in the REPO_ROOT.

The other answer and the first comment to the original question doesn't say why it is preferred to avoid this solution, so I'd be happy to hear more about that.

Benjamin
  • 337
  • 3
  • 7
  • 5
    Adding a filer for extension is useful - `if [[ "$FILE" =~ \.(c|h|cpp|cc)$ ]]; then` otherwise all sorts of files will be "formatted" – ilya1725 May 15 '20 at 19:20
  • This will likely break for file names with white space. – bitmask Mar 22 '21 at 08:22
  • 1
    For the life of me I could not get the regex expression to work without expressly calling grep: `for FILE in $(git diff --cached --name-only | grep -E '.*\.(c|cpp|h|hpp)')` – Alex Baum May 03 '21 at 23:31
  • @AlexBaum the regular expression is insufficient, as files may be found as well ([see live example](https://regexr.com/6fnc1)). The word boundary must be detected. This expressions should be better: `.*\.(c|cpp|h|hpp)\b` – user5534993 Feb 18 '22 at 07:15
4

This is now (finally) very simple using the open source https://pre-commit.com (the framework):

repos:
- repo: https://github.com/pre-commit/mirrors-clang-format
  rev: v13.0.0
  hooks:
  - id: clang-format

It grabs a 1-2 MB binary from PyPI for all common platforms. You can pin clang-format 10, 11, or 12 (And now 13, same day release!). See https://github.com/ssciwr/clang-format-wheel. If you use https://pre-commit.ci, you get automatic update PRs and your PRs get automatically fixed.

Claudio
  • 2,139
  • 2
  • 16
  • 20
Henry Schreiner
  • 745
  • 1
  • 5
  • 17
2

Actually, you don't invoke a clang-format binary at pre-commit hook.

Here is an instruction how to setup clang format at pre-commit hook: https://github.com/andrewseidl/githook-clang-format

Installation First, verify that clang-format is installed. On Linux this should be included with the regular clang package. For

MacOSX with Homebrew, clang-format is available via brew install clang-format.

Now install clang-format.hook from this repository into your repo's .git/hooks. If you don't already have a pre-commit hook, you can simply copy clang-format.hook to .git/hooks/pre-commit. For example:

cp githook-clang-format/clang-format.hook myrepo/.git/hooks/pre-commit

Usage Once the pre-commit hook is installed, clang-format will be run on each file included in the commit when you run git commit.

By default, clang-format uses the LLVM style. To change this, either create a .clang-format file with your desired format in the top level of your repo, or set the hooks.clangformat.style config option in your repo. The .clang-format file method is preferred if you will be working with a team or will be doing any major customizations to the style.

You can generate the .clang-format file from your desired style (here, llvm) using:

clang-format -style=llvm -dump-config > .clang-format

To use the git config method, inside your repo do:

git config hooks.clangformat.style llvm

kenorb
  • 137,499
  • 74
  • 643
  • 694
Anton Vlasov
  • 1,280
  • 1
  • 10
  • 18
  • 3
    "Actually, you don't invoke a clang-format binary at pre-commit hook." This is simply a script that invokes `clang-format` in a pre-commit hook. – jazzpi Sep 29 '20 at 10:06
0

Another option (not pre-commit one, but it also can be applied for commit) is to run git clang-format HEAD~1 <whatever options>. This will affect only lines changed by latest commit. It makes changes in place, so -i is not needed in that case.

  • Since `clang-format` is not a git subcommand by default, consider adding a link to the script needed for this to work: https://llvm.org/svn/llvm-project/cfe/trunk/tools/clang-format/git-clang-format – Aritz Lopez Dec 14 '20 at 13:17
  • That link points to a file which I canot access (access forbidden). – Martin Ueding Jun 23 '21 at 07:01
  • https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-format/git-clang-format - here's updated link as llvm moved to Github – Kostya Kozko Jul 06 '21 at 09:58