Prevent pushes to git containing tabs in certain files (e.g. *.cpp, *.h, CMakeLists.txt)

二次信任 提交于 2019-12-02 20:39:10
Cascabel

Uh oh, this question seems to have slipped through the cracks. Hope you're still out there, Esben!

You're looking for an update hook, which is run once for each ref updated. The arguments are the name of the ref, the old object name (commit SHA1), and the new object name.

So, all you really need to do is check the diff between the old and new and make sure it meets your standards. This isn't totally straightforward, of course, but it's totally manageable. Here's what I'd do:

Save the following script to .git/hooks/update.

old=$2
new=$3

# that's a literal tab, because (ba)sh turns \t into t, not a tab
# make sure your editor doesn't expand it to spaces
git diff --name-only $old $new | egrep '(\.(cpp|h)$)|^CMakeLists.txt$' | xargs -d'\n' git diff -U0 $old $new -- | grep -q '^+.* ' && exit 1

That lists all the files which differ between the old and new, greps for all the desired ones, gets the diff for them (with zero lines of context, since we don't care), and greps for an added line (starting with +) containing a tab. The grep exits success if it finds one, which will let the && run exit 1, causing the hook to exit failure and abort the update!

Note that this is slightly different from your requirements - it checks if the diff adds any tab characters. This is probably better in the long run; once you've made sure your existing code's okay, it's the same thing, except much faster since it doesn't have to search all the content.

VonC

You could setup a pre-push hook, but this is not really in the spirit of the git publication mechanism.

I would rather go with:

  • a pre-commit hook, preventing any commit with the wrong content
  • or a filter driver that you can easily associate with the right types of file, and which can fix or report any improper content.

Based on benprew's work, here's a pre-script hook that displays an error if any tab characters have been added, as well as the relevant line number. Save the following to .git/hooks/pre-commit.

(Note: pre-commit is the filename. There shouldn't be any . extension)

#!/bin/sh

if git rev-parse --verify HEAD 2>/dev/null
then
  git diff-index -p -M --cached HEAD
else
    :
fi |
perl -e '
    my $found_bad = 0;
    my $filename;
    my $reported_filename = "";
    my $lineno;
    sub bad_line {
        my ($why, $line) = @_;
        if (!$found_bad) {
            print STDERR "*\n";
            print STDERR "* You have some suspicious patch lines:\n";
            print STDERR "*\n";
            $found_bad = 1;
        }
        if ($reported_filename ne $filename) {
            print STDERR "* In $filename\n";
            $reported_filename = $filename;
        }
        print STDERR "* $why (line $lineno)\n";
        print STDERR "$filename:$lineno:$line\n";
    }
    while (<>) {
        if (m|^diff --git a/(.*) b/\1$|) {
            $filename = $1;
            next;
        }
        if (/^@@ -\S+ \+(\d+)/) {
            $lineno = $1 - 1;
            next;
        }
        if (/^ /) {
            $lineno++;
            next;
        }
        if (s/^\+//) {
            $lineno++;
            chomp;
            if (/   /) {
                bad_line("TAB character", $_);
            }
        }
    }
    exit($found_bad);
'

It's not exactly what you asked for since it doesn't do any filename checking, but hopefully it helps regardless.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!