I have a branch that I've been working on with a few commits. Some of these commits have code that should be formatted with clang-format, but not all code should be formatted. The practical solution to this is of course to do this:
git clang-format main -- path/to/files/to/format
This compares the currently checked out files with how they were in main
and runs clang-format on them. -- path/to/files/to/format
then limits the formatting to only this path. I could very easily commit this in a commit with subject "Clang format files", or similar, and carry on with my work.
I really want to be able to not have these formatting commits though. While using tools that automatically follows the formatting rules helps a lot, sometimes I still get into this situation with badly formatted code in my branch.
Previously I found a way to use git filter branch to do the formatting. It looks like this, in my .bashrc
:
clang-format-branch() {
sha=$1
git filter-branch -f --tree-filter \
"git-clang-format $sha || true" \
-- \
$sha..HEAD
}
If I'm on my-branch
that's branched out from main
, I can run this command like this:
clang-format-branch main
and it (slowly) rewrites my branch to have all files formatted properly. git-clang-format
compares against main
to find files to format. As there are sometimes no changes, the || true
is needed to not stop git filter-branch
.
Now, if you're like me, you'd think that this is simple: Simply put these two together in the following way:
git filter-branch -f --tree-filter "git-clang-format main -- path/to/files/to/format || true" -- main..HEAD
Which works perfectly! Now to my trouble: How do I get this into my .bashrc
file? The simple solution I tried is this:
clang-format-branch() {
sha=$1
shift 1
git filter-branch -f --tree-filter \
"git-clang-format $sha $@ || true" \
-- \
$sha..HEAD
}
to be able to run:
clang-format-branch main -- path/to/files/to/format
but then I get this:
fatal: bad revision 'path/to/files/to/format || true'
In some way, this get interpreted as a parameter to tree-filter instead of as a command to run. My guess is that it's because of the --
, which led me to think that there's maybe something wrong with escaping of the quotes. Here's where I spent time reading about quotes and checking if other tools (e.g. git-filter-repo) would help, but nothing has worked so far and I'm out of ideas. Is there some simple way to make this work?
I'm running on Windows with git bash if that has something to do with it.
Your problem is the $@
, which exists to construct multiple resulting strings from multiple supplied arguments, and does, here. Use $*
instead, which bungs all the arguments into the (single) result, which will then be re-burst by the shell when filter-branch runs it that way, as your filter.
Let me recommend this too-hacky-but-not-too-too-hacky function for your ~/.bashrc
:
-x ()
{
local -;
set -x;
"$@"
}
which is what I used (-x clang-format @~10 -- main.c
) to check my guess.