33

We're accessing a shared git repository via file paths, for various reasons I'll omit for now, created with --shared=group.

We have various unix groups but all share a common group. If I run a chgrp -R on the git repository everyone can read from it, but if someone writes to it more often than not new files are created which do not use the common group.

This problem appears to be because our primary group is not the shared one and if we run a newgrp all seems to work well.

There are issues with this approach though; newgrp is slow and it spawns a new shell, which makes me think calling it in a .bash_profile would be a bad idea, without even considering whether or not we'd want all our new files to use the common group. Relying on memory to run it before doing any git work seems like a recipe for disaster too though.

So... any suggestions?

ekad
  • 14,436
  • 26
  • 44
  • 46
rich
  • 18,987
  • 11
  • 75
  • 101

5 Answers5

29

An existing repository that has not been created with --shared can be turned shared using following commands:

# make the repository shared
git config core.sharedRepository group # or whatever other sharing option
# fix the setgid bit
find . -type d | xargs chmod g+s
# repair the permissions
chmod -R g+r *
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
fikovnik
  • 3,473
  • 3
  • 28
  • 29
  • 2
    In my case I had to do "chmod -R g+rw *" because group should have a right to write not just read. Otherwise thanks for your answer. – Denis V Sep 26 '13 at 13:59
  • Thanks @fikovnik, this helped me to make my repo readable by the www-data user without losing permissions when switching branches. In addition to your answer above, the missing piece for me was to add myself to the www-data group - otherwise directories lost the setgid bit when I switched branches. The chmod manual says this behaviour is system-dependent. It seems that on Linux, the behaviour is for the chmod system call to clear the setgid bit on directories unless the user belongs to the group, and it seems git uses the chmod system call to apply the `core.sharedRepository` setting. – akwizgran Jul 10 '19 at 13:17
  • I also had to do `chmod -R g+rw .*` (with a period) since it was the `.git/FETCH_HEAD` file which the rest of the group could not write to, – TheChymera Dec 09 '21 at 15:13
  • @TheChymera note that `chmod -R g+rw .*` will also affect other entries starting with `.`, in particular `..` the parent directory. That's quite a big unexpected side-effect; better to specify `.git` specifically instead, `chmod -R g+rw .git` – Andrew Richards Feb 03 '23 at 15:25
24

You need to set the setgid bit on the group as well.

chgrp -R GROUP /path/to/repo
find /path/to/repo -type d -print0 | xargs -0 chmod g+s 
Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
Wes Hardaker
  • 21,735
  • 2
  • 38
  • 69
  • 8
    Do not ever `chmod -R g+s` a git repo, instead of doing only what you thought you did, you just enabled setgid on every file. – Arrowmaster Jan 29 '11 at 10:31
  • Well, it's true it's not the best thing to do. Fortunately none of them are executable. I've updated the post to only hit directories instead (which is required). – Wes Hardaker Jan 29 '11 at 22:31
  • 2
    Well if you are going to use find you might as well go all out and use -print0 to protect from anybody crazy enough to use spaces or other weird characters in their branch/tag names. – Arrowmaster Jan 30 '11 at 02:29
  • 1
    This doesn't work for me, on new directories created git doesn't set the `setgid` bit for some reason: http://stackoverflow.com/questions/15889573/setgid-bit-not-preserved-by-git-on-new-directory-in-git-folder – Andrew Tomazos Apr 08 '13 at 23:00
  • 1
    It should if the parent directory is setgid – Wes Hardaker Apr 09 '13 at 13:58
  • 4
    find /path/to/repo -type d -exec chmod g+s {} \; – rich remer Oct 10 '13 at 16:36
12

Is this a bare repo? If its a bare repo and you used --shared when you created it then this shouldn't be happening which is why I'm asking.

If it is a bare repo maybe some of the directories got changed to g-s, if that happened you need to either chmod g+x all the directories only, make sure you don't do it to any files. An easier way than that might be to just git init --bare --shared=group a new repo and push the content back to it from somebodies clone.

Arrowmaster
  • 9,143
  • 2
  • 28
  • 25
8

Once the bare repository has the shared=group flag, git will take care of the rest, so the following has to be done only once. Also setgid is deprecated for this use. Here I copy/paste my answer from serverfault:

Assuming repogroup is your group, and you have cd to the repo directory:

First change the shared flag to group:

git config core.sharedRepository group 

Note: here you must use the keyword group, not the group name. This is equivalent to creating the bare repository with option --shared=group.

Then change the group for the whole repository:

chgrp -R repogroup .

To make sure that existing directories are group-writable (g+w), and existing executables also become group-executables (g+X) you also need to:

chmod -R g+wX .

Once you have done this, git will honor the shared=group flag and take care of group permissions in the following, both for existing and new files, so you'll never need again to umask or chgrp.

I'll put the source in a comment if I find it back.

Community
  • 1
  • 1
ggll
  • 963
  • 10
  • 13
  • you state "setgid is deprecated for this use.", could you provide a pointer to the rationale for this statement which would be really helpful, otherwise it's just hearsay - and you've not proposed an alternative to setgid. Using ACLs (`setfacl` etc) might be one approach but it's not available or enabled on all filesystems. – Andrew Richards Feb 03 '23 at 17:12
5

I had to use a combination from the above answers:

git config core.sharedRepository group
chgrp -R GROUP /path/to/repo
find /path/to/repo -type d -exec chmod g+rwxs {} \;
chovy
  • 72,281
  • 52
  • 227
  • 295