git ist das Versions-Kontroll-System, das derzeit unter anderem für den Kernel Linux verwendet wird.
Homepage: http://git-scm.com/
Lizenz: GPLv2
Tipps & Tricks
Mini-Howto
Wenn man bei einem Projekt mitarbeiten will, holt man sich erst einmal einen Klon ("clone") des Projekts auf den eigenen Rechner. Dazu verwendet man z.B. den Befehl "git clone git://git.sv.nongnu.org/akfavatar.git". Dann ändert man, was man ändern möchte. Wenn es nicht so ganz klappt, kann man eine Datei auch wieder in einen früheren Zustand zurückversetzen, zum Beispiel mit "git checkout -- avatar.c". Man kann sich zwischendurch seine Änderungen auch anzeigen lassen: "git diff". Wenn nun alles so ist, wie man es haben möchte, dann sollte man erstmal die bearbeiteten Dateien zum Einpflegen ("Einchecken") vorbereiten: "git add avatar.c akfavatar.h", und dann kann man seine Änderungen einpflegen ("einchecken"): "git commit -m "dies und jenes geändert"".
Das bisher erläuterte läuft alles auf der lokalen Kopie, die man auf den eigenen Rechner geladen hat. Wenn man seine Änderungen nun an den oder die Hauptentwickler schicken will, kann man sich eine Differenzdatei ("Patch") erstellen lassen: "git format-patch origin/master". Den schickt man dann an die Hauptentwickler.
Um mit der Entwicklung der anderen mitzuhalten, kann man sich mit dem Befehl "git pull origin" seine Kopie aktualisieren. Git weiß dann schon, wo es das herbekommt. Man muss sich dafür nur in dem Verzeichnis befinden, das man sich vorher schon einmal mit "clone" geholt hat.
Kurzreferenz
git init
- Erstellt ein Repository
git add [Datei/Verzeichnis]
- Stellt eine Datei oder ein Verzeichnis unter Versionsverwaltung.
git commit -a -m '[Kommentar]'
- Versioniert alle Dateien, die zuvor markiert wurden und verändert sind, und fügt einen Kommentar hinzu.
git checkout [Version oder Branch]
- Wechselt zu einer bestimmten Version oder einem Zweig ("branch").
git clone [--bare]
- Erstellt eine Kopie eines Repositorys
git pull [Repository]
- Holt die Änderungen in das eigene Repository
git push [Repository]
- Überträgt die Änderungen am lokalen Repository in ein anderes.
git branch [name]
- Erstellt einen lokalen Zweig ("branch")
git merge [branch]
- Verschmelzt zwei Zweige miteinander.
git branch -d/-D [branch]
- Löscht einen Versionszweig.
git diff [version] [version]
- Vergleicht zwei Versionen miteinander.
git log [-n 10]
- Zeit die Versionsgeschichte (letzte 10 Einträge).
git status
- Zeigt, ob Änderungen noch nicht gespeichert wurden.
git gc
- Räumt das Repository auf.
git mv [alter Name] [neuer Name]
- Benennt Dateien und Verzeichnissen um.
git rm [name]
- Löscht Dateien und Verzeichnisse.
git tag [name]
- Markiert eine Version mit einen Namen.
git ls-files
- Listet alle Dateien unter Versionsverwaltung auf.
Tutorial für Einsteiger
Ziel dieses Tutorial ist es, Einsteigern einen kleinen Einblick in Git zu geben.
Da es sich bei Git um ein dezentralisiertes Versions-Kontroll-System handelt, ist es möglich, Git nur "lokal" oder auch über mehrere Repositorys zu verwenden. Wir werden mit den lokalen Operationen anfangen.
Die Grundidee ist, alle Dateien in einem Aufbewahrungsort (Repository) zu verwalten. Hier werden die Dateien und deren Änderungen gespeichert und versioniert.
Mein kleines Projekt
Im folgenden Beispiel wird ein neues Projektverzeichnis eingerichtet, dieses soll in Zukunft versioniert werden.
user@host:~$ mkdir ~/MeinProjekt user@host:~$ cd ~/MeinProjekt/
user@host:~/MeinProjekt$ git init Initialized empty Git repository in /home/user/MeinProjekt/.git/ user@host:~/MeinProjekt$
Herzlichen Glückwunsch. Sie haben ihr eigenes Git-Repository erstellt!
Der nächste Schritt ist die Konfiguration. Im folgenden werden Namen und E-Mail-Adresse gesetzt.
user@host:~/MeinProjekt$ git config user.name "Stefan" user@host:~/MeinProjekt$ git config user.email "user@local"
Was hat git jetzt eigentlich gemacht?
Git hat im Verzeichnis /home/user/MeinProjekt ein neues, verstecktes Verzeichnis angelegt.
/home/user/MeinProjekt/.git
Mit dem git config wurde die Konfigurationsdatei bearbeitet
/home/user/MeinProjekt/.git/config
und um folgende Einträge erweitert.
[user] name = Stefan email = user@local
Die ersten Dateien
Wir werden nun anfangen, etwas zu arbeiten. Die ersten Dateien entstehen. Wir erstellen zuerst drei Dateien:
user@host:~/MeinProjekt$ echo "Text 1 in Datei 1" > Datei_1.txt user@host:~/MeinProjekt$ echo "Text 1 in Datei 2" > Datei_2.txt user@host:~/MeinProjekt$ echo "Text 1 in Datei 3" > Datei_3.txt
Diese sollen nun im Repository gespeichert werden.
user@host:~/MeinProjekt$ git add Datei_1.txt user@host:~/MeinProjekt$ git add Datei_2.txt user@host:~/MeinProjekt$ git add Datei_3.txt
user@host:~/MeinProjekt$ git commit -m "Meine ersten Dateien" [master (root-commit) 636db54] Meine ersten Dateien 3 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 Datei_1.txt create mode 100644 Datei_2.txt create mode 100644 Datei_3.txt
Die ersten Dateien
Lokal werden wir nun Dateien ändern:
user@host:~/MeinProjekt$ echo "Text 1 in Datei 1 - ändern" > Datei_1.txt user@host:~/MeinProjekt$ echo "Text 2 in Datei 2" >> Datei_2.txt user@host:~/MeinProjekt$ echo "Text 3 in Datei 2" >> Datei_2.txt user@host:~/MeinProjekt$ echo "Text 2 in Datei 3" >> Datei_3.txt
Nun können wir uns die Änderungen zwischen lokalem Dateisystem und Index ansehen:
user@host:~/MeinProjekt$ git diff index 38f57e1..a16a66a 100644 --- a/Datei_1.txt +++ b/Datei_1.txt @@ -1 +1 @@ -Text 1 in Datei 1 +Text 1 in Datei 1 - ändern diff --git a/Datei_2.txt b/Datei_2.txt index 1e10b21..6ec80e6 100644 --- a/Datei_2.txt +++ b/Datei_2.txt @@ -1 +1,3 @@ Text 1 in Datei 2 +Text 2 in Datei 2 +Text 3 in Datei 2 diff --git a/Datei_3.txt b/Datei_3.txt index 38d7991..40cbf6a 100644 --- a/Datei_3.txt +++ b/Datei_3.txt @@ -1 +1,2 @@ Text 1 in Datei 3 +Text 2 in Datei 3
Die Änderungen können über "add" zum Index hinzugefügt werden. Der "commit"-Befehl übernimmt die Informationen aus dem Index in das Repository.
user@host:~/MeinProjekt$ git add Datei_1.txt user@host:~/MeinProjekt$ git add Datei_2.txt user@host:~/MeinProjekt$ git add Datei_3.txt user@host:~/MeinProjekt$ git commit -m "Einige Änderungen" [master b8bb6d3] Einige Änderungen 3 files changed, 4 insertions(+), 1 deletions(-)
Nun sind auch diese Änderungen im Repository gespeichert.
user@host:~/MeinProjekt$ git log commit b8bb6d33acf5a0f911055e64bb222f1a912c2a0a Author: Stefan <user@local> Date: Sat Jan 30 15:46:43 2010 +0100 Einige Änderungen commit 636db5487141a7e857c6c60f0fde09fefb1f7ab8 Author: Stefan <user@local> Date: Sat Jan 30 15:35:33 2010 +0100 Meine ersten Dateien
Repository mit http veröffentlichen
git clone --bare /source /source_bare cd /source_bare git --bare update-server-info cp hooks/post-update.sample hooks/post-update chmod a+x hooks/post-update
...spätestens jetzt Apache-Webserver installieren...
sudo mkdir /var/www/olaf sudo chown olaf.olaf /var/www/olaf mv /home/olaf/source_bare /var/www/olaf
Mit einem bereits bestehenden Repository auf SourceForge.net umziehen
Hat man bereits ein existierendes lokales Repository und will dieses auf SourceForge.net veröffentlichen, hat man das Problem, nur eingeschränkt Zugriff auf das Dateisystem zu haben. Details siehe:
Der einfachste Weg verläuft deshalb über Git selbst:
Zunächst herausfinden, wie der der Branch heißt, den man veröffentlichen will:
or@bigbox:~/var/bibletime$ git branch * olaf
In diesem Fall also "olaf". Normalerweise ist es aber "master". Das ist hier aber ein klein bisschen anders in meinem Fall. Dann muss ich ggf. andere, entfernte Repositorys entfernen aus dem "Gedächtnis" von Git.
or@bigbox:~/var/bibletime$ git remote rm origin
Jetzt füge ich das entfernte ("remote") Repository von sourceforge.net hin zu (in das "Gedächtnis" von) Git.
or@bigbox:~/var/bibletime$ git remote add origin ssh://radicke@bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/
Jetzt kann ich mit einem einfachem "push" mein Repository hochschieben. Ich brauche keinen Zielrechner anzugeben. Den habe ich Git zuvor mit "remote add" bekanntgegeben. Mit "origin" ist das Repository bei git.sourceforge.net gemeint.
or@bigbox:~/var/bibletime$ git push -u origin olaf radicke@bibletimeofolaf.git.sourceforge.net's password: Counting objects: 31054, done. Compressing objects: 100% (5153/5153), done. Writing objects: 100% (31054/31054), 26.91 MiB | 100 KiB/s, done. Total 31054 (delta 24155), reused 30643 (delta 23802) To ssh://radicke@bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/bibletimeofolaf * [new branch] olaf -> olaf Branch olaf set up to track remote branch olaf from origin.
Der Prozess kann je nach Größe einige Minuten dauern.
Mit origin-Branches arbeiten
Wenn wir tatsächlich den Weg in den letzten Abschnitt gegangen sind, werden wir (oder andere) feststellen, daß nach einem "clone" das lokale Repository leer ist. Das hängt damit zusammen, daß es aktuell keinen "master"-Branch gibt. Es gibt immer wieder einmal Szenarien, bei denen wir die Versionszweige ("branches") anderer Entwickler erhalten wollen, die nicht "master" sind (mit "master" ist der Hauptzweig gemeint; bei SVN oder CVS nennt man das meist "trunk"). Zum Beispiel, wenn ein Entwickler einen versuchsweisen Versionszeig erstellt, um einen Test durchzuführen. Dann kann es passieren, daß wir diesen anschauen und bei uns lokal bearbeiten wollen, um eigene Tests zu machen. Soweit die Theorie. Jetzt zum konkreten Beispiel:
Tun wir so, als würden wir uns einen frischen "clone" ziehen von dem im Kapitel oben angelegten Repository.
olaf@gallien-197:~/var$ git clone git://bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/bibletimeofolaf/ Initialized empty Git repository in /atix/home/olaf/var/bibletimeofolaf/.git/ remote: Counting objects: 31054, done. remote: Compressing objects: 100% (4800/4800), done. remote: Total 31054 (delta 24155), reused 31054 (delta 24155) Receiving objects: 100% (31054/31054), 26.52 MiB | 826 KiB/s, done. Resolving deltas: 100% (24155/24155), done. warning: remote HEAD refers to nonexistent ref, unable to checkout.
Die letze Zeile warnt uns schon, daß etwas schiefgegangen ist. Wechseln wir also erstmal in unseren Repository-Clone...
olaf@gallien-197:~/var$ cd ./bibletimeofolaf/ olaf@gallien-197:~/var/bibletimeofolaf$ git branch * (no branch)
Wenn wir ein "ls" machen oder ein "git branch", werden wir nur gähnende Leere sehen. Es ist aber nicht so, daß das Repository tatsächlich leer ist! Die Zweige ("branches"), die von anderen Entwiklern im entfernten ("remote") Repository erstellt ("pushed") wurden, stehen uns zur verfügung. Wir müssen sie aber explizit "auschecken". Mit "origin" ist das entfernte Repository gemeint.
olaf@gallien-197:~/var/bibletimeofolaf$ git checkout origin/olaf Checking out files: 100% (1082/1082), done. Note: checking out 'origin/olaf'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, 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 90825ea... set small margins for small devs.
Jetzt sehen wir auch tatsächlich unsere Daten, haben aber immer noch keinen eigenen Versionzweig ("branch"):
olaf@gallien-197:~/var/bibletimeofolaf$ ls CMakeLists.txt ChangeLog LICENSE Makefile README README_ATER_GUI.txt build-debug.sh build-release.sh cmake docs i18n pics src olaf@gallien-197:~/var/bibletimeofolaf$ git branch * (no branch)
Das lässt sich aber schnell ändern (mit "branch")...
olaf@gallien-197:~/var/bibletimeofolaf$ git branch master olaf@gallien-197:~/var/bibletimeofolaf$ git branch * (no branch) master olaf@gallien-197:~/var/bibletimeofolaf$ git checkout master Switched to branch 'master' olaf@gallien-197:~/var/bibletimeofolaf$ ls CMakeLists.txt ChangeLog LICENSE Makefile README README_ATER_GUI.txt build-debug.sh build-release.sh cmake docs i18n pics src
Jetzt schieben ("push") wir das in die öffentlichen Repositorys von sourceforge.net....
olaf@gallien-197:~/var/bibletimeofolaf$ git push --all ssh://radicke@bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/bibletimeofolaf radicke@bibletimeofolaf.git.sourceforge.net's password: Total 0 (delta 0), reused 0 (delta 0) To ssh://radicke@bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/bibletimeofolaf * [new branch] master -> master
Git teilt uns mit, daß unser "master" als "master" auf "origin" geschoben ("pushed") wurde. Wir können jetzt nochmal einen "clone" erstellen, um zu überprüfen, was die anderen Entwickler bei einem "clone"-Befehl erhalten.
olaf@gallien-197:~/var/bibletimeofolaf$ cd .. olaf@gallien-197:~/var$ mv ./bibletimeofolaf/ ./bibletimeofolaf_backup olaf@gallien-197:~/var$ git clone ssh://radicke@bibletimeofolaf.git.sourceforge.net/gitroot/bibletimeofolaf/bibletimeofolaf Initialized empty Git repository in /atix/home/olaf/var/bibletimeofolaf/.git/ radicke@bibletimeofolaf.git.sourceforge.net's password: remote: Counting objects: 31054, done. remote: Compressing objects: 100% (4800/4800), done. remote: Total 31054 (delta 24155), reused 31054 (delta 24155) Receiving objects: 100% (31054/31054), 26.52 MiB | 233 KiB/s, done. Resolving deltas: 100% (24155/24155), done. Checking out files: 100% (1082/1082), done. olaf@gallien-197:~/var$ cd ./bibletimeofolaf olaf@gallien-197:~/var/bibletimeofolaf$ ls CMakeLists.txt ChangeLog LICENSE Makefile README README_ATER_GUI.txt build-debug.sh build-release.sh cmake docs i18n pics src olaf@gallien-197:~/var/bibletimeofolaf$ git branch * master
Also ist alles nun in bester Ordnung.
Buchempfehlung
"Git- kurz und gut" von Sven Riedel, ISBN-10: 389721914X