{"thread":{"id":"32129","subject":"[PATCH] Add support for a 'pre-push' hook","startedAt":"2012-11-16T19:42:59Z","lastAt":"2012-11-17T09:00:01Z","messageCount":7,"participants":["Aske Olsson","Matthieu Moy","Junio C Hamano","Michael Haggerty"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"203361","messageId":"CAJwKrPYwCE4ExmK09PURMfjYezn6vdCH_BBXU4WCwrnotyV9CA@mail.gmail.com","threadId":"32129","inReplyTo":null,"subject":"[PATCH] Add support for a 'pre-push' hook","fromName":"Aske Olsson","fromEmail":"askeolsson@gmail.com","sentAt":"2012-11-16T19:42:59Z","receivedAt":"2012-11-16T19:42:59Z","isPatch":true,"sender":{"key":"askeolsson@gmail.com","avatar":"https://avatars.githubusercontent.com/u/474194?v=4"},"body":"If the script .git/hooks/pre-push exists and is executable it will be\ncalled before a `git push` command, and when the script exits with a\nnon-zero status the push will be aborted.\nThe hook can be overridden by passing the '--no-verify' option to\n`git push`.\n\nThe pre-push hook is usefull to run tests etc. before push. Or to make\nsure that if a binary solution like git-media, git-annex or git-bin is\nused the binaries are uploaded before the push, so when others do a\nfetch the binaries will be available already. This also reduces the\nneed for introducing extra (git) commands to e.g. sync binaries.\n\nSigned-off-by: Aske Olsson <askeolsson@gmail.com>\n---\n Documentation/git-push.txt |  11 +++-\n Documentation/githooks.txt |  12 +++++\n builtin/push.c             |   6 +++\n t/t5542-pre-push-hook.sh   | 132 +++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 160 insertions(+), 1 deletion(-)\n create mode 100644 t/t5542-pre-push-hook.sh\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex fe46c42..5807b6a 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -11,7 +11,7 @@ SYNOPSIS\n [verse]\n 'git push' [--all | --mirror | --tags] [-n | --dry-run]\n[--receive-pack=<git-receive-pack>]\n    [--repo=<repository>] [-f | --force] [--prune] [-v | --verbose]\n[-u | --set-upstream]\n-   [<repository> [<refspec>...]]\n+   [ --no-verify] [<repository> [<refspec>...]]\n\n DESCRIPTION\n -----------\n@@ -157,6 +157,10 @@ useful if you write an alias or script around 'git push'.\n  receiver share many of the same objects in common. The default is\n  \\--thin.\n\n+--no-verify::\n+ This option bypasses the pre-push hook.\n+ See also linkgit:githooks[5].\n+\n -q::\n --quiet::\n  Suppress all output, including the listing of updated refs,\n@@ -430,6 +434,11 @@ Commits A and B would no longer belong to a\nbranch with a symbolic name,\n and so would be unreachable.  As such, these commits would be removed by\n a `git gc` command on the origin repository.\n\n+HOOKS\n+-----\n+This command can run the `pre-push` hook.  See linkgit:githooks[5] for\n+more information.\n+\n GIT\n ---\n Part of the linkgit:git[1] suite\ndiff --git a/Documentation/githooks.txt b/Documentation/githooks.txt\nindex b9003fe..847e0f8 100644\n--- a/Documentation/githooks.txt\n+++ b/Documentation/githooks.txt\n@@ -176,6 +176,18 @@ save and restore any form of metadata associated\nwith the working tree\n (eg: permissions/ownership, ACLS, etc).  See contrib/hooks/setgitperms.perl\n for an example of how to do this.\n\n+[[pre-push]]\n+pre-push\n+~~~~~~~~\n+\n+This hook is invoked by 'git push' and can be bypassed with the\n+`--no-verify` option. It takes no parameter, and is invoked before\n+the push happens.\n+Exiting with a non-zero status from this script causes 'git push'\n+to abort.\n+\n+\n+\n [[pre-receive]]\n pre-receive\n ~~~~~~~~~~~\ndiff --git a/builtin/push.c b/builtin/push.c\nindex db9ba30..9c4d2ec 100644\n--- a/builtin/push.c\n+++ b/builtin/push.c\n@@ -16,6 +16,7 @@ static const char * const push_usage[] = {\n };\n\n static int thin;\n+static int no_verify;\n static int deleterefs;\n static const char *receivepack;\n static int verbosity;\n@@ -392,6 +393,7 @@ int cmd_push(int argc, const char **argv, const\nchar *prefix)\n  N_(\"control recursive pushing of submodules\"),\n  PARSE_OPT_OPTARG, option_parse_recurse_submodules },\n  OPT_BOOLEAN( 0 , \"thin\", &thin, N_(\"use thin pack\")),\n+ OPT_BOOLEAN('0', \"no-verify\", &no_verify, \"bypass pre-push hook\"),\n  OPT_STRING( 0 , \"receive-pack\", &receivepack, \"receive-pack\",\nN_(\"receive pack program\")),\n  OPT_STRING( 0 , \"exec\", &receivepack, \"receive-pack\", N_(\"receive\npack program\")),\n  OPT_BIT('u', \"set-upstream\", &flags, N_(\"set upstream for git pull/status\"),\n@@ -419,6 +421,10 @@ int cmd_push(int argc, const char **argv, const\nchar *prefix)\n  set_refspecs(argv + 1, argc - 1);\n  }\n\n+ if (!no_verify && run_hook(NULL, \"pre-push\")) {\n+ die(_(\"pre-push hook failed: exiting\\n\"));\n+ }\n+\n  rc = do_push(repo, flags);\n  if (rc == -1)\n  usage_with_options(push_usage, options);\ndiff --git a/t/t5542-pre-push-hook.sh b/t/t5542-pre-push-hook.sh\nnew file mode 100644\nindex 0000000..842aa23\n--- /dev/null\n+++ b/t/t5542-pre-push-hook.sh\n@@ -0,0 +1,132 @@\n+#!/bin/sh\n+\n+test_description='pre-push hook'\n+\n+. ./test-lib.sh\n+\n+D=`pwd`\n+HOOK=\"master/.git/hooks/pre-push\"\n+\n+# Repo pair\n+mk_repo_pair () {\n+ rm -rf master mirror &&\n+ mkdir mirror &&\n+ (\n+ cd mirror &&\n+ git init &&\n+ git config receive.denyCurrentBranch warn\n+ )\n+ mkdir master &&\n+ (\n+ cd master &&\n+ git init &&\n+ git remote add $1 up ../mirror\n+ )\n+}\n+\n+# hook that always succeeds\n+mk_hook_exec () {\n+cat > \"$HOOK\" <<EOF\n+#!/bin/sh\n+exit 0\n+EOF\n+chmod +x \"$HOOK\"\n+}\n+\n+# hook that fails\n+mk_hook_fail () {\n+cat > \"$HOOK\" <<EOF\n+#!/bin/sh\n+exit 1\n+EOF\n+chmod +x \"$HOOK\"\n+}\n+\n+# nonexecutable hook\n+mk_hook_no_exec () {\n+rm -f \"$HOOK\"\n+cat > \"$HOOK\" <<EOF\n+#!/bin/sh\n+echo 'test run'\n+exit 0\n+EOF\n+}\n+\n+test_expect_success 'push with no pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --mirror up\n+ )\n+'\n+\n+test_expect_success 'push --no-verify with no pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --no-verify --mirror up\n+ )\n+'\n+\n+test_expect_success 'push with succeeding pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_exec &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --mirror up\n+ )\n+'\n+\n+test_expect_success 'push --no-verify with succeeding pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_exec &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --no-verify --mirror up\n+ )\n+'\n+\n+test_expect_success 'push with failing pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_fail &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ test_must_fail git push --mirror up\n+ )\n+'\n+\n+test_expect_success 'push --no-verify with failing hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_fail &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --no-verify --mirror up\n+ )\n+'\n+\n+test_expect_success 'push with non-executable pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_no_exec &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --mirror up\n+ )\n+'\n+\n+test_expect_success 'push --no-verify with non-executable pre-push hook' '\n+ mk_repo_pair &&\n+ (\n+ mk_hook_no_exec &&\n+ cd master &&\n+ echo one >foo && git add foo && git commit -m one &&\n+ git push --no-verify --mirror up\n+ )\n+'\n+test_done\n--\n1.8.0\n"},{"id":"203369","messageId":"vpq625547ne.fsf@grenoble-inp.fr","threadId":"32129","inReplyTo":"CAJwKrPYwCE4ExmK09PURMfjYezn6vdCH_BBXU4WCwrnotyV9CA@mail.gmail.com","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Matthieu Moy","fromEmail":"matthieu.moy@grenoble-inp.fr","sentAt":"2012-11-16T20:25:41Z","receivedAt":"2012-11-16T20:25:41Z","isPatch":true,"sender":{"key":"matthieu.moy@grenoble-inp.fr","avatar":"https://gravatar.com/avatar/72c8a2705971a25dfaff23cece15130d405685845d911aedd5667ace277f3fc5?d=mp&s=160"},"body":"Aske Olsson <askeolsson@gmail.com> writes:\n\n> If the script .git/hooks/pre-push exists and is executable it will be\n> called before a `git push` command, and when the script exits with a\n> non-zero status the push will be aborted.\n\nThat sounds like a sane thing to do.\n\n>  Documentation/git-push.txt |  11 +++-\n>  Documentation/githooks.txt |  12 +++++\n>  builtin/push.c             |   6 +++\n>  t/t5542-pre-push-hook.sh   | 132 +++++++++++++++++++++++++++++++++++++++++++++\n\nIt would be nice to provide a sample hook in the default template. See\nthe template/ directory in Git's source code.\n\n> +--no-verify::\n> + This option bypasses the pre-push hook.\n> + See also linkgit:githooks[5].\n> +\n>  -q::\n>  --quiet::\n>   Suppress all output, including the listing of updated refs,\n\nHere, and below: you seem to have whitespace damage. Somebody replaced\ntabs with spaces I guess. Using git send-email helps avoiding this.\n\n> +D=`pwd`\n\nUnused variable, left from previous hacking I guess.\n\n> +# hook that always succeeds\n> +mk_hook_exec () {\n> +cat > \"$HOOK\" <<EOF\n> +#!/bin/sh\n> +exit 0\n> +EOF\n> +chmod +x \"$HOOK\"\n> +}\n> +\n> +# hook that fails\n> +mk_hook_fail () {\n> +cat > \"$HOOK\" <<EOF\n> +#!/bin/sh\n> +exit 1\n> +EOF\n> +chmod +x \"$HOOK\"\n> +}\n\nI'd add a \"touch hook-ran\" in the script, a \"rm -f hook-ran\" before\nlaunching git-push, and test the file existance after the hook to make\nsure it was ran.\n\n> +test_expect_success 'push with no pre-push hook' '\n> + mk_repo_pair &&\n> + (\n> + cd master &&\n> + echo one >foo && git add foo && git commit -m one &&\n> + git push --mirror up\n> + )\n> +'\n> +\n> +test_expect_success 'push --no-verify with no pre-push hook' '\n> + mk_repo_pair &&\n\nI don't think you need to re-create the repos for each tests. Tests are\ngood, but they're better when they're fast so avoiding useless\noperations is good.\n\nWe try to write tests so that one test failure does not imply failures\nof the next tests (i.e. stopping in the middle should not not leave\ngarbage that would prevent the next test from running), but do not\nnecessarily write 100% self-contained tests.\n\n> + echo one >foo && git add foo && git commit -m one &&\n\ntest_commit ?\n\n> +test_expect_success 'push with failing pre-push hook' '\n> + mk_repo_pair &&\n> + (\n> + mk_hook_fail &&\n> + cd master &&\n> + echo one >foo && git add foo && git commit -m one &&\n> + test_must_fail git push --mirror up\n> + )\n> +'\n\nIt would be cool to actually check that the push was not performed\n(verify that the target repo is still pointing to the old revision).\nOtherwise, an implementation that would call run_hook after pushing\nwould pass the tests.\n\n> +test_expect_success 'push with non-executable pre-push hook' '\n> + mk_repo_pair &&\n> + (\n> + mk_hook_no_exec &&\n> + cd master &&\n> + echo one >foo && git add foo && git commit -m one &&\n> + git push --mirror up\n> + )\n> +'\n> +\n> +test_expect_success 'push --no-verify with non-executable pre-push hook' '\n> + mk_repo_pair &&\n> + (\n> + mk_hook_no_exec &&\n> + cd master &&\n> + echo one >foo && git add foo && git commit -m one &&\n> + git push --no-verify --mirror up\n> + )\n> +'\n\nThese two tests are not testing much. The hook is not executable, so it\nshouldn't be ran, but you do not check whether the hook is ran or not.\nAt least make the \"exit 0\" an \"exit 1\" in the hook.\n\n-- \nMatthieu Moy\nhttp://www-verimag.imag.fr/~moy/\n"},{"id":"203370","messageId":"7vvcd5l290.fsf@alter.siamese.dyndns.org","threadId":"32129","inReplyTo":"CAJwKrPYwCE4ExmK09PURMfjYezn6vdCH_BBXU4WCwrnotyV9CA@mail.gmail.com","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-11-16T20:30:19Z","receivedAt":"2012-11-16T20:30:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Aske Olsson <askeolsson@gmail.com> writes:\n\n> If the script .git/hooks/pre-push exists and is executable it will be\n> called before a `git push` command, and when the script exits with a\n> non-zero status the push will be aborted.\n> The hook can be overridden by passing the '--no-verify' option to\n> `git push`.\n>\n> The pre-push hook is usefull to run tests etc. before push. Or to make\n> sure that if a binary solution like git-media, git-annex or git-bin is\n> used the binaries are uploaded before the push, so when others do a\n> fetch the binaries will be available already. This also reduces the\n> need for introducing extra (git) commands to e.g. sync binaries.\n>\n> Signed-off-by: Aske Olsson <askeolsson@gmail.com>\n> ---\n> ...\n> +[[pre-push]]\n> +pre-push\n> +~~~~~~~~\n> +\n> +This hook is invoked by 'git push' and can be bypassed with the\n> +`--no-verify` option. It takes no parameter, and is invoked before\n> +the push happens.\n> +Exiting with a non-zero status from this script causes 'git push'\n> +to abort.\n> ...\n> + if (!no_verify && run_hook(NULL, \"pre-push\")) {\n> + die(_(\"pre-push hook failed: exiting\\n\"));\n> + }\n\nNAK, at least in the current form.  At least the system should tell\nthe hook where it is pushing and what is being pushed.\n\nAfter working on my notebook, I may want to push to my desktop\nmachine first to test it, without having to test locally on an\nunderpowered CPU, but when I am publishing the end result to the\nwider world, I do want to test the result beforehand.  Without\n\"where am I pushing\", the hook would not help me to enforce testing\nonly for the latter.\n\nA lazy \"git push\" without any other argument may be configured in my\nrepository to push its \"maint\", \"master\", \"next\" and \"pu\" branches\nto the public repository.  I may say \"git push origin +pu\", while on\none of the topic branches, to push only the \"pu\" branches out before\nI am confident that the other branches I'll eventually publish are\nready (it is more likely that I may even *know* they are broken and\ndo not pass the test in such a case, and that is why I am pushing\nonly \"pu\" out).  I'd want to run tests only on 'pu' in such a case.\nWithout \"what am I pushing\", the hook would not be able to help me\ndoing that, either.\n\nBesides, there are five valid reasons to add a new hook to the\nsystem, but your version of pre-push does not satisfy any of them:\n\n     http://thread.gmane.org/gmane.comp.version-control.git/94111/focus=71069\n\nIt is more like \"to always cause an action before running a git\noperation locally,\" so you can even write\n\n    cat >$HOME/bin/git-mypush <<\\EOF\n    #!/bin/sh\n    run test || exit\n    exec git push \"$@\"\n    EOF\n    chmod +x $HOME/bin/git-mypush\n\nand then can run \"git mypush\" instead of adding this hook.\n"},{"id":"203379","messageId":"7vmwyhkzs5.fsf@alter.siamese.dyndns.org","threadId":"32129","inReplyTo":"vpq625547ne.fsf@grenoble-inp.fr","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-11-16T21:23:38Z","receivedAt":"2012-11-16T21:23:38Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Matthieu Moy <Matthieu.Moy@grenoble-inp.fr> writes:\n\n>> +# hook that fails\n>> +mk_hook_fail () {\n>> +cat > \"$HOOK\" <<EOF\n>> +#!/bin/sh\n>> +exit 1\n>> +EOF\n>> +chmod +x \"$HOOK\"\n>> +}\n>\n> I'd add a \"touch hook-ran\" in the script, a \"rm -f hook-ran\" before\n> launching git-push, and test the file existance after the hook to make\n> sure it was ran.\n\nAnd if you create that \"evidence that it did ran\" file without using\n\"touch\", it would be perfect.  Unless you are updating the timestamp\nof an existing file while preserving the contents of it, it is\nmisleading to use \"touch\".\n\nAll other points in your review are good.  Thanks.\n"},{"id":"203393","messageId":"50A73120.9040301@alum.mit.edu","threadId":"32129","inReplyTo":"7vvcd5l290.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Michael Haggerty","fromEmail":"mhagger@alum.mit.edu","sentAt":"2012-11-17T06:39:28Z","receivedAt":"2012-11-17T06:39:28Z","isPatch":true,"sender":{"key":"mhagger@alum.mit.edu","avatar":"https://avatars.githubusercontent.com/u/119718?v=4"},"body":"On 11/16/2012 09:30 PM, Junio C Hamano wrote:\n> Aske Olsson <askeolsson@gmail.com> writes:\n> \n>> If the script .git/hooks/pre-push exists and is executable it will be\n>> called before a `git push` command, and when the script exits with a\n>> non-zero status the push will be aborted.\n>> The hook can be overridden by passing the '--no-verify' option to\n>> `git push`.\n>>\n>> The pre-push hook is usefull to run tests etc. before push. Or to make\n>> sure that if a binary solution like git-media, git-annex or git-bin is\n>> used the binaries are uploaded before the push, so when others do a\n>> fetch the binaries will be available already. This also reduces the\n>> need for introducing extra (git) commands to e.g. sync binaries.\n>>\n>> Signed-off-by: Aske Olsson <askeolsson@gmail.com>\n>> ---\n>> ...\n>> +[[pre-push]]\n>> +pre-push\n>> +~~~~~~~~\n>> +\n>> +This hook is invoked by 'git push' and can be bypassed with the\n>> +`--no-verify` option. It takes no parameter, and is invoked before\n>> +the push happens.\n>> +Exiting with a non-zero status from this script causes 'git push'\n>> +to abort.\n>> ...\n>> + if (!no_verify && run_hook(NULL, \"pre-push\")) {\n>> + die(_(\"pre-push hook failed: exiting\\n\"));\n>> + }\n> \n> NAK, at least in the current form.  At least the system should tell\n> the hook where it is pushing and what is being pushed.\n\nI agree.\n\n> Besides, there are five valid reasons to add a new hook to the\n> system, but your version of pre-push does not satisfy any of them:\n> \n>      http://thread.gmane.org/gmane.comp.version-control.git/94111/focus=71069\n\nHere I disagree.  I think it satisfies (1):\n\n>  (1) A hook that countermands the normal decision made by the\n>      underlying command.  Examples of this class are the update\n>      hook and the pre-commit hook.\n\npre-push would be very similar in spirit to pre-commit: pre-commit is a\nfilter that can prevent a \"bad\" commit from getting into the local\nrepository; pre-push is similarly a filter between the local repo and\nremote repositories.\n\nI also think it satisfies (2) and/or (5b):\n\n>  (2) A hook that operates on data generated after the command\n>      starts to run.  [...]\n\n>  (5) [...]  Another example is the post-checkout\n>      hook that gets information that is otherwise harder to get\n>      (namely, if it was a branch checkout or file checkout --\n>      you can figure it out by examining the command line but\n>      that already is part of the processing git-checkout does\n>      anyway, so no need to force duplicating that code in the\n>      userland).\n\nIt would not be trivial for a wrapper script to figure out what branches\nand commits are about to be pushed.  But \"git push\" could tell the hook\nscript what branches are to be pushed.  And if the pre-push hook is run\nafter negotiation between client and server of what commits need to be\ntransfered, the hook could also be provided that information and use it\nto figure out which commits it should vet.\n\n\nAlthough a pre-receive script on the remote repository could do most of\nthe same things as a pre-push script, the latter would sometimes have\nadvantages because it is run \"client-side\":\n\n* When the user doesn't have the ability to change the pre-receive\nscript on the server (think public git hosting services).\n\n* For user-specific actions that are not wanted by all users pushing to\nthe same server (for example, maybe I add the string \"WIP\" to commit\nmessages for commits that are not ready to be pushed; my pre-push script\ncould verify that I don't push such a commit by accident).\n\n* Preventing \"secret\" info (password files, proprietary branches) from\nbeing pushed.  Even if the remote repo were taught to reject them, they\nwould have already traversed the internet.\n\nMichael\n\n-- \nMichael Haggerty\nmhagger@alum.mit.edu\nhttp://softwareswirl.blogspot.com/\n"},{"id":"203396","messageId":"CAJwKrPZC_9h5N8+zX8a0vhDQkv8e4y98+PWb=ygKfVc5CH3Qzw@mail.gmail.com","threadId":"32129","inReplyTo":"50A73120.9040301@alum.mit.edu","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Aske Olsson","fromEmail":"askeolsson@gmail.com","sentAt":"2012-11-17T08:47:58Z","receivedAt":"2012-11-17T08:47:58Z","isPatch":true,"sender":{"key":"askeolsson@gmail.com","avatar":"https://avatars.githubusercontent.com/u/474194?v=4"},"body":"On Sat, Nov 17, 2012 at 7:39 AM, Michael Haggerty <mhagger@alum.mit.edu> wrote:\n>\n> On 11/16/2012 09:30 PM, Junio C Hamano wrote:\n> > Aske Olsson <askeolsson@gmail.com> writes:\n> >\n> >> If the script .git/hooks/pre-push exists and is executable it will be\n> >> called before a `git push` command, and when the script exits with a\n> >> non-zero status the push will be aborted.\n> >> The hook can be overridden by passing the '--no-verify' option to\n> >> `git push`.\n> >>\n> >> The pre-push hook is usefull to run tests etc. before push. Or to make\n> >> sure that if a binary solution like git-media, git-annex or git-bin is\n> >> used the binaries are uploaded before the push, so when others do a\n> >> fetch the binaries will be available already. This also reduces the\n> >> need for introducing extra (git) commands to e.g. sync binaries.\n> >>\n> >> Signed-off-by: Aske Olsson <askeolsson@gmail.com>\n> >> ---\n> >> ...\n> >> +[[pre-push]]\n> >> +pre-push\n> >> +~~~~~~~~\n> >> +\n> >> +This hook is invoked by 'git push' and can be bypassed with the\n> >> +`--no-verify` option. It takes no parameter, and is invoked before\n> >> +the push happens.\n> >> +Exiting with a non-zero status from this script causes 'git push'\n> >> +to abort.\n> >> ...\n> >> + if (!no_verify && run_hook(NULL, \"pre-push\")) {\n> >> + die(_(\"pre-push hook failed: exiting\\n\"));\n> >> + }\n> >\n> > NAK, at least in the current form.  At least the system should tell\n> > the hook where it is pushing and what is being pushed.\n>\n> I agree.\n\nYes, I also agree that is a nice piece of information to pass to the hook.\nWill work on that.\n\n\n> > Besides, there are five valid reasons to add a new hook to the\n> > system, but your version of pre-push does not satisfy any of them:\n> >\n> >      http://thread.gmane.org/gmane.comp.version-control.git/94111/focus=71069\n>\n> Here I disagree.  I think it satisfies (1):\n>\n> >  (1) A hook that countermands the normal decision made by the\n> >      underlying command.  Examples of this class are the update\n> >      hook and the pre-commit hook.\n>\n> pre-push would be very similar in spirit to pre-commit: pre-commit is a\n> filter that can prevent a \"bad\" commit from getting into the local\n> repository; pre-push is similarly a filter between the local repo and\n> remote repositories.\n\nYes, I was thinking of a pre-push hook in the same way, preventing bad\ncommits from leaving the repo, but I guess you could argue that a bad\ncommit shouldn't happen in the first place due to the pre-commit hook.\n\n> I also think it satisfies (2) and/or (5b):\n>\n> >  (2) A hook that operates on data generated after the command\n> >      starts to run.  [...]\n>\n> >  (5) [...]  Another example is the post-checkout\n> >      hook that gets information that is otherwise harder to get\n> >      (namely, if it was a branch checkout or file checkout --\n> >      you can figure it out by examining the command line but\n> >      that already is part of the processing git-checkout does\n> >      anyway, so no need to force duplicating that code in the\n> >      userland).\n>\n> It would not be trivial for a wrapper script to figure out what branches\n> and commits are about to be pushed.  But \"git push\" could tell the hook\n> script what branches are to be pushed.  And if the pre-push hook is run\n> after negotiation between client and server of what commits need to be\n> transfered, the hook could also be provided that information and use it\n> to figure out which commits it should vet.\n>\n>\n> Although a pre-receive script on the remote repository could do most of\n> the same things as a pre-push script, the latter would sometimes have\n> advantages because it is run \"client-side\":\n>\n> * When the user doesn't have the ability to change the pre-receive\n> script on the server (think public git hosting services).\n\nYeah, and for my case I would like to sync some binaries to a remote\nstorage before pushing the commits that contains references to these.\nI know a wrapper script could easily do this, but I'm not to sure that it will\nwork in an organization with a lot of developers. Sooner or later one of them\nwill have some git problem and search the net, find an answer which (of\ncourse) doesn't include the commands in the wrapper script. Then he might\nend up pushing something that none of the other devs can get hold of and\nthat might cause builds to break etc.\nAnd we can't currently run pre-receive hooks to deny the commit.\n\n> * For user-specific actions that are not wanted by all users pushing to\n> the same server (for example, maybe I add the string \"WIP\" to commit\n> messages for commits that are not ready to be pushed; my pre-push script\n> could verify that I don't push such a commit by accident).\n>\n> * Preventing \"secret\" info (password files, proprietary branches) from\n> being pushed.  Even if the remote repo were taught to reject them, they\n> would have already traversed the internet.\n\nYes we have also seen a couple of these, would be nice to have a way\ndo deny them.\n\n-Aske\n"},{"id":"203397","messageId":"CAJwKrPbP--_zT4=xaYKwD1SbkO+bhT73EbgVzgT0oPA2FBCfTw@mail.gmail.com","threadId":"32129","inReplyTo":"vpq625547ne.fsf@grenoble-inp.fr","subject":"Re: [PATCH] Add support for a 'pre-push' hook","fromName":"Aske Olsson","fromEmail":"askeolsson@gmail.com","sentAt":"2012-11-17T09:00:01Z","receivedAt":"2012-11-17T09:00:01Z","isPatch":true,"sender":{"key":"askeolsson@gmail.com","avatar":"https://avatars.githubusercontent.com/u/474194?v=4"},"body":"On Fri, Nov 16, 2012 at 9:25 PM, Matthieu Moy\n<Matthieu.Moy@grenoble-inp.fr> wrote:\n> Aske Olsson <askeolsson@gmail.com> writes:\n>\n>> +--no-verify::\n>> + This option bypasses the pre-push hook.\n>> + See also linkgit:githooks[5].\n>> +\n>>  -q::\n>>  --quiet::\n>>   Suppress all output, including the listing of updated refs,\n>\n> Here, and below: you seem to have whitespace damage. Somebody replaced\n> tabs with spaces I guess. Using git send-email helps avoiding this.\n\nI had some firewall problems at work, so ended up sending from gmail.\nWill fix ;)\n\n>> +D=`pwd`\n>\n> Unused variable, left from previous hacking I guess.\n\nYep!\n\n> I'd add a \"touch hook-ran\" in the script, a \"rm -f hook-ran\" before\n> launching git-push, and test the file existance after the hook to make\n> sure it was ran.\n\nYea' that would probably be a good idea!\n\n> I don't think you need to re-create the repos for each tests. Tests are\n> good, but they're better when they're fast so avoiding useless\n> operations is good.\n>\n> We try to write tests so that one test failure does not imply failures\n> of the next tests (i.e. stopping in the middle should not not leave\n> garbage that would prevent the next test from running), but do not\n> necessarily write 100% self-contained tests.\n\nOk, I'll speed it up.\n\n>> + echo one >foo && git add foo && git commit -m one &&\n>\n> test_commit ?\n\nCool, I'll use that!\n\n> It would be cool to actually check that the push was not performed\n> (verify that the target repo is still pointing to the old revision).\n> Otherwise, an implementation that would call run_hook after pushing\n> would pass the tests.\n[...]\n>\n> These two tests are not testing much. The hook is not executable, so it\n> shouldn't be ran, but you do not check whether the hook is ran or not.\n> At least make the \"exit 0\" an \"exit 1\" in the hook.\n\nAll very good points, thanks. I'll get back to hacking.\n\n-Aske\n"}]}