git 1.7, apache2 über https mit smart-http
git 1.7, apache2 über https mit smart-http
git
ist svn
in vielen Belangen überlegen. Am Eindrücklichsten werden die Vorteile von git von Linus Torvalds, dem Autor von git
, erklärt. Es gibt etliche Tutorials und Einführungen zu git
.
Seit git
-Version 1.6.6 kann man ein remote repository sehr effizient über http(s) betreiben, wenn man smart-http
aktiviert. Dies geht, indem man das cgi-Modul von git
in einen Webserver einbaut. Dieser Weg ist ähnlich effizient wie git
über ssh
oder über das git
-Protokoll.
Schön ist, dass man für jedes repository einen eigenen apache-vhost verwenden kann. So sind alle Haupt-Projekte sauber voneinander getrennt und haben ihre eigene Benutzerverwaltung. Die Benutzerverwaltung kann natürlich auf alle Arten, die der Apache beherrscht, erfolgen, z.B. LDAP. Im Beispiel verwenden wir Digest-Dateien, man könnte aber auch htpasswd
verwenden, solange man ausschließlich https benutzt (hier wird das Passwort verschlüsselt übertragen).
Außerdem müssen keine System-Benutzer für die Verwendung von ssh
angelegt werden.
Server-Konfiguration (hier: debian squeeze 6.0)
Voraussetzung: apache2
ist bereits installiert. HTTPS verfügbar, Zertifikate stehen bereit (hier: nicht self-signed)
apt-get install git-core
Datei erzeugen: /etc/apache2/sites-available/git.example.com-ssl
<VirtualHost *:443>
ServerName git.example.com
DocumentRoot /var/www/git.example.com/git
ErrorLog /var/log/apache2/error-git.log
CustomLog /var/log/apache2/access-git.log common
<Location />
AuthType Digest
AuthName git
AuthDigestDomain /
AuthDigestProvider file
AuthUserFile /var/www/git.example.com/password/users.digest
Order allow,deny
Deny from all
Satisfy any
Require valid-user
</Location>
SetEnv GIT_PROJECT_ROOT /var/www/git.example.com/git
SetEnv GIT_HTTP_EXPORT_ALL
# 64 bit only!
ScriptAlias / /usr/lib64/git-core/git-http-backend/
SSLEngine on
SSLProtocol all
SSLCipherSuite HIGH:MEDIUM
SSLCertificateFile /etc/ssl/certs/example_com.crt
SSLCertificateKeyFile /etc/ssl/private/example_com.key
SSLCertificateChainFile /etc/ssl/certs/RapidSSL_Intermediate_CA.pem
SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
</VirtualHost>
a2ensite git.example.com-ssl
mkdir /var/www/git.example.com
cd /var/www/git.example.com
mkdir password
htdigest -c password/users.digest git newuser
mkdir git
cd git
Im Folgenden wird ein git
Repository erzeugt. git
Push ist ab Version 1.7 nur noch mit repositories möglich, die mit --bare
erzeugt wurden. Das erzeugte Repository ist insofern keine Arbeitskopie.
git init --bare
Schreibrechte für apache-Benutzer setzen:
cd ..
chown -R www-data git
service apache2 restart
Update debian squeeze auf wheezy
Der Skriptalias lautet jetzt:
ScriptAlias / /usr/lib/git-core/git-http-backend/
statt
ScriptAlias / /usr/lib64/git-core/git-http-backend/
Danach apache
neu starten:
service apache2 restart
Für jedes repository ist Folgendes zu tun:
cd var/www/git.xyz.de/git/<repo-name>
git update-server-info
mv hooks/post-update.sample hooks/post-update
git config http.receivepack true
chown -R www-data *
Hierbei werden folgende Probleme gelöst:
Mit dem neuen ScriptAlias
wird das git-http-backend
wieder richtig eingebunden.
git update-server-info
löst folgenden Fehler:
fatal: https://git.xyz.de/git/<repo>/info/refs not found: did you run git update-server-info on the server?
.git/hooks/post-update
erledigt ein update-server-info
automatisch bei Änderungen
http.receivepack true
erlaubt pushes. Ansonsten kommt folgender Fehler:
error: Cannot access URL https://heinz@git.xyz.de/git/<repo>/, return code 22. fatal: git-http-push failed
Multible Projekte -> Multible repositories
git betrachtet jedoch immer das komplette Projekt, nie einzelne Dateien. Man kann daher nicht wie bei svn einzelne Unterverzeichnisse auschecken. Daher sollte man jedes Projekt in ein eigenes repository legen. Dieser Schritt ist nicht nötig, wenn man nur ein Projekt verwendet (wie im Beispiel oben) oder wenn man jedes Projekt in seinen eigenen apache vhost legt (auch wie im Beispiel)
Auf dem Server lassen sich die verschiedenen repositories in einem apache vhost z.B. so anlegen:
cd /var/www/git.example.com/git
mkdir projectA
cd projectA
git init --bare
cd ..
chown -R www-data projektA
mkdir projectB
cd projectB
git init --bare
cd ..
chown -R www-data projektA
usw. Beim Auschecken muss man dann das entsprechende Projekt angeben:
git clone https://git.example.com/projectA projectA
Client-Installation (hier: Ubuntu natty 11.04)
git
installieren:
sudo apt-get install git
In $HOME/.netrc
kann das Login festgelegt werden:
machine git.example.com
login newuser
password newuserpass
Rechte setzen:
chmod 600 ~/.netrc
Namen und E-Mail hinterlegen
git config --global user.name "Your Name Comes Here"
git config --global user.email you@yourdomain.example.com
vim
als Standard-Editor festlegen
git config --global core.editor vim
Syntax Highlighting (farbige Formatierung)
git config --global color.branch auto
git config --global color.diff auto
git config --global color.interactive auto
git config --global color.status auto
master-Branch erstellen
Da wir Server-seitig keine Arbeitskopie haben, müssen wir den master
-Branch Client-seitig erstellen. Dies wird gemacht, indem auf dem Client ein erster commit gemacht wird:
Lokale Arbeitskopie des repositories vom Server herunterladen:
git clone https://git.example.com tmpgit
cd tmpgit
Änderung machen und lokal committen:
touch readme
git add readme
git commit -a
Aktuelle Branches anzeigen:
git branch
liefert die Ausgabe
* master
master branch mit auf den Server hochladen:
git push origin master
cd ..
Workflow
Mit diesem Workflow werden Änderungen für ein neues Feature zunächst in einem neuen lokalen Branch gemacht. Dort kann beliebig oft committed werden (lokal und remote), ohne den master-Branch anzufassen. Wenn das Feature fertig ist, wird in den master-Branch gemerged. Lokale Arbeitskopie herunterladen (clone
) oder bestehende Arbeitskopie aktualisieren (pull
):
git clone https://git.example.com gitdir
cd gitdir
git pull
Statt git pull kann man auch erstmal die Änderungen prüfen:
git fetch
git diff master origin/master
git merge origin/master
Neuen Branch namens new-feature
erzeugen, wechseln in new-feature
git checkout --track -b new-feature
Nun können Änderungen am Quellcode erfolgen, wobei Dateien unter Versionskontrolle zu stellen sind. Beispiel:
touch readme
git add readme
In branch new-feature
committen (nur lokal!), dann den branch new-feature
auch ins remote repository stellen (Optional. git push
funktioniert ab Version 1.7 nur mit einem bare repository (s.o))
git commit -a
git push origin new-feature
Andere Team-Mitglieder können jetzt diesen remote branch auschecken und können darauf mit git pull
und git push
arbeiten, ohne den master
branch anfassen zu müssen.
Wechseln auf master
-Branch (im selben Verzeichnis sieht man nun wieder den alten Stand vom master
-Branch):
git checkout master
git merge new-feature
Jetzt sind alle Änderungen des Branches new-feature
auch im Branch master
und mit einem
git push
auch im master
-Branch des Remote Repositories.
Remote Branch auschecken
git clone
checkt immer den default Branch aus. Dieser lässt sich pro Repository festlegen und verweist meistens auf den master
Branch bzw. auf den letzten Entwicklungsstand. Wenn man jedoch an einem anderen Branch arbeiten möchte, muss man diesen so auschecken:
default branch auschecken:
git clone https://example.com/ gittest
cd gittest
git branch
zeigt hierbei nur den default
Branch an (hier entsprechend den master
Branch):
* master
Man kann jedoch auch alle Branches, inklusive der Remote Branches, anzeigen:
git branch -a
Remote Branch experimental
auschecken:
git checkout --track -b experimental origin/experimental
Jetzt arbeitet man in der lokalen Arbeitskopie auf dem Branch experimental
.
Branch löschen
Branch new-feature
im lokalen Repository löschen:
git branch -d new-feature
Branch new-feature
im Remote Repository löschen:
git push origin :new-feature
Weitere git Kommandos
Datei untracken (Datei wird danach nicht mehr committed. Datei wird trotz rm
nicht gelöscht). Alternative: Von Anfang an .gitignore
benutzen.
git rm --cached filename
Versionstag setzen:
git tag -a v0.1
Tags auflisten:
git tag -l
Tag löschen:
git tag -d v0.1
Letzte Commit-Kommentare verändern, Commits zusammenfassen
git rebase -i HEAD~5
Log formatieren (hier Datum und Commit-Text):
git log --date=short --pretty="tformat:%ad %s"
Benutzerverwaltung
git verfügt selbst über keine Benutzerverwaltung. In Verbindung mit smart-http
kann man zunächst nur die Authentifizierungsmechanismen des Apache-Webservers benutzen. Hiermit lässt sich immerhin über eine Passwort-Datei definieren, wer Zugriff auf ein Repository bekommt.
Immerhin müssen in Verbindung mit der Apache-Authorisierung keine Systembenutzer angelegt werden, was z.B. bei der Verwendung von ssh
nötig wäre.
Benötigt man eine feingranularere Benutzerverwaltung, bietet sich die Verwendung von gitolite an. Dieses funktioniert in neueren Versionen auch mit smart-http
.