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?
问题:
回答1:
You can use GitEnterprise to setup per-branch permissions (admin) to block non-fastforward pushes using fine-grained access permission.
And git config --system receive.denyNonFastForwards true
will simply do the job if you need to block history changing for all branches.
回答2:
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
回答3:
You can prevent non-fast-forward updates by configuring denyNonFastForwards
git config --system receive.denyNonFastForwards true
But it applies for all branches. For more info please refer ProGit
回答4:
This SO answer will give you what you're looking for. Just edit it to apply to the master branch instead:
#!/bin/sh
# lock the master branch for pushing
refname="$1"
if [ "$refname" = "refs/heads/master" ]
then
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
echo "You cannot push to the master branch."
echo "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
exit 1
fi
exit 0
Update:
This will prevent all pushes to the master branch, including fast-forward.
回答5:
I think it depends on what you use on server side to access your repository. There are some server applications which support per-branch permissions, like Gerrit or Gitlab (however, i'm not sure if Gitlab supports your usecase). Gerrit supports it, since i use a similiar workflow in my company.
Maybe Gitolite also supports it (that's what Gitlab uses under the hood), which is easier to setup, but doesn't have a webinterface like Gerrit or Gitlab.
Additional comment: GitEnterprise, as suggested, is also a good solution, my suggestions however are suitable, if you have your own server (which is common in many companies).
回答6:
If you would be allowed to modify your server, then this will enable fast-forwarding on server.
ssh ip 'echo $"[receive]
denyDeletes = false
denyNonFastForwards = false" >> /path/to/repo/config'
#then git push -f origin master