Git如何直接修改索引以进行预提交格式化挂钩?

7

我希望在将文件添加到Git索引之前自动进行格式化。目前,我有一个类似于以下内容的pre-commit hook:

#!/bin/bash

set -e
exec 1>&2

workingext="working.$$"
ext="bak.$$"
git diff -z --cached --name-only | egrep -z '\.(pl|pm|t)$' | \
        while read -d'' -r f; do
    # First modify the file in the index
    mv "$f" "$f.$workingext"
    git show :"$f" > "$f"
    perl -c "$f"
    perltidy -pbp -nst -b -bext="$ext" "$f";
    rm -f "$f.$ext"
    git add "$f"
    mv "$f.$workingext" "$f"
    # Then the working copy
    perl -c "$f"
    perltidy -pbp -nst -b -bext="$ext" "$f";
    rm -f "$f.$ext"
done

基本上,我会备份工作副本,检查索引副本,格式化它们,将它们添加到索引中,然后恢复工作副本并对其进行格式化,以便工作副本和索引副本之间的差异不会变得太大。我首先使用perl -c检查文件的语法,以使格式化工具perltidy不会被语法错误的文件搞糊涂。
到目前为止,这似乎运作得相当顺利。但是,我想知道是否有一种方法可以将一个文件的内容添加到以另一个文件的名称命名的索引中。也就是说,像git update-index-from-file --from-file foo.pl.tmp foo.pl这样的命令将更新文件foo.pl,使其在索引中的内容完全来自foo.pl.tmp,但其工作目录中的版本保持不变。这可能会避免我现在正在做的重命名操作(尽管这可能有助于确保我不会无法检索地丢失索引的内容)。
1个回答

16

可以的。首先,您需要通过运行以下命令从文件创建一个blob:

git hash-object -w foo.pl.tmp

请看这里:http://www.kernel.org/pub/software/scm/git/docs/git-hash-object.html

使用指定文件的内容(可以位于工作树之外)计算指定类型对象的对象ID值,并可选择将生成的对象写入对象数据库。该命令会将对象ID输出到标准输出。

使用 git hash-object 命令输出的 blob sha,您现在可以将此 blob 添加到索引中并命名为“foo.pl”,方法如下:

git update-index --add --cacheinfo 100644 *YOURSHA* foo.pl

来自 update-index手册

--cacheinfo用于注册当前工作目录中不存在的文件。这对于最小检出合并非常有用。

如果要假装你有一个路径为path、模式为mode、sha1值为sha1的文件,请执行以下操作:

$ git update-index --cacheinfo mode sha1 path
但我想指出,你的情况看起来更像应该使用涂抹过滤器来完成这些操作。请参阅此处了解有关它们的信息:https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#Keyword-Expansion

很棒的答案。让我整理了一下我的解决方案,用于类似(相同?)问题的解决(我给了信用:D)。现在它基本上成为了这个的编码版本。 - jarzec
清洁和模糊滤镜的问题在于,与预提交钩子不同,它不会被存储。每个使用者都有自己的 git config,因此每个检出代码的用户都需要重新配置过滤器。 - Eyal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接