Gitosis - manage git repositories sanely
I’ve finally made all my projects available publicly via git at http://git.mivok.net/ thanks to gitosis. Before that, I kind of just thrown everything in a git directory under my home directory and accessed it over ssh, which worked fine for private repositories, but fell flat whenever I wanted to make something available to somebody else.
Gitosis promised to make it easy to add new repositories and set up access for new people as needed, and once everything is set up, it is really easy - everything is contained in a config file inside a git repository, so you can make changes locally and push. You also have the benefit that your changes themselves are under version control. However, there were a few hiccups along the way, so I’m going to describe what I did in case others try and hit the same problems I did.
Gitosis uses python and setuptools, which I already had available. I’m running Ubuntu, so installing any requirements is as simple as running:
aptitude install python python-setuptools
Of course, git itself is a requirement. For now we’ll use the Ubuntu package, but it’s a good idea to build from source if you want the latest version:
aptitude install git-core
Next, get the gitosis source:
git clone git://eagain.net/gitosis.git
and install:
cd gitosis
sudo python ./setup.py install
So far, everything is pretty straightforward. Next we need to add a user that everyone will connect as in order to access repositories. The main method gitosis uses for accessing repositories, is to have a single user that everyone connects to over ssh. Logins are only allowed via ssh keys, and anyone who connects is restricted to running gitosis commands, preventing them from accessing anything they shouldn’t.
sudo adduser --system --shell /bin/sh --gecos 'git user' \
--group --disabled-password --home /srv/git git
Here I’ve set the home directory to /srv/git
. This directory will hold all
repositories and gitosis files. Next we need to initialize this directory with
all of the gitosis configuration files:
sudo -H -u git gitosis-init < your-ssh-key.pub
(the -H option to sudo sets the HOME variable to the user you are running commands as. In this case - /srv/git).
The your-ssh-key.pub
file should be your ssh public key for the computer you
are working on now. You will use this to access the administration repository
and any other repositories you create later. If you don’t have an ssh key set
up already, make one now and copy the id_rsa.pub
file to the server before
running the above command:
ssh-keygen -t rsa -b 4096
For more information on ssh-keys, see the ssh-keygen man page.
Note: by default, gitosis takes the comment field of your ssh key to be your
username. In my case, it was mark@laptop, and I would have had to use
mark@laptop as my username whenever editing permissions. If you want something
nicer, edit the copy of your public key before running the gitosis-init
command and change the comment field to something a little nicer.
Now you have the basic server set up. To edit the configuration, clone the administration repository:
git clone git@your-server.example.com:gitosis-admin.git
Then you can edit the gitosis.conf file, commit it, and push back to the server.
At this point I hit my first snag. Any changes pushed back to the server didn’t take effect. The magic updating of settings wasn’t working. After some hunting around (read: typing stuff into Google and clicking frantically), I found that all of the magic is done via a hook on the gitosis-admin repository. For some reason, the hook script wasn’t executable, and so never ran. Before committing any configuration changes, make sure to fix the permissions on the repository hook:
sudo chmod +x /srv/git/repositories/gitosis-admin.git/hooks/post-update
The basic gitosis setup at this point is complete. Aside from adding
repositories and new users, the other steps are optional. However, we are
talking about making repositories publicly accessible, and the other two
steps - setting up git://
access via git-daemon
and setting up gitweb will
do this.
First though, here’s a quick overview on adding users/repositories.
To add a new user, get a copy of their ssh public key (ssh keys are what makes
the whole thing work), and copy it to your gitosis-admin checkout inside the
keydir
directory. Name the file USERNAME.pub
, replacing the username with
the name of the user you wish to add - this is the username you will use when
setting permissions. For example, if you add joe.pub
, then you will use joe
as the username in the configuration below.
To add a repository, you just give somebody permission to access it and then push. This involves editing the gitosis.conf and adding a few lines:
[group foo]
writable = myrepository
members = joe
This allows user joe to write to myrepository.git. You then add this as a remote in your local repository and push to create the repository on the server:
cd path/to/my-repository
git remote add origin git@your-server.example.com:myrepository.git
git push
This assumes you actually have something to push. In practice this isn’t an
issue - you start with a blank local repository (using git init
), commit
your first changes, and push. The first person to push actually creates the
repository.
Setting up git:// access
This part allows people to clone a repository without needing to authenticate, and without having to generate ssh keys. You can’t push to repositories in this way however - you have to use ssh if you want to push back to a repository. Chances are, you don’t want all repositories to be public, and gitosis allows you to pick and choose which you make public and which you make private using (wait for it…) the gitosis.conf file.
Setting up git:// access is as simple as running the git-daemon command:
sudo -u git git-daemon --base-path=/srv/git/repositories/
If you’re running Ubuntu however, gitosis comes with a nice script that you just drop in to /etc/event.d, edit to change the path, and it will start the git-daemon automatically on boot:
sudo cp gitosis/etc-event.d-local-git-daemon /etc/event.d/local-git-daemon
sudo sed -i s+/srv/example.com/git+/srv/git+ /etc/event.d/local-git-daemon
sudo initctl start local-git-daemon
The initctl script starts the daemon without rebooting, which is usually a good thing.
By default, no repositories are made public. To make them public, you need to
add a daemon = yes
option to your gitosis.conf:
[repo myrepository]
daemon = yes
Here we have made a new repo
section for myrepository. Save the gitosis.conf
file, commit, push, and you should be able to clone myrepository using
git://your-server.example.com/myrepository.git
.
Gitweb - making everything look pretty
The final step is getting gitweb working. For this you need a copy of
gitweb.cgi and associated files. I built git from source, and gitweb.cgi was
built as part of this, but if you didn’t do this, there is an Ubuntu package
available called gitweb
. I also use lighttpd on my server, with pages stored
under /srv/www/domain.example.com/pages/
so I’ll be describing a
configuration for that server and layout.
First, copy gitweb.cgi
, gitweb.css
, and all of the images to
/srv/www/domain.example.com/
. I put the css files and images inside a
pages
subdirectory (the document root), and put gitweb.cgi
inside a
separate cgi-bin
directory outside of the document root.
Next, configure lighttpd. I have simple-vhost set up which sets the document root based on the domain name requested, so we only need to do special set up for the git/cgi parts:
$HTTP["host"] =~ "^git\.your-server\.example\.com$" {
url.redirect = (
"^/$" => "/gitweb/",
"^/gitweb$" => "/gitweb/"
)
alias.url = (
"/gitweb/" => "/srv/www/git.your-server.example.com/cgi-bin/gitweb.cgi",
)
setenv.add-environment = (
"GITWEB_CONFIG" => "/srv/www/git.your-server.example.com/gitweb.conf",
)
$HTTP["url"] =~ "^/gitweb/" { cgi.assign = ("" => "") }
}
Gitosis does provide a config file for lighttpd, but it wasn’t appropriate for
my setup. Note that the above needs the following modules loaded: mod_alias
,
mod_cgi
, mod_redirect
, mod_setenv
.
Gitweb.cgi needs editing slightly in the above configuration, by default it looks for the css file in the same location as the gitweb.cgi file (i.e. in a /gitweb/ dir), but they are stored at the root of the site. Open up gitweb.cgi and search for gitweb.css. Add a slash before the filename and save the file.
Next is creating a gitweb.conf file. Again, gitosis helps out here, providing
a gitweb.conf
file that just needs some tweaking with the right paths.
Copy the gitweb.conf
file from the gitosis source distribution to
/srv/www/git.your-server.example.com/
, and open it up for editing.
Edit the $projects_list
, $projectroot
, and the @git_base_url_list
lines and save:
$projects_list = '/srv/git/gitosis/projects.list';
$projectroot = "/srv/git/repositories";
@git_base_url_list = ('git://your-server.example.com');
By default, gitosis creates repositories that are only accessible by the git user and users in the git group, so we need to give the web server permissions to access repositories. If this isn’t done, gitweb will say that there are no repositories available even when you configure web access in gitosis for the repository.
usermod -G git www-data
You will need to restart the web server after this in order for the group
change to take effect. If your web server is running as someone else other
than www-data
, change the above command appropriately.
Finally, to give access to a repository via gitweb, the process is similar to
setting up git:// access. Edit gitosis.conf, and add a gitweb = yes
line
next to the daemon = yes
line for the repository. Commit, push, and the
repository should now show up in gitweb. In the default configuration, you need
to have both daemon = yes
and gitweb = yes
for a repository to be made
available via gitweb. See the gitweb.conf
file if you want to change this.