On Wed, Sep 11, 2013 at 04:13:43PM -0600, Pete Zaitcev wrote:
> Dear All:
> 
> I found that I pushed a merge node into Fedora git (fortunately it was
> only on f19 branch, not in Rawhide):
> 
> commit 51eec48c20ba57054f17ba29f23e6a0aa36df9a4
> Merge: ac36771 f9213a5
> Author: Pete Zaitcev <zait...@kotori.zaitcev.us>
> Date:   Wed Aug 7 12:14:15 2013 -0600
> 
>     Merge branch 'f19' of ssh://pkgs.fedoraproject.org/openstack-swift into 
> f19
> 
> Thought I was careful about them, but apparently not enough. So, does
> anyone have a script that can be attached to git hooks, reliably detects
> an attempt to push merge nodes, then bails the push?

The attached script is what we use in libvirt for preventing merge
commits being pushed to the main repo.  Copy that to your hooks
directory naming the file 'update'. Then edit your .git/config
file to set

  [hooks "denymerge"]
          master = true


It can also be used to prevent creation of new branches or to block
commits which have trailing whitespace at the end of line eg by
setting

  [hooks]
          allowbadwhitespace = false
          denycreatebranch = true

See the script for other possible config options

Regards,
Daniel
-- 
|: http://berrange.com      -o-    http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org              -o-             http://virt-manager.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org       -o-       http://live.gnome.org/gtk-vnc :|
#!/bin/sh
#
# An example hook script to block unannotated tags from entering.
# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
#
# To enable this hook, rename this file to "update".
#
# Config
# ------
# hooks.allowunannotated
#   This boolean sets whether unannotated tags will be allowed into the
#   repository.  By default they won't be.
# hooks.allowdeletetag
#   This boolean sets whether deleting tags will be allowed in the
#   repository.  By default they won't be.
# hooks.allowmodifytag
#   This boolean sets whether a tag may be modified after creation. By default
#   it won't be.
# hooks.allowdeletebranch
#   This boolean sets whether deleting branches will be allowed in the
#   repository.  By default they won't be.
# hooks.denycreatebranch
#   This boolean sets whether remotely creating branches will be denied
#   in the repository.  By default this is allowed.
#
# 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 master-branch-ow...@example.com
#
# hooks.denymerge.BRANCH_NAME
#   When this boolean is true, you may not push a merge commit to BRANCH_NAME.
#   By default, you may.
#
# ---------------------------------------------------------------------
# Allow people to change server-side git config in very specific ways.
# To enable this, on the server, you must do something like the following,
#
# git config hooks.server.config-changing.valid-commands \
# 'git config hooks.allowbadwhitespace true
# git config hooks.allowbadwhitespace false
# git config hooks.denypush.branch.master master-branch-ow...@example.com
# git config --unset hooks.denypush.branch.master'
#
# where the git config variable, hooks.server.config-changing.valid-commands,
# contains the list of commands that are allowed, one per line.
#
# CAUTION: nothing about this hook code enforces the restriction that
# only "git config ..." commands be run automatically.
# That restriction comes solely from the list above.
#
# Then, when someone with a cloned repository wants to make the hook
# run one of those commands *on* *the* *server*, that user must push
# a tag whose name starts with "git-control-" and whose one-line message
# matches exactly one of the listed commands.
#
# For example, to temporarily allow someone to push a bad-whitespace
# commit, with the settings implied above, you might do this:
#
#   first_commit=$(git log --reverse --pretty=%H |head -1)
#   git tag -m 'git config hooks.allowbadwhitespace true' \
#     git-control-$(date +%F-%H-%M-%S.%N) $first_commit
#
# Note that we're not tagging HEAD, but rather the very first commit
# in the repository, in an attempt not to clutter up gitk/gitweb
# displays with these rarely-interesting tag names.
#
# Then, to reenable that hook, do this (nearly the same, except s/true/false/):
#
#   first_commit=$(git log --reverse --pretty=%H |head -1)
#   git tag -m 'git config hooks.allowbadwhitespace false' \
#     git-control-$(date +%F-%H-%M-%S.%N) $first_commit
# ---------------------------------------------------------------------

# --- 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
        echo " (if you want, you could supply GIT_DIR then run" >&2
        echo "  $0 <ref> <oldrev> <newrev>)" >&2
        exit 1
fi

if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
        echo "Usage: $0 <ref> <oldrev> <newrev>" >&2
        exit 1
fi

# --- Config
allowunannotated=$(git config --bool hooks.allowunannotated)
allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
denycreatebranch=$(git config --bool hooks.denycreatebranch)
allowdeletetag=$(git config --bool hooks.allowdeletetag)
allowmodifytag=$(git config --bool hooks.allowmodifytag)

# check for no description
projectdesc=$(sed -e '1q' "$GIT_DIR/description")
case "$projectdesc" in
"Unnamed repository"* | "")
        echo "*** Project description file hasn't been set" >&2
        exit 1
        ;;
esac

# --- Check types
# if $newrev is 0000...0000, it's a commit to delete a ref.
zero="0000000000000000000000000000000000000000"
if [ "$newrev" = "$zero" ]; then
        newrev_type=delete
else
        newrev_type=$(git cat-file -t $newrev)
fi

check_diff=no
case "$refname","$newrev_type" in
        refs/tags/*,commit)
                # un-annotated tag
                short_refname=${refname##refs/tags/}
                if [ "$allowunannotated" != "true" ]; then
                        echo "*** The un-annotated tag, $short_refname, is not 
allowed in this repository" >&2
                        echo "*** Use 'git tag [ -a | -s ]' for tags you want 
to propagate." >&2
                        exit 1
                fi
                ;;
        refs/tags/*,delete)
                # delete tag
                if [ "$allowdeletetag" != "true" ]; then
                        echo "*** Deleting a tag is not allowed in this 
repository" >&2
                        exit 1
                fi
                ;;
        refs/tags/*,tag)
                case $refname in
                  refs/tags/show)
                    echo "*** a tag named 'show' is not permitted" >&2
                    exit 1
                    ;;
                  refs/tags/git-control-*)
                    cmd=$(git cat-file -p $newrev|tail -n+6)
                    git config hooks.server.config-changing.valid-commands |
                    (while read v_cmd; do
                      if test "x$cmd" = "x$v_cmd"; then
                        echo Running cmd: "$v_cmd"
                        eval "$v_cmd"
                        match=1
                        exit 0 # found a match
                      fi
                    done
                    exit 1 # signal failure to match
                    )
                    if test $? = 1; then
                      echo "*** unrecognized directive: $cmd" >&2
                      exit 1
                    fi
                    ;;
                esac
                # annotated tag
                if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > 
/dev/null 2>&1
                then
                        echo "*** Tag '$refname' already exists." >&2
                        echo "*** Modifying a tag is not allowed in this 
repository." >&2
                        exit 1
                fi
                ;;
        refs/heads/*,commit)
                # branch
                if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
                        echo "*** Creating a branch is not allowed in this 
repository" >&2
                        exit 1
                fi

                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)
                        for r in $(test "$oldrev" = $zero \
                                     && git rev-list $newrev \
                                     || git rev-list $newrev ^$oldrev); do
                          is_merge_commit $r && {
                            printf "error: *** %s\n" \
                          "You may not push merge commits to branch $branch." \
                          "Did you forget to rebase? ($r)" >&2
                          exit 1
                          }
                        done
                        ;;
                esac

                ;;
        refs/heads/*,delete)
                # delete branch
                if [ "$allowdeletebranch" != "true" ]; then
                        echo "*** Deleting a branch is not allowed in this 
repository" >&2
                        exit 1
                fi
                ;;
        refs/remotes/*,commit)
                # tracking branch
                check_diff=yes
                ;;
        refs/remotes/*,delete)
                # delete tracking branch
                if [ "$allowdeletebranch" != "true" ]; then
                        echo "*** Deleting a tracking branch is not allowed in 
this repository" >&2
                        exit 1
                fi
                ;;
        *)
                # Anything else (is there anything else?)
                echo "*** Update hook: unknown type of update to ref $refname 
of type $newrev_type" >&2
                exit 1
                ;;
esac

if [ $check_diff = yes ]; then
        allow_bad_whitespace=$(git config --bool hooks.allowbadwhitespace)
        if [ "$allow_bad_whitespace" != "true" ]; then
                test "$oldrev" = $zero \
                        && exit 0
                exec git diff --check $oldrev $newrev --
        fi
fi

# --- Finished
exit 0
-- 
devel mailing list
devel@lists.fedoraproject.org
https://admin.fedoraproject.org/mailman/listinfo/devel
Fedora Code of Conduct: http://fedoraproject.org/code-of-conduct

Reply via email to