2

I have to configure read-only access for some remote branches of a controlled git repository.

The scenario is as follows:

For our development, we have an internal "development repository" (1) that mirrors an "external repository". This "development repository" gets periodic updates (git remote update in a cron job). Our development takes place in branches "dev_*" derived from the external repositories, but never direct on the external branch:

Repositories schema

The workflow for adding functionality to master:

  1. We create a branch dev_master with master as parent.
  2. John clones the repository development, checks out dev_master, works on it, and pushes regularly back to development.
  3. If the repository external gets master updated, so is master in development (due to the above mentioned cronjob), and someone can merge master on dev_master, so we keep in sync with external.

We need to forbid John's pushes to the branch master of development, so his changes doesn't get lost after the periodic update from external.

Again, schematic:

Repositories summary


Notes

(1) I could find that some people call this development repository "staging repository" (for example, in How do I setup a staging repository in git?, where a very similar situation has been presented)

Community
  • 1
  • 1
Alberto
  • 5,021
  • 4
  • 46
  • 69
  • Very similar to [Prohibit remote pushing to the master branch in git](http://stackoverflow.com/questions/2045329/prohibit-remote-pushing-to-the-master-branch-in-git). The difference is that I need to forbid access to all branches of the external repository, whereas in the mentioned question, the author only needed to forbid pushes to the `master` branch – Alberto Jan 24 '13 at 13:13
  • See also, for the remote side, http://stackoverflow.com/a/5097437/6309 – VonC Sep 20 '13 at 06:33

1 Answers1

3

I forbid these pushes using a Server-Side hook. From git help hooks:

pre-receive
This hook is invoked by git-receive-pack on the remote repository, which happens when a git push is done on a local repository. Just before starting to update refs on the remote repository, the pre-receive hook is invoked. Its exit status determines the success or failure of the update.
[...]
If the hook exits with non-zero status, none of the refs will be updated. If the hook exits with zero, updating of individual refs can still be prevented by the update hook.
[...]

The hook code:

#!/bin/bash

# Read the branches of the remote repository
remote_branches=$(git ls-remote --heads | sed "s,.*\(refs/heads/\),\1,")

function forbid_push_to_remote_branches()
{
    while read old_value new_value ref_name
    do
        # Test for existence of [$ref_name] in remote
        for remote_branch in $remote_branches
        do
            if [[ $remote_branch == $ref_name ]]
            then
                invalid_refs="$invalid_refs [$remote_branch]"
                break
            fi
        done
    done

    # if remote read-only branches found, exit with non-zero
    # and list these branches
    if [[ -n $invalid_refs ]]
    then
        echo "ERROR: You are trying to push to remote branch(es):" >&2
        echo "   $invalid_refs" >&2
        return 1 
    else
        return 0
    fi
}

forbid_push_to_remote_branches
exit $?

This code must be copied to the file $(bare_repo_path.git)/hooks/pre-receive in the server (there is no pre-receive.sample).

Alberto
  • 5,021
  • 4
  • 46
  • 69