Можете ли вы изменить содержимое файла во время git commit?

Одна из вещей, которые я сохраняю в своем открывшемся романе список слов Я хотел бы автоматически установить первую строку, которая представляет собой число слов в словаре. Мой первый вариант - написать крюк предварительной фиксации, который читает файл, подсчитывает слова, переписывает первую строку и записывает ее снова. Здесь код

PRE_COMMIT {
  my ($git) = @_;
  my $branch =  $git->command(qw/rev-parse --abbrev-ref HEAD/);
  say "Pre-commit hook in $branch";
  if ( $branch =~ /master/ ) {
     my $changed = $git->command(qw/show --name-status/);
     my @changed_files = ($changed =~ /\s\w\s+(\S+)/g);
     if ( $words ~~ @changed_files ) {
       my @words_content = read_file( $words );
       say "I have $#words_content words";
       $words_content[0] = "$#words_content\n";
       write_file( $words, @words_content );
     }
   }
};

Однако, поскольку файл уже поставлен, я получаю эту ошибку

Ошибка: ваши локальные изменения в следующие файлы будут перезаписаны по кассе:   текст /words.dic Пожалуйста, сделайте свои изменения или запишите их прежде чем вы сможете переключаться между ветвями. Aborting

Может быть, лучше сделать это как крюк после фиксации и изменить его для следующего коммита? Или вообще что-то совершенно другое? Общий вопрос: если вы хотите обработать и изменить содержимое файла во время фиксации, каков его правильный способ?

Ответы

Ответ 1

Фактическая фиксация, заключенная в git commit, - это то, что находится в индексе после завершения завершения фиксации. Это означает, что вы можете изменять файлы в крюке предварительной фиксации, если вы тоже git add.

Здесь мой пример pre-commit hook, измененный из .sample:

#!/bin/sh
#
# An example hook script to verify what is about to be committed.
# [snipped much of what used to be in it, added this --
#  make sure you take out the exec of git diff-index!]

num=$(cat zorg)
num=$(expr 0$num + 1)
echo $num > zorg
git add zorg
echo "updated zorg to $num"
exit 0

а затем:

$ git commit -m dink
updated zorg to 3
[master 76eeefc] dink
 1 file changed, 1 insertion(+), 1 deletion(-)

Но обратите внимание на незначительный недостаток (не относится к вашему делу):

$ git commit
git commit
updated zorg to 4
# On branch master
# Untracked files:
[snip]
nothing added to commit but untracked files present (use "git add" to track)
$ git commit
updated zorg to 5
# Please enter the commit message for your changes. Lines starting
[snip - I quit editor without changing anything]
Aborting commit due to empty commit message.
$ git commit
updated zorg to 6
# Please enter the commit message for your changes. Lines starting

В основном, поскольку обновления привязки до фиксации и git add s, файл продолжает увеличиваться, даже если я на самом деле не выполняю фиксацию здесь.

Ответ 2

Оказывается, вы можете запускать "hooks" - они фактически обрабатываются другим mecanism - при создании файлов (в git add время):

https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#_keyword_expansion

(прокрутите немного вниз до диаграммы "smudge/clean" )

Вот что я понял:

  • отредактируйте .gitattributes и создайте правила для файлов, которые должны запускать обновление словаря:

    novel.txt updateDict

  • Затем скажите Git, что фильтр "updateDict" делает на smudge (git checkout) и clean (git add):

    $ git config --global filter.updateDict.clean countWords.script

    $ git config --global filter.updateDict.smudge cat