Simon Josefsson <[EMAIL PROTECTED]> wrote: > Jim Meyering <[EMAIL PROTECTED]> writes: > >> Does anyone object to my installing a server-side hook >> that would prevent pushing merge commits on master? >> In our experience here (with gnulib.git), pushing a merge >> commit is always unintentional. > > +1 from me. How would you do that? I'd like to do it in some other > projects. It is easy to inadvertently send a merge commit.
Apply the patch below to git.git on its "maint" branch, then copy templates/hooks--update.sample into your server-side repository as an executable repo.git/hooks/update. Finally, server-side, set the config variable for each repo/branch pair: git --git-dir=/path/to/your-proj.git config --bool \ hooks.denymerge.master true The only tricky part was the is_merge_commit function, and I learned that by asking on #git/irc.freenode. [Thanks to doener (Björn Steinbrink)] However, beware. I'm pretty sure that some parts of this patch depend on having a relatively recent version of git. I'm using it with git-1.5.6.4. Jim P.S., as you can see, the naming of the config options is not consistent. Still not sure which approach I prefer. >From c02efe37e975094f7fbc7938f29c38819355f995 Mon Sep 17 00:00:00 2001 From: Jim Meyering <[EMAIL PROTECTED]> Date: Tue, 29 Jul 2008 18:16:50 +0200 Subject: [PATCH] add hooks: deny-bad-whitespace, per-branch: deny-push deny-merge-commit Reject any attempt to push a change that adds "bad" whitespace. Override with this: git config hooks.allowbadwhitespace true Disable push-access on a per-branch basis. Prohibit pushing merge commits on a per-branch basis. --- templates/hooks--update.sample | 60 ++++++++++++++++++++++++++++++++++++++++ 1 files changed, 60 insertions(+), 0 deletions(-) diff --git a/templates/hooks--update.sample b/templates/hooks--update.sample index 93c6055..0c89f30 100755 --- a/templates/hooks--update.sample +++ b/templates/hooks--update.sample @@ -17,12 +17,35 @@ # This boolean sets whether deleting branches will be allowed in the # repository. By default they won't be. # +# hooks.allowbadwhitespace +# This boolean sets whether you may push a commit that adds bad whitespace. +# By default, you may not. +# +# hooks.denypush.branch.BRANCH_NAME +# If defined to a string that looks like an email address, this option +# disables push access to the specified branch. When a push fails as +# a result of this option, the resulting diagnostic includes the specified +# email address. For example, run this on the server to deny all push +# access to "master": +# +# For example, enable it with this: +# git config hooks.denypush.branch.master [EMAIL PROTECTED] +# +# hooks.denymerge.BRANCH_NAME +# When this boolean is true, you may not push a merge commit to BRANCH_NAME. +# By default, you may. +# # --- Command line refname="$1" oldrev="$2" newrev="$3" +is_merge_commit() +{ + git rev-parse --verify --quiet $1^2 > /dev/null +} + # --- Safety check if [ -z "$GIT_DIR" ]; then echo "Don't run this script from the command line." >&2 @@ -56,6 +79,7 @@ else newrev_type=$(git-cat-file -t $newrev) fi +check_diff=no case "$refname","$newrev_type" in refs/tags/*,commit) # un-annotated tag @@ -78,6 +102,32 @@ case "$refname","$newrev_type" in ;; refs/heads/*,commit) # branch + check_diff=yes + branch=${1##refs/heads/} + deny_push_email=$(git config "hooks.denypush.branch.$branch") + case $deny_push_email in + '') ;; + *) printf "error: *** %s\n" \ + "commit on branch '$branch'" \ + "locked by $deny_push_email" >&2 + exit 1;; + esac + + # When enabled, this prohibits pushing a merge commit. + # Enable this hook for branch "next" with e.g., + # git config --bool hooks.denymerge.next true + deny_merge=$(git config --bool "hooks.denymerge.$branch") + case $deny_merge in + true) + is_merge_commit $newrev && { + printf "error: *** %s\n" \ + "You may not push merge commits to branch $branch." \ + "Did you forget to rebase? ($newrev)" >&2 + exit 1 + } + ;; + esac + ;; refs/heads/*,delete) # delete branch @@ -88,6 +138,7 @@ case "$refname","$newrev_type" in ;; refs/remotes/*,commit) # tracking branch + check_diff=yes ;; refs/remotes/*,delete) # delete tracking branch @@ -103,5 +154,14 @@ case "$refname","$newrev_type" in ;; esac +if [ $check_diff = yes ]; then + allow_bad_whitespace=$(git config --bool hooks.allowbadwhitespace) + if [ "$allow_bad_whitespace" != "true" ]; then + test "$oldrev" = 0000000000000000000000000000000000000000 \ + && exit 0 + exec git diff --check $oldrev $newrev -- + fi +fi + # --- Finished exit 0 -- 1.6.0.2.514.g23abd3