[PATCH] Add support for a 'pre-push' hook
From: Aske Olsson <hidden>
Date: 2016-06-15 22:55:18
Subsystem:
documentation, the rest · Maintainers:
Jonathan Corbet, Linus Torvalds
If the script .git/hooks/pre-push exists and is executable it will be called before a `git push` command, and when the script exits with a non-zero status the push will be aborted. The hook can be overridden by passing the '--no-verify' option to `git push`. The pre-push hook is usefull to run tests etc. before push. Or to make sure that if a binary solution like git-media, git-annex or git-bin is used the binaries are uploaded before the push, so when others do a fetch the binaries will be available already. This also reduces the need for introducing extra (git) commands to e.g. sync binaries. Signed-off-by: Aske Olsson <redacted> --- Documentation/git-push.txt | 11 +++- Documentation/githooks.txt | 12 +++++ builtin/push.c | 6 +++ t/t5542-pre-push-hook.sh | 132 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 t/t5542-pre-push-hook.sh
diff --git a/Documentation/git-push.txt b/Documentation/git-push.txt
index fe46c42..5807b6a 100644
--- a/Documentation/git-push.txt
+++ b/Documentation/git-push.txt@@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git push' [--all | --mirror | --tags] [-n | --dry-run]
[--receive-pack=<git-receive-pack>]
[--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]
[-u | --set-upstream]
- [<repository> [<refspec>...]]
+ [ --no-verify] [<repository> [<refspec>...]]
DESCRIPTION
-----------@@ -157,6 +157,10 @@ useful if you write an alias or script around 'git push'. receiver share many of the same objects in common. The default is \--thin. +--no-verify:: + This option bypasses the pre-push hook. + See also linkgit:githooks[5]. + -q:: --quiet:: Suppress all output, including the listing of updated refs,
@@ -430,6 +434,11 @@ Commits A and B would no longer belong to abranch with a symbolic name, and so would be unreachable. As such, these commits would be removed by a `git gc` command on the origin repository. +HOOKS +----- +This command can run the `pre-push` hook. See linkgit:githooks[5] for +more information. + GIT --- Part of the linkgit:git[1] suite
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index b9003fe..847e0f8 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt@@ -176,6 +176,18 @@ save and restore any form of metadata associatedwith the working tree (eg: permissions/ownership, ACLS, etc). See contrib/hooks/setgitperms.perl for an example of how to do this. +[[pre-push]] +pre-push +~~~~~~~~ + +This hook is invoked by 'git push' and can be bypassed with the +`--no-verify` option. It takes no parameter, and is invoked before +the push happens. +Exiting with a non-zero status from this script causes 'git push' +to abort. + + + [[pre-receive]] pre-receive ~~~~~~~~~~~
diff --git a/builtin/push.c b/builtin/push.c
index db9ba30..9c4d2ec 100644
--- a/builtin/push.c
+++ b/builtin/push.c@@ -16,6 +16,7 @@ static const char * const push_usage[] = { }; static int thin; +static int no_verify; static int deleterefs; static const char *receivepack; static int verbosity;
@@ -392,6 +393,7 @@ int cmd_push(int argc, const char **argv, constchar *prefix)
N_("control recursive pushing of submodules"),
PARSE_OPT_OPTARG, option_parse_recurse_submodules },
OPT_BOOLEAN( 0 , "thin", &thin, N_("use thin pack")),
+ OPT_BOOLEAN('0', "no-verify", &no_verify, "bypass pre-push hook"),
OPT_STRING( 0 , "receive-pack", &receivepack, "receive-pack",
N_("receive pack program")),
OPT_STRING( 0 , "exec", &receivepack, "receive-pack", N_("receive
pack program")),
OPT_BIT('u', "set-upstream", &flags, N_("set upstream for git pull/status"),@@ -419,6 +421,10 @@ int cmd_push(int argc, const char **argv, constchar *prefix)
set_refspecs(argv + 1, argc - 1);
}
+ if (!no_verify && run_hook(NULL, "pre-push")) {
+ die(_("pre-push hook failed: exiting\n"));
+ }
+
rc = do_push(repo, flags);
if (rc == -1)
usage_with_options(push_usage, options);diff --git a/t/t5542-pre-push-hook.sh b/t/t5542-pre-push-hook.sh
new file mode 100644
index 0000000..842aa23
--- /dev/null
+++ b/t/t5542-pre-push-hook.sh@@ -0,0 +1,132 @@ +#!/bin/sh + +test_description='pre-push hook' + +. ./test-lib.sh + +D=`pwd` +HOOK="master/.git/hooks/pre-push" + +# Repo pair +mk_repo_pair () { + rm -rf master mirror && + mkdir mirror && + ( + cd mirror && + git init && + git config receive.denyCurrentBranch warn + ) + mkdir master && + ( + cd master && + git init && + git remote add $1 up ../mirror + ) +} + +# hook that always succeeds +mk_hook_exec () { +cat > "$HOOK" <<EOF +#!/bin/sh +exit 0 +EOF +chmod +x "$HOOK" +} + +# hook that fails +mk_hook_fail () { +cat > "$HOOK" <<EOF +#!/bin/sh +exit 1 +EOF +chmod +x "$HOOK" +} + +# nonexecutable hook +mk_hook_no_exec () { +rm -f "$HOOK" +cat > "$HOOK" <<EOF +#!/bin/sh +echo 'test run' +exit 0 +EOF +} + +test_expect_success 'push with no pre-push hook' ' + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) +' + +test_expect_success 'push --no-verify with no pre-push hook' ' + mk_repo_pair && + ( + cd master && + echo one >foo && git add foo && git commit -m one && + git push --no-verify --mirror up + ) +' + +test_expect_success 'push with succeeding pre-push hook' ' + mk_repo_pair && + ( + mk_hook_exec && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) +' + +test_expect_success 'push --no-verify with succeeding pre-push hook' ' + mk_repo_pair && + ( + mk_hook_exec && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --no-verify --mirror up + ) +' + +test_expect_success 'push with failing pre-push hook' ' + mk_repo_pair && + ( + mk_hook_fail && + cd master && + echo one >foo && git add foo && git commit -m one && + test_must_fail git push --mirror up + ) +' + +test_expect_success 'push --no-verify with failing hook' ' + mk_repo_pair && + ( + mk_hook_fail && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --no-verify --mirror up + ) +' + +test_expect_success 'push with non-executable pre-push hook' ' + mk_repo_pair && + ( + mk_hook_no_exec && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --mirror up + ) +' + +test_expect_success 'push --no-verify with non-executable pre-push hook' ' + mk_repo_pair && + ( + mk_hook_no_exec && + cd master && + echo one >foo && git add foo && git commit -m one && + git push --no-verify --mirror up + ) +' +test_done --
1.8.0