January 7, 2010

Sharing your git repository

… or maybe not.

We’ve had this problem for some time and couldn’t really find a good solution for that. We wanted to have some repositories to be only writeable for selected users and even some repositories to be accessible for some users and completely invisible for the others.

First requirement seemed to be pretty simple as git access control is based on file permissions. So creating a repository only writeable for a selected group seemed to work… until somebody hasn’t committed a change which created a new object in .git directory which wasn’t group writable! The next person trying to change this object after was getting permission denied error like that:

#> git push origin master
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 286 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
fatal: failed to write object
error: unpack failed: unpack-objects abnormal exit
To smarek@mygitserver.com:/home/smarek/git/myRepo.git
 ! [remote rejected] master -> master (n/a (unpacker error))
error: failed to push some refs to 'smarek@mygitserver.com:/home/smarek/git/myRepo.git'

Obviously git atomic commits did its trick and didn’t break the repository, but at the same time this issue prevented us pushing the changes to remote repository! We had tried different git hooks, but it didn’t work the way we wanted. So basically we ended up with a script that must have been run manually on git server when the issue was encountered.

#!/bin/bash
if [ $# -lt 1 ]; then
    echo "Usage: $0 <repo>"
    exit 1
fi
chown -R owner:group /path/to/repo/$1.git/objects
chmod -R g+w /path/to/repo/$1.git/objects

Until now. Friend of mine (thanks rodrigez) actually discovered a native git feature, that allows you to control access to a repository – core.sharedRepository. It accepts the following values:

  • umask (or false) – the default value. Git uses permissions reported by umask
  • group (or true) – makes the repository group-writable
  • all (or world or everybody) – same as group, but make the repository readable by all users
  • 0xxx: 0xxx is an octal number and each file will have mode 0xxx. 0xxx will override users umask value. 0640 will create a repository which is group-readable but not writable. 0660 is equivalent to group.

You can set that using either git config command if your repository already exists, or you want to make the default value either global or system wide:

#> git config core.sharedRepository group

or during brand new repository creation:

#> git init --shared=group

So for me setting core.sharedRepository to group solves my first issues, while removing all access to other users to all files in the repository and setting core.sharedRepository to 0770 will restrict access to the repository to only limited number of people.

4 Comments

  • Hi Seb
    Nice stuff, but to control group membership of newly created files you don’t need to use external scripts. *nix provides at least twice mechanisms you could use:

    1. (my personal favourite) use the setgid bit on the parent folder (see details below)

    2. use the newgrp CLI command to change the default group of the user before making any changes to the repository.

    Ad 1. just to show the example look at the code below:

    $mkdir test
    $chgrp gitusers test
    $chmod g+s test
    $touch test/file.txt
    $mkdir test/dir
    $touch test/dir/file2.txt
    $ls -alR test/
    test/:
    razem 12
    drwxrwsr-x. 3 piotrs gitusers 4096 01-08 09:48 .
    drwx——. 42 piotrs piotrs 4096 01-08 09:48 ..
    drwxrwsr-x. 2 piotrs gitusers 4096 01-08 09:48 dir
    -rw-rw-r–. 1 piotrs gitusers 0 01-08 09:48 file.txt

    test/dir:
    razem 8
    drwxrwsr-x. 2 piotrs gitusers 4096 01-08 09:48 .
    drwxrwsr-x. 3 piotrs gitusers 4096 01-08 09:48 ..
    -rw-rw-r–. 1 piotrs gitusers 0 01-08 09:48 file2.txt

    Hope that helps

Leave a Reply

Your email address will not be published. Required fields are marked *