2010-03-09 2 views
48

Я пишу крюк предварительной фиксации. Я хочу запустить php -l против всех файлов с расширением .php. Однако я застрял.Git pre-commit hook: изменено/добавлено файлы

Мне нужно получить список новых/измененных файлов, которые поставлены. удаленные файлы должны быть исключены.

Я пробовал использовать git diff и git ls-files, но я думаю, что мне нужна рука здесь.

+0

http://phpadvent.org/2008/dont-commit-that-error-by-travis-swicegood – Maerlyn

+0

Это довольно хорошо. Однако он не обрабатывает частично поставленные файлы. См. Мой комментарий к ответу @ LarryH. – igorw

ответ

31

git diff --cached --name-status покажет сводку того, что поставил, так что вы можете легко исключить удаленные файлы, например:

M  wt-status.c 
D  wt-status.h 

Это указывает на то, что вес-status.c был модифицирован и вес-status.h был удален в (индекс). Таким образом, чтобы проверять только файлы, которые не были удалены:

[email protected]:~/src/git <master>$ git diff --cached --name-status | awk '$1 != "D" { print $2 }' 
wt-status.c 
wt-status.h 

Вам придется прыгать через дополнительные обручи, чтобы иметь дело с именами файлов с пробелами в хотя (-z, мерзавец различий и некоторые более интересный разбора)

+0

Спасибо, это хорошее начало.Однако, если я изменяю файл без его создания, он все равно отображается. Я запускаю git версию 1.7.0.1.147.g6d84b (недавняя пользовательская сборка). Не уверен, что это предполагаемое поведение. – igorw

+0

Звучит странно. Переключатель «--cached» должен сделать только показ файлов, которые были поставлены: хотя я тестирую это с 1.6.5, кажется удивительным, что это изменилось бы ... «git diff --cached» на его собственные показывают неустановленные изменения? – araqnid

+0

После некоторой отладки я смог отследить ее по другой причине. Большое спасибо! – igorw

70

немного аккуратнее способ получения такой же список является:

git diff --cached --name-only --diff-filter=ACM 

Это возвращает список файлов, которые должны быть проверены.

Но просто работающий php -l на вашей рабочей копии может оказаться неправильной. Если вы выполняете частичную фиксацию, то есть просто выбираете подмножество различий между вашим текущим рабочим набором и HEAD для фиксации, тогда тест будет выполняться на вашем рабочем наборе, но будет удостоверять фиксацию, которая никогда не существовала на вашем диск.

Чтобы сделать это правильно, вы должны извлечь все поэтапное изображение в область темпа и выполнить там тест.

rm -rf $TEMPDIR 
mkdir -p $TEMPDIR 
git checkout-index --prefix=$TEMPDIR/ -af 
git diff --cached --name-only --diff-filter=ACM | xargs -n 1 -I '{}' \bin\echo TEMPDIR/'{}' | grep \\.php | xargs -n 1 php -l 

См. Building a better pre-commit hook for Git для другой реализации.

+4

Фактически можно передать содержимое файла в 'php -l'. И это то, с чем мы закончили. См. Здесь: http://github.com/phpbb/phpbb3/blob/develop-olympus/git-tools/hooks/pre-commit – igorw

+2

Чтобы проверить синтаксис поэтапного файла, вы можете использовать 'git show: FILENAME | php -l'. –

7

Вот что я использую для моих Perl проверки:

git diff --cached --name-status | while read st file; do 
     # skip deleted files 
     if [ "$st" == 'D' ]; then continue; fi 
     # do a check only on the perl files 
     if [[ "$file" =~ "(.pm|.pl)$" ]] && ! perl -c "$file"; then 
       echo "Perl syntax check failed for file: $file" 
       exit 1 
     fi 
done 

для PHP это будет выглядеть следующим образом:

git diff --cached --name-status | while read st file; do 
     # skip deleted files 
     if [ "$st" == 'D' ]; then continue; fi 
     # do a check only on the php files 
     if [[ "$file" =~ ".php$" ]] && ! php -l "$file"; then 
       echo "PHP syntax check failed for file: $file" 
       exit 1 
     fi 
done 
+2

Довольно хорошо, но не работает для частично поставленных файлов, потому что он читает весь файл. – igorw

0

мерзавец дифф --cached не является достаточным, если был указан вызов фиксации с флагом -a, и нет способа определить, был ли этот флаг вставлен в крючок. Это поможет, если аргументы для фиксации должны быть доступны для проверки на крючок.

+0

git diff --cached DOES представляется достаточным. Однако, я считаю, что если вы запустите git status --porcelain внутри вашего крючка, все файлы, которые будут обработаны, не будут иметь пробел или? в первой позиции выхода. Я не тестировал его полностью, но до сих пор он поддерживал все условия, которые у меня есть в моем репо, сочетание новых, добавленных, измененных файлов, где я пытаюсь передать явные файлы, набор файлов по умолчанию, а для всего. Так зачем использовать git status вместо git diff? Я думаю, что легче разобрать. – mpersico

+0

'git status --porcelain | grep -E -v '^ [? ] '' – mpersico

+0

' git status --porcelain | perl -ane 'print $ F [1], qq (\ n), если m/^ [ACM] /' ' - лучший ответ. У этого есть преимущество использования опции --porcelain, которая никогда не изменится. Используйте собственный синтаксический анализатор, если perl слишком тяжелый для вас. – mpersico

7

Ни один из ответов здесь не поддерживает имена файлов с пробелами. Лучший способ для этого, чтобы добавить -z флаг в сочетании с xargs -0

git diff --cached --name-only --diff-filter=ACM -z | xargs -0 ... 

Это то, что дается мерзавца во встроенном в образцах (см .git/крюки/пре-commit.sample)

 Смежные вопросы

  • Нет связанных вопросов^_^