访问git预接收挂钩中更改的文件路径

访问git预接收挂钩中更改的文件路径,git,githooks,git-remote,Git,Githooks,Git Remote,我正在远程回购上编写一个git预接收钩子,以确保推送的代码符合我们公司的内部准则 我能够找到在启动预接收挂钩时要检查的所有文件,但是,我没有使用正常文件操作打开这些文件的路径(例如,cat git\u working\u directory/file\u name将抛出没有这样的文件或目录错误)验证代码的应用程序需要文件路径作为参数,以便打开文件并运行检查 考虑这个场景:开发人员创建了一个新文件并将其推送到服务器,预接收挂钩被触发。在此阶段,新文件不会保存到远程服务器的工作目录中,因为预接收挂钩

我正在远程回购上编写一个git预接收钩子,以确保推送的代码符合我们公司的内部准则

我能够找到在启动预接收挂钩时要检查的所有文件,但是,我没有使用正常文件操作打开这些文件的路径(例如,
cat git\u working\u directory/file\u name
将抛出
没有这样的文件或目录
错误)验证代码的应用程序需要文件路径作为参数,以便打开文件并运行检查

考虑这个场景:开发人员创建了一个新文件并将其推送到服务器,预接收挂钩被触发。在此阶段,新文件不会保存到远程服务器的工作目录中,因为预接收挂钩仍在运行

我想知道是否有一个临时位置,文件在推送后立即保存在git中,以便我可以将该目录传递给应用程序以运行检查

更新:


我可以到一个临时地点结账并在那里进行检查,这可能是一个选项,但考虑到开发商经常推动,有时甚至是在同一时间,而且回购规模很大,这个选项似乎不可行。我正在寻找一种解决方案,如果文件路径可用,我可以直接使用它。

您可能需要编写
pre-receive
钩子,将文件签出到临时位置。通常,这意味着您将
git克隆到一个临时目录中,然后签出特定的提交并运行检查。例如,类似于:

#!/bin/sh

REPO=$PWD

check_files_in () {
  rev=$1

  # create a temporary working directory
  workdir=$(mktemp -d gitXXXXXX)
  (
    # arrange to clean up the workding directory
    # when the subshell exits
    trap "cd /; rm -rf $workdir" EXIT

    # unset GIT_DIR because it would confuse things
    unset GIT_DIR

    # clone the repository
    cd $workdir
    git clone $REPO check

    # checkout the specific revision we're checking
    cd check
    git checkout $rev

    # perform some sort of validation.  The exit code of this 
    # command will be the exit code of this function, so
    # returning an error will reject the push.
    run-validation-scripts
  )
}

while read oldrev newrev refname; do
  check_files_in $newrev || exit 1
done
我想知道是否有一个临时位置,文件在推送后立即保存在git中,以便我可以将该目录传递给应用程序以运行检查

不,没有这样的地方。这些文件存储为blob,可以简化为delta和/或压缩,因此不能保证它们在“准备使用”状态下的任何位置都可用

检查标准的应用程序需要文件路径作为参数,以便打开文件并运行其检查

如果您使用的是linux,您可以将
/dev/stdin
作为输入文件,并将这些文件通过管道

#/垃圾箱/垃圾箱
读取oldrev newrev refname时;做
git diff——读取文件时仅命名$oldrev$newrev |;做
git show$newrev:$file | validate/dev/stdin | |退出1
完成
完成

推送的文件保存在永久位置,即存储库中的git对象。提取它们的一种方法是使用

#/usr/bin/perl-T
严格使用;
使用警告;
#替换为实际检查程序和可选参数
我的@CHECK_程序=qw/ls-la/;
#我的@CHECK_程序=qw/false/;
使用文件::Temp qw/tempdir/;
$ENV{PATH}=“/bin:/usr/bin”;
而(){
#SP LF
我的($oldsha,$newsha,$refname)=/\A([^]+)([^]+)([^]+)\x0A\z/;
模具“$0:意外输入:$\”,除非定义了$refname;
my$tmp=tempdir“prerecv-$-XXXXXX”,DIR=>“/tmp”,CLEANUP=>1;
系统(qq{git存档--格式=tar$newsha | tar-C“$tmp”-x})=0
或死亡“$0:git存档$newsha失败”;
系统(@CHECK_PROGRAM,$tmp)==0或死“$0:检查失败”;
}
因为代码代表另一个用户运行,所以它使用
-T
开关启用Perl的安全特性


请注意,您的检查程序将看到整个树被推送,而不知道哪些文件已更改。如果检查器还需要有关增量的信息,请调查并可能调查其
--diff filter
选项。

要跟进joozek的回答,如果需要检查oldrev何时为全零(您正在推送一个新分支),您仍然可以通过向joozek的解决方案添加以下内容来读取新提交:

#/垃圾箱/垃圾箱
z40=0000000000000000000000000000
读取oldrev newrev refname时;做
如果[$oldrev==$z40];然后
#正在推送的提交用于新分支
oldrev=4B825DC642CB6EB9A060E54BF8D6928FBEE4904
fi
git diff——读取文件时仅命名$oldrev$newrev |;做
git show$newrev:$file | validate/dev/stdin | |退出1
完成
完成
散列“4b825dc642cb6eb9a060e54bf8d69288fbee4904”是git的空树对象,它具有差异可比性(不包括所有零)。这样,您将能够检查推送到新分支的所有对象


虽然这个空对象散列很有用,但在使用它时要小心。如果要推送的提交/分支很大,则计算成本可能会很高,因为您正在检查中的每个对象。

远程回购不应该有一个工作目录。您需要将文件签出到一个临时工作目录中,并在那里运行您的检查。@larsks是否有一个git命令,我可以运行它将这些文件签入临时目录?只是澄清一下:您签入存储库的文件不保存在那里“就这样”。它们中的一些以增量形式存储到另一些,或者它们的内容被压缩。我的理解是,没有任何地方可以保证这些文件存在于“准备消费”状态中。我只是想知道git是如何存储文件以及如何访问这些文件的,我是否遗漏了什么。谢谢。看起来这是一个可行的选择,我会尽量让你们知道。现在我想了想,我意识到这需要一个工作副本(不应该出现在服务器上)。我将在一分钟内更新我的答案,以便直接从repo@SriVishnuTotakura我编辑了我的答案,删除了WC存在的要求。检查一下,虽然它能工作,但我认为,当某个时候发生多个推送时,我仍然会有问题。@SriVishnuTotakura你不应该有任何问题。git show以所需的版本(没有任何临时文件)输出您的文件,并且版本本身是不可变的,因此