简体   繁体   English

在git pre-receive hook中访问已更改的文件路径

[英]Access the changed files path in git pre-receive hook

I'm writing a git pre-receive hook on the remote repo to make sure pushed code is consistent with our company's internal guidelines. 我正在远程仓库上写一个git预接收挂钩,以确保推送的代码与我们公司的内部指南一致。

I'm able to find all the files that are to be checked when a pre-receive hook is fired, however, I don't have the path to these files to open them using normal file operations(eg cat git_working_directory/file_name would throw No such file or directory error). 我能够找到在触发预接收挂钩时要检查的所有文件,但是,我没有这些文件的路径来使用普通文件操作打开它们(例如cat git_working_directory/file_name会抛出No such file or directory错误)。 The application which validates the code requires the file path as an argument so that it can open the file and run its checks. 验证代码的应用程序需要将文件路径作为参数,以便它可以打开文件并运行其检查。

Consider this scenario: the developer created a new file and pushed it to the server and the pre-receive hook is triggered. 考虑这种情况:开发人员创建了一个新文件并将其推送到服务器并触发了预接收挂钩。 At this stage the new file is not saved on to the remote's working directory because the pre-receive hook is still running. 在此阶段,新文件未保存到远程工作目录,因为预接收挂钩仍在运行。

I'm wondering if there is a temporary location where the files are saved in git as soon as they are pushed so that I can pass that directory to the application to run the checks? 我想知道是否有一个临时位置,文件一旦被推送就保存在git中,以便我可以将该目录传递给应用程序来运行检查?

Update: 更新:

I could checkout to a temporary location and run the checks there, this could be an option but considering the fact that developers frequently push, sometimes even at the same time and the repo being very big, this option doesn't seem to be feasible. 我可以结账到临时位置并在那里运行检查,这可能是一个选项,但考虑到开发人员经常推动的事实,有时甚至在同一时间和回购非常大,这个选项似乎不可行。 I'm looking more for a solution where I can just use the path to the file if it is somehow available. 我正在寻找一个解决方案,我可以使用文件的路径,如果它以某种方式可用。

I'm wondering if there is a temporary location where the files are saved in git as soon as they are pushed so that I can pass that directory to the application to run the checks? 我想知道是否有一个临时位置,文件一旦被推送就保存在git中,以便我可以将该目录传递给应用程序来运行检查?

No, there is no such place. 不,没有这样的地方。 Those files are stored as blobs and can be reduced to deltas and/or compressed, so there's no guarantee they'll be available anywhere in 'ready-to-consume' state. 这些文件存储为blob,可以简化为增量和/或压缩,因此不能保证它们在“准备消费”状态下可用。

The application which checks for the standards requires the file path as an argument so that it can open the file and run its checks. 检查标准的应用程序需要将文件路径作为参数,以便它可以打开文件并运行其检查。

If you're on linux you could just point /dev/stdin as input file and put the files through pipe. 如果您使用的是Linux,则可以将/dev/stdin指向输入文件并将文件放入管道。

#!/bin/sh
while read oldrev newrev refname; do
 git diff --name-only $oldrev $newrev | while read file; do
   git show $newrev:$file | validate /dev/stdin || exit 1
     done
done

You would probably need to write pre-receive hook that checks out the files in a temporary location. 您可能需要编写pre-receive挂钩来检出临时位置的文件。 Generally, that means you would git clone the bare repository into a temporary directory, and then check out the specific commit and run your checks. 通常,这意味着您将git clone裸存储库到临时目录,然后检查特定的提交并运行您的检查。 For example, something like: 例如,类似于:

#!/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

The pushed files are saved in a permanent location, namely as git objects in the repository. 推送的文件保存在永久位置,即存储库中的git对象。 One way to extract them is using git archive . 提取它们的一种方法是使用git archive

#! /usr/bin/perl -T

use strict;
use warnings;

# replace with your real check program and optional arguments
my @CHECK_PROGRAM = qw/ ls -la /;
#my @CHECK_PROGRAM = qw/ false /;

use File::Temp qw/ tempdir /;

$ENV{PATH} = "/bin:/usr/bin";

while (<>) {
  # <old-value> SP <new-value> SP <ref-name> LF
  my($oldsha,$newsha,$refname) = /\A([^ ]+) ([^ ]+) ([^ ]+)\x0A\z/;
  die "$0: unexpected input: $_" unless defined $refname;

  my $tmp = tempdir "prerecv-$$-XXXXXX", DIR => "/tmp", CLEANUP => 1;

  system(qq{git archive --format=tar $newsha | tar -C "$tmp" -x}) == 0
    or die "$0: git-archive $newsha failed";

  system(@CHECK_PROGRAM, $tmp) == 0 or die "$0: check failed";
}

Because the code runs on behalf of another user, it enables Perl's taint mode security feature with the -T switch. 因为代码代表另一个用户运行,所以它使用-T开关启用Perl的污点模式安全功能。

Note that your check program will see the entire tree as pushed without knowledge of which files have changed. 请注意,您的检查程序将在不知道哪些文件已更改的情况下将整个树视为已推送。 If the checker requires information about the delta as well, investigate git diff-tree and possibly its --diff-filter option. 如果检查器也需要有关delta的信息,请调查git diff-tree以及可能的--diff-filter选项。

To follow up on joozek's answer, if you need to check for when oldrev is all zeroes (you are pushing a new branch), you can still read through the new commits by adding the following to joozek's solution: 要跟进joozek的回答,如果你需要检查oldrev是全零(你正在推动一个新的分支),你仍然可以通过在joozek的解决方案中添加以下内容来阅读新的提交:

#!/bin/sh
z40=0000000000000000000000000000000000000000
while read oldrev newrev refname; do

 if [ $oldrev == $z40 ]; then
   # Commit being pushed is for a new branch
   oldrev=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 fi
 git diff --name-only $oldrev $newrev | while read file; do
   git show $newrev:$file | validate /dev/stdin || exit 1
     done
done

The hash "4b825dc642cb6eb9a060e54bf8d69288fbee4904" is git's empty tree object, which is diff comparable (all zeroes is not). 散列“4b825dc642cb6eb9a060e54bf8d69288fbee4904”是git的空树对象,它是差异可比的(全部为零)。 This way you will be able to check all objects being pushed to the new branch. 这样,您就可以检查被推送到新分支的所有对象。

While this empty object hash is useful, be careful when using it. 虽然这个空对象哈希很有用,但在使用它时要小心。 It can get computationally expensive if the commit/branch being pushed is large, since you are checking every object within. 如果推送的提交/分支很大,它可能会计算成本很高,因为您正在检查其中的每个对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM