[PATCH] Add support for a 'pre-push' hook

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <askeolsson@xxxxxxxxx>
---
 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 a
branch 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 associated
with 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, const
char *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, const
char *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
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]