git attribute using filter smudge/clean to process .cpp files through shell script not finding filename

ぐ巨炮叔叔 提交于 2019-12-08 09:39:23

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!