RTFM

[Read This Fine Material] from Joshua Hoblitt

Preventing git nonfastforward (–force) pushes

| 0 comments

Per discussion in the git book and on stackoverflow:

http://stackoverflow.com/questions/1754491/is-there-a-way-to-configure-git-repository-to-reject-git-push-force
http://git-scm.com/book/en/Customizing-Git-An-Example-Git-Enforced-Policy

Set these values on the git repo you want to protect:

git config receive.denyNonFastforwards true
git config receive.denyDeletes true

This may also be set as a system wide default via:

git config --system receive.denyNonFastforwards true
git config --system receive.denyDeletes true

Demonstration that this will indeed prevent forced pushes:

jhoblitt@leo ~/test $ git init --bare testrepo.git
Initialized empty Git repository in /home/jhoblitt/test/testrepo.git/
jhoblitt@leo ~/test $ cd testrepo.git/
jhoblitt@leo ~/test/testrepo.git $ git config receive.denyNonFastforwards true
jhoblitt@leo ~/test/testrepo.git $ git config receive.denyDeletes true
jhoblitt@leo ~/test/testrepo.git $ cd ..
jhoblitt@leo ~/test $ git clone ./testrepo.git/ testclone
Cloning into 'testclone'...
warning: You appear to have cloned an empty repository.
done.
jhoblitt@leo ~/test $ cd testclone/
jhoblitt@leo ~/test/testclone $ echo "1" > foo
jhoblitt@leo ~/test/testclone $ git add foo
jhoblitt@leo ~/test/testclone $ git commit -m"first commit"
[master (root-commit) 98667fc] first commit
 1 file changed, 1 insertion(+)
 create mode 100644 foo
jhoblitt@leo ~/test/testclone $ echo "2" > foo
jhoblitt@leo ~/test/testclone $ git add foo
jhoblitt@leo ~/test/testclone $ git commit -m"second commit"
[master 325237a] second commit
 1 file changed, 1 insertion(+), 1 deletion(-)
jhoblitt@leo ~/test/testclone $ echo "3" > foo
jhoblitt@leo ~/test/testclone $ git add foo
jhoblitt@leo ~/test/testclone $ git commit -m"oops, last commit should have been 3"
[master bb776bd] oops, last commit should have been 3
 1 file changed, 1 insertion(+), 1 deletion(-)
jhoblitt@leo ~/test/testclone $ git push origin master
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 460 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To /home/jhoblitt/test/testrepo.git/
   98667fc..bb776bd  master -> master
jhoblitt@leo ~/test/testclone $ git rebase -i HEAD~2
[detached HEAD b88ab29] second commit
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/master.
jhoblitt@leo ~/test/testclone $ git push origin master
To /home/jhoblitt/test/testrepo.git/
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to '/home/jhoblitt/test/testrepo.git/'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
jhoblitt@leo ~/test/testclone $ git push --force origin master
Counting objects: 5, done.
Writing objects: 100% (3/3), 243 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
remote: error: denying non-fast-forward refs/heads/master (you should pull first)
To /home/jhoblitt/test/testrepo.git/
 ! [remote rejected] master -> master (non-fast-forward)
error: failed to push some refs to '/home/jhoblitt/test/testrepo.git/'

Leave a Reply