问题
I wanted to setup code style formatting for all .cpp files before they are committed to git.
I made small script (named codeformat) to do this, (also tried replaing %f with $1)
#! /bin/bash
clang-format -style=file %f | diff %f -**
if [ $? -ne 0 ]; then
echo "ERROR: codeformat not correct"
exit 1
fi
did setup git config and updated .gitattributes with *.cpp filter=codeformat,
git config --global filter.codeformat.clean codeformat
git config --global filter.codeformat.smudge codeformat
looks like script is being run, but it is not getting file name. Why is this?
回答1:
You have the %f directive in the wrong place.
As shown in the gitattributes documentation (search for %f):
Sequence "%f" on the filter command line is replaced with the name of the file the filter is working on. A filter might use this in keyword substitution. For example:
[filter "p4"] clean = git-p4-filter --clean %f smudge = git-p4-filter --smudge %f
Hence, to get the path name of the file, you would need to set, e.g., filter.codeformat.clean to codeformat %f.
At this point you will also need to modify your bash script, since its syntax for argument substitution is indeed $1. However, read the immediate next paragraph from the gitattributes documentation:
Note that "%f" is the name of the path that is being worked on. Depending on the version that is being filtered, the corresponding file on disk may not exist, or may have different contents. So, smudge and clean commands should not try to access the file on disk, but only act as filters on the content provided to them on standard input.
The emphasis here is mine, but this is telling you that you cannot simply open the disk file and read it. You must filter only the standard input, providing standard output.
(As it turns out, clang-format is designed to do just that. Diff, however, is not.)
Edit to add working example:
$ cat ~/scripts/dotest
#! /bin/sh
echo "dotest run with $# arguments:" >>/tmp/dotest_log
for i do
printf '%s\n' "$i"
done >>/tmp/dotest_log
cat
$ which dotest
[path edited]/scripts/dotest
$ cat .git/config
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
[filter "testfilter"]
clean = dotest %f
smudge = dotest %f
$ cat .gitattributes
*.test filter=testfilter
$ echo 'bar.test' > bar.test
$ git add bar.test
$ cat /tmp/dotest_log
dotest run with 1 arguments:
bar.test
回答2:
%f is interpreted by git and should be in gitconfig. In the shell script use $1:
git config --global filter.codeformat.clean 'codeformat %f'
git config --global filter.codeformat.smudge 'codeformat %f'
#! /bin/bash
clang-format -style=file $1 | diff $1 -**
if [ $? -ne 0 ]; then
echo "ERROR: codeformat not correct"
exit 1
fi
回答3:
that means, i can never get file name?, i tried %f with git config itself and changed script to use $1, still it doesn't get filename.
cat ~/.gitconfig
[filter "codeformat"]
clean = codeformat %f
smudge = codeformat %f
cat .gitattributes
#clang code style format
*.cpp filter=codeformat
cat codeformat
#! /bin/bash
clang-format -i -style=file $1 -
echo "file/path accessed is _____ $1 ____" > log_output 2>&1
git add src/sample.cpp
cat log_output
file/path accessed is _____ ____
same command(below) if i run on command line works well,
clang-format -i -style=file src/sample.cpp
With git add it cannot get filename and hence other error with error: cannot use -i when reading from stdin.
note this time, i removed diff command, used -i to replace source file directly"
来源:https://stackoverflow.com/questions/46856372/git-attribute-using-filter-smudge-clean-to-process-cpp-files-through-shell-scri