How can I prevent non-fastforward pushes to selected branch(es) in git?

前端 未结 7 1261
醉话见心
醉话见心 2020-12-10 06:46

I would like to protect my git repository so only non master branches can be overwritten. Is there a way to protect only selected branches?

相关标签:
7条回答
  • 2020-12-10 07:27

    Here's an update hook (copy to hooks/update) that I wrote for my own use. This script by default denies all non-fast-forward updates but allows them for explicitly configured branches. It should be easy enough to invert it so that non-fast-forward updates are allowed for all but the master branch.

    #!/bin/sh
    #
    # A hook script to block non-fast-forward updates for branches that haven't
    # been explicitly configured to allow it. Based on update.sample.
    # Called by "git receive-pack" with arguments: refname sha1-old sha1-new
    #
    # Config
    # ------
    # hooks.branch.<name>.allownonfastforward
    #   This boolean sets whether non-fast-forward updates will be allowed for
    #   branch <name>. By default they won't be.
    
    # --- Command line
    refname="$1"
    oldrev="$2"
    newrev="$3"
    
    # --- 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
    
    # --- 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
    
    case "$refname","$newrev_type" in
            refs/tags/*,commit)
                    # un-annotated tag
                    ;;
            refs/tags/*,delete)
                    # delete tag
                    ;;
            refs/tags/*,tag)
                    # annotated tag
                    ;;
            refs/heads/*,commit)
                    # branch
                    # git rev-list doesn't print anything on fast-forward updates
                    if test $(git rev-list "$newrev".."$oldrev"); then
                            branch=${refname##refs/heads/}
                            nonfastforwardallowed=$(git config --bool hooks.branch."$branch".allownonfastforward)
    
                            if [ "$nonfastforwardallowed" != "true" ]; then
                                    echo "hooks/update: Non-fast-forward updates are not allowed for branch $branch"
                                    exit 1
                            fi
                    fi
                    ;;
            refs/heads/*,delete)
                    # delete branch
                    ;;
            refs/remotes/*,commit)
                    # tracking branch
                    ;;
            refs/remotes/*,delete)
                    # delete tracking branch
                    ;;
            *)
                    # Anything else (is there anything else?)
                    echo "hooks/update: Unknown type of update to ref $refname of type $newrev_type" >&2
                    exit 1
                    ;;
    esac
    
    # --- Finished
    exit 0
    
    0 讨论(0)
提交回复
热议问题