Атрибут git с использованием фильтра smudge/clean для обработки файлов.cpp с помощью сценария оболочки, который не находит имя файла

Я хотел настроить форматирование кода для всех файлов.cpp до того, как они будут переданы в git.

Для этого я создал небольшой скрипт (с именем codeformat) (также попытался заменить%f на $1)

#! /bin/bash
clang-format -style=file %f | diff %f -**
if [ $? -ne 0 ]; then
   echo "ERROR: codeformat not correct"
   exit 1
fi

установил git config и обновил.gitattributes с помощью *.cpp filter=codeformat,

git config --global filter.codeformat.clean codeformat
git config --global filter.codeformat.smudge codeformat

похоже, что скрипт запускается, но не получает имя файла. Почему это?

3 ответа

Решение

У тебя есть %f директива не в том месте.

Как показано в документации по gitattributes (найдите %f):

Последовательность "%f" в командной строке фильтра заменяется именем файла, над которым работает фильтр. Фильтр может использовать это в подстановке ключевых слов. Например:

[filter "p4"]
        clean = git-p4-filter --clean %f
        smudge = git-p4-filter --smudge %f

Следовательно, чтобы получить путь к файлу, вам нужно установить, например, filter.codeformat.clean в codeformat %f,

На этом этапе вам также потребуется изменить скрипт bash, поскольку его синтаксис для подстановки аргументов действительно $1, Тем не менее, прочитайте следующий абзац из документации по gitattributes:

Обратите внимание, что "%f" - это имя пути, над которым вы работаете. В зависимости от фильтруемой версии, соответствующий файл на диске может не существовать или иметь различное содержимое. Таким образом, команды smudge и clean не должны пытаться получить доступ к файлу на диске, а действуют только как фильтры для содержимого, предоставленного им при стандартном вводе.

Акцент здесь мой, но это говорит о том, что вы не можете просто открыть файл на диске и прочитать его. Вы должны фильтровать только стандартный ввод, обеспечивая стандартный вывод.

( Как выясняется, формат clang предназначен именно для этого. Различия, однако, нет.)


Изменить, чтобы добавить рабочий пример:

$ 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

%f интерпретируется git и должен быть в gitconfig, В сценарии оболочки используйте $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

Это означает, что я никогда не могу получить имя файла?, я попробовал%f с самим git config и изменил скрипт на использование $1, но он не получает имя файла.

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 _____  ____

та же команда (ниже), если я запускаю в командной строке, работает хорошо,

clang-format -i -style=file src/sample.cpp

С git add он не может получить имя файла и, следовательно, другую ошибку с ошибкой: не может использовать -i при чтении из стандартного ввода.

на этот раз, я удалил команду diff, использовал -i для прямой замены исходного файла "

Другие вопросы по тегам