测试将在预提交挂钩中提交的内容

pwa*_*ler 14 git pre-commit pre-commit-hook githooks git-index

互联网上充斥着对这个问题的不正确和不理想的答案.这是不幸的,因为你会认为这将是你想做的常见事情.

问题:当pre-commit钩子运行时,存储库可能不干净.因此,如果你天真地进行测试,他们就不会反对你提交的内容,而是你的工作树中发生的任何污垢.

最明显的事情是git stash --keep-index --include-untracked在的开始pre-commit,并git pop在出口处.这样你就可以测试(纯)索引,这就是我们想要的.

不幸的是,如果你使用它git add --patch,会生成合并冲突标记(特别是如果你编辑了),因为stash@{0}提交后内容可能与工作树不匹配.

另一个常见的解决方案是克隆存储库并在新的临时存储库中运行测试.这有两个问题:一个是我们还没有提交,所以我们不能轻易地获得我们即将提交的状态的存储库副本(我确信有一种方法可以做到这一点) ,但我不感兴趣,因为:).其次,我的测试可能对当前工作目录的位置敏感.例如,由于本地环境配置.

那么:如何在git stash --keep-index --include-untracked不引入合并冲突标记的情况下将我的工作树恢复到它所处的状态,并且不修改提交后的内容HEAD

Gar*_*rwe 5

git write-tree在钩子中很有用pre-commit。它将一棵树写入索引的存储库(如果提交完成,该树将被重用)。

将树写入存储库后,您可以使用git archive | tar -x将树写入临时目录。

例如:

#!/bin/bash

TMPDIR=$(mktemp -d)
TREE=$(git write-tree)
git archive $TREE | tar -x -C $TMPDIR

# Run tests in $TMPDIR

RESULT=$?
rm -rf "$TMPDIR"
exit $RESULT
Run Code Online (Sandbox Code Playgroud)


Wil*_*ell 2

如果克隆整个存储库的成本太高,也许您只需要工作目录的副本。制作副本比尝试处理冲突更简单。例如:

#!/bin/sh -e

trap 'rm -rf $TMPD' 0
mkdir ${TMPD=$PWD/.tmpdir}
git ls-tree -r HEAD | while read mod type sha name; do
    if test "$type" = blob; then
        mkdir -p $TMPD/$( dirname "$name" ) 
        git show $sha > $TMPD/"$name";
        chmod $mod $TMPD/"$name"
    fi
done
cd $TMPD
git diff --cached HEAD | patch
# Run tests here
Run Code Online (Sandbox Code Playgroud)

这将转储树的状态,因为它将在 $TMPD 中提交后,因此您可以在那里运行测试。您应该以比此处更安全的方式获取临时目录,但为了使最终的 diff 能够工作(或者更早地简化脚本和 cd),它必须是工作目录的子目录。