34

我在 GitHub 上的公开小说中保留的内容之一是我想自动设置第一行的单词列表,即字典中的单词数。我的第一个选择是编写一个预提交挂钩来读取文件、计算单词、重写第一行并再次写回。这是代码

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 );
     }
   }
};

但是,由于文件已经暂存,我收到此错误

错误:您对以下文件的本地更改将被结帐覆盖:text/words.dic 请在切换分支之前提交您的更改或存储它们。中止

将其作为提交后挂钩并为下一次提交进行更改可能会更好吗?或者做一些完全不同的事情?一般的问题是:如果您想在提交期间处理和更改文件的内容,那么正确的做法是什么?

4

2 回答 2

32

git commit一旦预提交挂钩完成,实际的提交就是索引中的任何内容。这意味着您可以更改预提交挂钩中的文件,只要您git add也可以。

这是我的示例预提交挂钩,从 .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

基本上,因为 pre-commit 钩子更新和git adds,即使我实际上并没有在这里执行提交,文件也会不断增加。

[ 2021 年 8 月编辑:我需要强调的是,我推荐这种方法。git commit -a请注意,使用,git commit --include和时可能会出现一些奇怪的情况,包括在命令行上命名文件时插入git commit --only的隐含情况。--only这是因为这种git commit创建了第二个,有时甚至是第三个内部 Git 索引。您在挂钩内执行的任何git add操作都只能影响两个或三个索引文件之一。]

于 2013-05-30T09:41:10.090 回答
17

事实证明,您可以运行“挂钩”——它们实际上是由另一种机制处理的——在暂存文件时(git add有时):

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

(向下滚动到“涂抹”和“清洁”图表)

这是我的理解:

  1. 编辑.gitattributes, 并为应该触发字典更新的文件创建规则:

    novel.txt filter=updateDict

  2. 然后,告诉 GitupdateDict过滤器在涂抹(git checkout) 和清洁(git add) 上做了什么:

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

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

于 2013-06-28T08:34:54.460 回答