[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: automatically preventing merge commits on master
From: |
Jim Meyering |
Subject: |
Re: automatically preventing merge commits on master |
Date: |
Mon, 13 Oct 2008 21:41:46 +0200 |
Simon Josefsson <address@hidden> wrote:
> Jim Meyering <address@hidden> 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 <address@hidden>
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 address@hidden
+#
+# 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