Install and Configure a Public git Repository
This explains how to install and configure a public git server that can host multiple projects providing read-only anonymous access and read/write for authenticated commiters, along with the gitweb web-browser interface.
Install
On Ubuntu this is quite simple:
sudo apt-get install git-core git-daemon-run gitweb
You might want to update to the latest version from git's own repository.
git clone git://git.kernel.org/pub/scm/git/git.git cd git
Build the latest release
Easy way to ensure build dependencies are installed for stand-alone source that has an earlier Ubuntu/Debian? package:
sudo apt-get build-dep git-core
Build using the same options as the Ubuntu package uses ( extracted from Ubuntu build logs)
/usr/bin/make all test \
CC='gcc' CFLAGS='-g -Wall -O2' NO_OPENSSL=1 GITWEB_CONFIG=/etc/gitweb.conf \
prefix=/usr mandir=/usr/share/man INSTALLDIRS=vendor WITH_P4IMPORT=1 \
PYTHON_PATH=/usr/bin/python TCLTK_PATH=/usr/bin/wish8.4
/usr/bin/make -CDocumentation man ASCIIDOC8=YesPlease
/usr/bin/make -CDocumentation man html ASCIIDOC8=YesPlease
Install using the same options:
usr/bin/make install install-doc \
CC='gcc' CFLAGS='-g -Wall -O2' NO_OPENSSL=1 GITWEB_CONFIG=/etc/gitweb.conf \
prefix=/usr mandir=/usr/share/man INSTALLDIRS=vendor WITH_P4IMPORT=1 \
PYTHON_PATH=/usr/bin/python TCLTK_PATH=/usr/bin/wish8.4
Configure
Firewall
These rules need adding to the netfilters/iptables start-up scripts (usually in /etc/iptables.up.rules).
Allow access to port 9418 for TCP
# git-daemon -A INPUT -p tcp -m tcp --dport 9418 -j ACCEPT
To provide secure encrypted authenticated access for commiters you might want to ensure SSH (port 22) is allowed. (However, in some circumstances it is better to leave port 22 closed on public interfaces and only provide SSH access through a virtual private network tunnel using OpenVPN or similar):
# For git over ssh (allows push) -A INPUT -p tcp -m tcp -s 84.12.34.240/29 --dport 22 -j ACCEPT
Ensure the firewall rules are being enabled when the network starts. Usually that is using a post-up rule in the network configuration.
/etc/network/interfaces
# The first network card - this entry was created during the Debian installation
# (network, broadcast and gateway are optional)
iface eth0 inet static
address 10.1.2.3
netmask 255.255.255.0
gateway 10.1.2.254
post-up iptables-restore < /etc/iptables.up.rules
git-daemon
The git-daemon-run package installs a runit service in /etc/sv/git-daemon/. Edit the run file and set the paths for virtual hosting. Because I provide for a git repository for each domain account I use the interpolated-path option to extract the hostname the git client connected to and build the path based on it. This is rather like apache's VirtualHost where the site presented is determined by checking the Host: header. In this case it is git repositories not web sites that can share the same IP address:
/etc/sv/git-daemon/run
#!/bin/sh exec 2>&1 echo 'git-daemon starting.' exec /usr/lib/git-core/git-daemon --syslog --verbose --base-path=/home --interpolated-path=/home/%H/git%D
Once you've created some public repositories, confirm the service is running using something like this:
git ls-remote git://tjworld.net/linux-2.6-tegra-adam bc91e98a9822e4c5c390e87257fbc5829457af6c refs/heads/smba1002_10.9.7
Create per-account directories
First create 'base' directories in all home directories with correct ownership:
sudo su
awk -F: '$3 > 999 && substr($6,1,5) == "/home" {print $3,$4,$6}' /etc/passwd | while read account; \
do AUID=${account%% * /home*}; AGUID=$(expr "${account}" : '.* \([0-9]\+\) .*'); DIR=${account##* }; \
[ ! -e ${DIR}/git ] && mkdir ${DIR}/git && chown $AUID:$AGUID ${DIR}/git; done
exit
Or, if doing it manually for each user account:
cd ~ mkdir git
Create repositories
Create empty repository and make it ready for public access. Set ${HOST_DOMAIN} and ${PROJECT} appropriately:
export GIT_DIR="/home/${HOST_DOMAIN}/git/${PROJECT}.git"
git-init
Enable public access
To enable a repository to be available to anonymous public access:
touch $GIT_DIR/git-daemon-export-ok
Enable gitweb
The Perl git-web script allows web-browsing of the repository. After following these instructions it will be available at http://${HOST_DOMAIN}/perl/gitweb.cgi
Name the repository
To avoid gitweb reporting the project name as:
Unnamed repository; edit this file to name it for gitweb.
Edit the repository's description file and make it more descriptive:
echo "Experimental branch" > ${GIT_DIR}/description
Install Perl prerequisites
Some preparation is required to support gitweb fully. The primary issue is that if the apache VirtualHost is using suexec to impose security it is not possible to pass environment variables to CGI scripts, and therefore gitweb can't be told to use a per-account configuration using GITWEB_CONFIG. An additional issue is that by default all Perl scripts will be handled by the cgi-bin handler mod_cgid. For performance it would be better to have mod_perl installed.
Install mod_perl and supporting Perl bundles needed by apache:
sudo apt-get install libapache2-mod-perl2
Create a server-wide apache Perl configuration. As root create this file:
/etc/apache2/mods-available/perl.conf
PerlModule ModPerl::Registry
Create a symbolic link to it so apache reads it at start-up:
sudo su cd /etc/apache2/mods-enabled ln -s ../mods-available/perl.conf perl.conf exit
Per-account gitweb configuration
In the user's git directory create a link to the gitweb system installation directory:
cd ~ ln -s /usr/share/gitweb git/gitweb
Copy the default configuration file so the site settings can be customised:
cd ~ cp /etc/gitweb.conf git/gitweb.conf
Edit git/gitweb.conf and set values for the user account. Set the path to the supporting files to something other than the root of the web site to avoid clutter. Comment out the favicon setting if the site is using its own. Replace ${HOST_DOMAIN} with the correct path:
# path to git projects (<project>.git)
$projectroot = "/home/${HOST_DOMAIN}/git";
# directory to use for temp files
$git_temp = "/tmp";
# target of the home link on top of all pages
$home_link = $my_uri;
# html text to include at home page
$home_text = "indextext.html";
# file with project list; by default, simply scan the projectroot dir.
$projects_list = $projectroot;
# stylesheet to use
$stylesheet = "gitweb.css";
# logo to use
$logo = "git-logo.png";
# the 'favicon'
# $favicon = "git-favicon.png";
Add the GITWEB_CONFIG environment variable to the web-site's configuration file so that gitweb uses per-site configuration rather than the global configuration set in /etc/gitweb.conf. Also add Alias and Location directives. Replace ${HOST_DOMAIN} with the correct path.
/etc/apache2/sites-available/${HOST_DOMAIN}.conf:
SetEnv GITWEB_CONFIG /home/${HOST_DOMAIN}/git/gitweb.conf
Alias /gitweb/ /home/${HOST_DOMAIN}/git/gitweb/
<Location /gitweb/*.cgi>
SetHandler perl-script
PerlHandler ModPerl::Registry
Options +ExecCGI
PerlSendHeader On
allow from all
</Location>
Allow a default index page if a web browser navigates to /gitweb/ rather than the real /gitweb/index.cgi. Add "index.cgi" to DirectoryIndex in the web-site's configuration file:
DirectoryIndex index.php index.html index.py index.cgi
Restart the server.
sudo apache2ctl restart
Use
Accessing the web interface
Browse to http://${HOST_DOMAIN}/gitweb/
Updating the Public Repository
To push your local private repository to the remote public repository there are several options. If you have enabled SSH access then:
To update the remote branch master from the local branch of the same name:
cd /home/all/Projects/packeteer git push ssh://tjworld.net@tjworld.net/~tjworld.net/git/packeteer.git master Password: Counting objects: 21, done. Compressing objects: 100% (21/21), done. Writing objects: 100% (21/21), 5.47 MiB | 42 KiB/s, done. Total 21 (delta 2), reused 0 (delta 0) refs/heads/master: 0000000000000000000000000000000000000000 -> f499ede17792694ddcd25fed589e794a72ee35fa To ssh://tjworld.net@tjworld.net/~tjworld.net/git/packeteer.git * [new branch] master -> master
If you don't use public ssh but have a VPN connection then you might do something like this:
cd ~ mkdir remote # mount remote server in local file-system sshfs tjworld.net@vpn.lan.tjword.net ~/remote cd /home/all/Projects/packeteer git status # On branch master nothing to commit (working directory clean) git push ~/remote/git/packeteer.git master
Note: This method of using an sshfs mount seems to confuse git. It seems to take much longer to push the change, and it creates a new local branch entry that matches the remote repository path. For that reason it is better to use the ssh protocol but to the private VPN host:
git push ssh://tjworld.net@vpn.lan.tjworld.net/~tjworld.net/git/packeteer.git master
Cloning Public Repository by Other Developers
Anyone who wants a copy of the public repository does a simple clone:
git clone git://tjworld.net/packeteer.git
Collaborating
If another developer has a clone of the public repository already and you have published a change, they update using:
git fetch
If you are testing experimental code you might have a branch for it:
git branch experimental git checkout experimental Switched to branch "experimental" echo "Editing files for experimental code" >> changelog git add changelog git commit -a -s -m "Experimental commit" Created commit 98bc7fa: Experimental commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 changelog git push ~/remote/git/packeteer.git experimental Counting objects: 4, done. Compressing objects: 100% (2/2), done. Writing objects: 100% (3/3), 357 bytes, done. Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. To ~/remote/git/packeteer.git * [new branch] experimental -> experimental
The other developer might then update their clone:
git fetch
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2)remote: , done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From git://tjworld.net/packeteer.git
* [new branch] experimental -> origin/experimental
git branch -r
origin/HEAD
origin/experimental
origin/master
git checkout origin/experimental
Note: moving to "origin/experimental" which isn't a local branch
If you want to create a new branch from this checkout, you may do so
(now or later) by using -b with the checkout command again. Example:
git checkout -b <new_branch_name>
HEAD is now at 98bc7fa... Experimental commit
git log -1
commit 98bc7fa8777160f0849b4e78f8522a9ae9ce2497
Author: TJ <linux@tjworld.net>
Date: Sun Apr 20 20:24:30 2008 +0100
Experimental commit
Signed-off-by: TJ <linux@tjworld.net>
Quickly Create New Public Project Repository
GIT_DIR="/home/${HOST_DOMAIN}/git/${PROJECT}.git"
git-init
touch $GIT_DIR/git-daemon-export-ok
echo "Project Name" > ${GIT_DIR}/description
