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
.gitdirectory 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,importandlistscripts yourself. If you add ahelpscript, 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
publishandunpublishscript 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
publishscript