Search code examples
gitbranchgit-remote

Restrict push to certain remotes for a branch


I have two remotes, one for production and one for GitHub. As I have to push certain files to the productions that must not land on GitHub I would like to restrict a branch to avoid accidents.

Is there a way to tell my git client that it should never push the branch "deploy" to remote "github" and only push this branch to "production"?


Solution

  • kowsky's answer is the right one, provided your Git is at least 1.8.2 (and if not you should upgrade :-) ). However, the linked examples are faulty.

    The pre-push hook is invoked with two arguments, which provide:

    • the name of the remote, if a named remote is used, else the URL
    • the URL (the result of expanding the named remote, if a named remote is used)

    What is to be pushed, which is something you specify at the time you run git push, is provided to the hook on its standard input. This is where the two linked examples are both broken.

    If you run:

    git push github refspec1 refspec2 ... refspecN
    

    then the reference(s) being pushed are those given on this command line.

    If you run:

    git push github
    

    (with no refspecs), the set of branches to be pushed is... well, it's complicated, but in modern Git, it defaults to the current branch.

    The sample pre-push hooks assume that only the current branch is to be pushed. Since that's the modern default, the samples will probably work, up until you accidentally run:

    git push github deploy
    

    (while on, say, master), and then they won't, and you may be sad. :-)

    To fix them, use a githook that reads, e.g.:

    #! /bin/sh
    [ "$1" = github ] || exit 0 # allow if not pushing to github
    while read lref lhash rref rhash; do
        case "$lref" in
        refs/heads/deploy)
            echo "error: attempt to push 'deploy' branch to github" 1>&2
            exit 1;;
        esac
    done
    

    This will allow:

    git push github master:deploy
    

    (which creates or updates a deploy on remote github, but using local branch master, not local branch deploy) while forbidding:

    git push github deploy:oops
    

    (which pushes the local deploy to a branch named oops).

    Should you wish to have more complicated rules, write them up. Note that if you want to prevent the use of git push https://github.com/... to bypass your own hook, you can check $2 as well as $1. Of course, if you are that determined to bypass your own hook, you could easily run git push --no-verify to disable your hook.