How to make a git server/website
Basic ssh server
Every repository on the server will be owned by a git user.
useradd -m git
Create a new directory to store the repositories owned by the git user.
mkdir /srv/git
chown git:git /srv/git
Login as the git user so the new repositories will be owned by him.
su git
cd /srv/git
Creating a repository
They will be stored as bare, meaning we will only store the .git
folder not the actual files (called the workspace) to save space.
It’s a convention to to suffix a bare repository with the .git
extension.
mkdir repo.git
cd repo.git
git init --bare
Or clone a distant one:
git clone --bare <location>
Look at the content of a bare repository and the
.git
directory in a regular one to convince yourself that they’re the same.
SSH Authentication
You could add a password for the git user but it’s ultimately safer to user a key pair.
If you don’t know what that is you generate it with ssh-keygen
.
Follow the steps and it will create id_rsa
(private key) and id_rsa.pub
(public key) in ~/.ssh
.
On your server you append your public key to /home/git/.ssh/authorized_keys
At this point you should be able to login as the git user via ssh
ssh git@<host>
You can clone from your server.
git clone git@<hostname>:/srv/git/<reponame>.git
Better server interaction with git-shell
Permitting the git user to have a regular shell can be too permissive, we would like to restrict him to a few repository actions, like creation/deletion, importing (clone), listing.
echo $(which git-shell) >> /etc/shells` # Register the git-shell as a valid shell
chsh -s $(which git-shell) git # Change the shell of the git user
If you try to ssh as the git user, you will be greeted with something along the line of:
fatal: Interactive git shell is not enabled.
hint: ~/git-shell-commands should exist and have read and execute access.
Connection to <host> closed.
As suggested by the hint we have to create the directory /home/git/git-shell-commands
and put the commands (executable) available to the git user.
#!/bin/sh
[ $# -ne 1 ] &&
echo "Usage: $0 repository" && exit 1
repo_path="/srv/git/$1.git"
[ -d "$repo_path" ] &&
echo "$0: Error: $repo_path already exist" && exit 2
mkdir "$repo_path"
git -C "$repo_path" init --bare
This script create a new repository in /srv/git
.
Put it under git-shell-commands/create
and make it executable then try to ssh as the git user once again.
You will be prompted with git>
, you can only execute the create <repository>
and exit
command.
You can probably create the
delete
,import
andlist
scripts yourself. If you add ahelp
script, it will be ran at the beginning of the connection. It can be used to add a greeting message.
Allow anyone to clone with git-daemon
Cloning with ssh is fine but only the people with ssh access can do it, we would like anyone to clone.
git-daemon does precisely that, after running it you will be able to run git clone git://<host>/<repository>
git daemon --reuseaddr --base-path=/srv/git/ /srv/git/
Follow the instruction of this tutorial if you want to know how to make it a service
Public/private repository
You may want to introduce a public/private distinction for your repositories.
A simple way to do this is by creating a public
directory in /srv/git
which will contain symbolic link to the repository in /srv/git
.
/srv/git/
|- foo.git/
|- bar.git/
|- qux.git/
|- public/
|- foo.git -> /srv/git/foo.git
|- bar.git -> /srv/git/bar.git
Change the git daemon to only serve the public repositories
git daemon --reuseaddr --base-path=/srv/git/public /srv/git/public
.
Add a
publish
andunpublish
script ingit-shell-commands/
.
Generate a static website
Here we will create a site that look’s like this with nginx, stagit and a few scripts. If you don’t like the minimalist appearance of the site, here is a list of alternatives.
nginx
server {
root /var/www/git; # where our website's files will be located
index index.html;
# It's a convention to put it in a git. subdomain.
server_name git.<hostname> www.git.<hostname>;
location / {
try_files $uri $uri/ =404;
}
}
Put this configuration file in /etc/nginx/sites-available
.
Enable the site ln -s /etc/nginx/sites-available /etc/nginx/sites-enable
stagit
Stagit is pretty small tool so it won’t take long to install it from sources.
git clone git://git.codemadness.org/stagit
cd stagit
make
make install
stagit /path/to/repository
. - generate a static pages for a repository in the current directory.stagit-index repo1 repo2 repo3 > index.html
- generate an index for multiple repositories.
Read the man page of both of these commands for more information
git hooks
Git hooks are scripts located in <repository>/.git/hooks
that will be run on a certain action.
The hook we’re interested in is post-receive
, it will be ran after someone pushes to the repository.
We can use it to regenerate the repository’s pages and the website’s index.
#!/bin/sh
# Insert repo_name variable here
# <REPO_NAME> -- replace with repo_name=name
[ -z "$repo_name" ] && exit 1
[ ! -d "/srv/git/public/$repo_name.git" ] && exit
repo_web_path="/var/www/git/$repo_name"
mkdir -p "$repo_web_path"
cd "$repo_web_path" || exit 1
stagit "/srv/git/$repo_name.git"
stagit-index /srv/git/public/* > /var/www/git/index.html
This is a template for the post-receive
hook.
Every time you publish a repository you can change his post-receive
hook.
post_receive_path="<repository>/hooks/post-receive"
sed '/REPO_NAME/ c repo_name='"$repo" < post-receive.template > "$post_receive_path"
chmod +x "$post_receive_path"
"$post_receive_path"
Add this code to your
publish
script