Kapitel 2. Erste Schritte

Bevor wir uns in ein Meer von Git-Befehlen stürzen, schauen wir uns ein paar einfache Beispiele an. Trotz ihrer Einfachheit sind alle davon wichtig und nützlich. Um ehrlich zu sein, in meinen ersten Monaten mit Git brauchte ich nicht mehr, als in diesem Kapitel beschrieben steht.

Stand sichern

Hast Du gravierende Änderungen vor? Nur zu, aber speichere Deinen aktuellen Stand vorher lieber nochmal ab:

$ git init
$ git add .
$ git commit -m "Meine erste Sicherung"

Falls deine Änderungen schief gehen, kannst du jetzt die alte Version wiederherstellen:

$ git reset --hard

Um den neuen Stand zu sichern:

$ git commit -a -m "Eine andere Sicherung"

Hinzufügen, Löschen, Umbenennen

Bisher kümmert sich Git nur um Dateien, die existierten, als Du das erste Mal git add ausgeführt hast. Wenn Du Dateien oder Verzeichnisse hinzufügst, musst du Git das mitteilen:

$ git add readme.txt Dokumentation

Ebenso, wenn Git Dateien vergessen soll:

$ git rm ramsch.h veraltet.c
$ git rm -r belastendes/material/

Git löscht diese Dateien für Dich, falls Du es noch nicht getan hast.

Eine Datei umzubenennen, ist das selbe, wie sie zu löschen und unter neuem Namen hinzuzufügen. Git benutzt hierzu die Abkürzung git mv, welche die gleiche Syntax wie mv hat. Zum Beispiel:

$ git mv fehler.c feature.c

Fortgeschrittenes Rückgängig machen/Wiederherstellen

Manchmal möchtest Du einfach zurückgehen und alle Änderungen ab einem bestimmten Zeitpunkt verwerfen, weil sie falsch waren. Dann:

$ git log

zeigt Dir eine Liste der bisherigen Commits und deren SHA1 Hashwerte:

commit 766f9881690d240ba334153047649b8b8f11c664
Author: Bob <bob@example.com>
Date:   Tue Mar 14 01:59:26 2000 -0800

    Ersetze printf() mit write().

commit 82f5ea346a2e651544956a8653c0f58dc151275c
Author: Alice <alice@example.com>
Date:   Thu Jan 1 00:00:00 1970 +0000

    Initial commit.

Die ersten paar Zeichen eines Hashwert reichen aus, um einen Commit zu identifizieren; alternativ benutze kopieren und einfügen für den kompletten Hashwert. Gib ein:

$ git reset --hard 766f

um den Stand eines bestimmten Commits wieder herzustellen und alle nachfolgenden Änderungen für immer zu löschen.

Ein anderes Mal willst Du nur kurz zu einem älteren Stand springen. In diesem Fall, gib folgendes ein:

$ git checkout 82f5

Damit springst Du in der Zeit zurück, behältst aber neuere Änderungen. Aber, wie bei Zeitreisen in einem Science-Fiction-Film, wenn Du jetzt etwas änderst und commitest, gelangst Du in eine alternative Realität, denn Deine Änderungen sind anders als beim früheren Commit.

Diese alternative Realität heißt Branch, und wir kommen später darauf zurück. Für jetzt merke Dir,

$ git checkout master

bringt Dich wieder in die Gegenwart. Um zu verhindern, dass sich Git beschwert, solltest Du vor einem Checkout alle Änderungen commiten oder reseten.

Um wieder die Computerspielanalogie anzuwenden:

  • git reset --hard: Lade einen alten Stand und lösche alle Spielstände, die neuer sind als der jetzt geladene.
  • git checkout: Lade einen alten Spielstand, aber wenn Du weiterspielst, wird der Spielstand von den früher gesicherten Spielständen abweichen. Jeder Spielstand, der ab jetzt gesichert wird, entsteht in dem separaten Branch, welcher der alternative Realität entspricht. dazu kommen wir später.

Du kannst auch nur einzelne Dateien oder Verzeichnisse wiederherstellen, indem Du sie an den Befehl anhängst:

$ git checkout 82f5 eine.datei andere.datei

Sei vorsichtig, diese Art des Checkout kann Dateien überschreiben, ohne dass Du etwas merkst. Um Unfälle zu vermeiden, solltest Du immer commiten bevor Du ein Checkout machst, besonders am Anfang, wenn Du Git noch erlernst. Allgemein gilt: Wenn Du unsicher bist, egal, ob ein Git Befehl oder irgendeine andere Operation, führe zuerst git commit -a aus.

Du magst Kopieren und Einfügen von Hashes nicht? Dann nutze:

$ git checkout :/"Meine erste Si"

um zu einem Commit zu springen, dessen Beschreibung so anfängt. Du kannst auch nach dem 5. letzten Commit fragen:

$ git checkout master~5

Rückgängig machen

In einem Gerichtssaal können Ereignisse aus den Akten gelöscht werden. Ähnlich kannst Du gezielt Commits rückgängig machen.

$ git commit -a
$ git revert 1b6d

wird den Commit mit dem angegebenen Hashwert rückgängig machen. Das Rückgängig machen wird als neuer Commit erstellt, was mit git log überprüft werden kann.

Changelog erstellen

Verschiedene Projekte benötigen ein Änderungsprotokoll. Das kannst du mit folgendem Befehl erstellen:

$ git log > ChangeLog

Dateien herunterladen

Eine Kopie eines mit Git verwalteten Projekts bekommst du mit:

$ git clone git://server/pfad/zu/dateien

Um zum Beispiel alle Dateien zu bekommen, die ich zum Erzeugen dieser Seiten benutze:

$ git clone git://git.or.cz/gitmagic.git

Es gibt gleich noch viel mehr über den clone Befehl zu sagen.

Das Neueste vom Neuen

Wenn Du schon eine Kopie eines Projektes hast, kannst Du es auf die neuste Version aktualisieren mit:

$ git pull

Einfaches Veröffentlichen

Angenommen Du hast ein Skript geschrieben und möchtest es anderen zugänglich machen. Du könntest sie einfach bitten, es von Deinem Computer herunterzuladen, aber falls sie das tun, während Du experimentierst oder das Skript verbesserst, könnten sie in Schwierigkeiten geraten. Genau deswegen gibt es Releasezyklen. Entwickler arbeiten regelmäßig an einem Projekt, veröffentlichen den Code aber nur, wenn sie ihn für vorzeigbar halten.

Um dies in Git zu tun, gehe ins Verzeichnis in dem das Skript liegt:

$ git init
$ git add .
$ git commit -m "Erster Stand"

Dann sage Deinen Nutzern:

$ git clone dein.computer:/pfad/zum/skript

um Dein Skript herunterzuladen. Das setzt voraus, dass sie einen SSH-Zugang haben. Falls nicht, führe git deamon aus und sage den Nutzern folgendes:

$ git clone git://dein.computer/pfad/zum/skript

Ab jetzt, immer wenn Dein Skript reif für eine Veröffentlichung ist:

$ git commit -a -m "Nächster Stand"

und Deine Nutzer können ihr Skript aktualisieren mit:

$ git pull

Deine Nutzer werden nie mit Versionen in Kontakt kommen, von denen Du es nicht willst. Natürlich funktioniert der Trick für fast alles, nicht nur Skripts.

Was habe ich getan?

Finde heraus, was Du seit dem letzten Commit getan hast:

$ git diff

Oder seit Gestern:

$ git diff "@{gestern}"

Oder zwischen irgendeiner Version und der vorvorletzten:

$ git diff 1b6d "master~2"

Jedes mal ist die Ausgabe ein Patch, der mit git apply eingespielt werden kann. Versuche auch:

$ git whatchanged --since="2 weeks ago"

Um mir die Geschichte eines Repositories anzuzeigen, benutze ich häufig qgit da es eine schicke Benutzeroberfläche hat, oder tig, eine Konsolenanwendung, die sehr gut über langsame Verbindungen funktioniert. Alternativ kannst Du einen Webserver installieren mit git instaweb, dann kannst Du mit jedem Webbrowser darauf zugreifen.

Übung

A, B, C, D sind 4 aufeinander folgende Commits. B ist identisch mit A, außer, dass einige Dateien gelöscht wurden. Wir möchten die Dateien in D wieder hinzufügen, aber nicht in B. Wie machen wir das?

Es gibt mindestens 3 Lösungen. Angenommen, wir sind bei D:

  1. Der Unterschied zwischen A und B sind die gelöschten Dateien. Wir können einen Patch erstellen, der diesen Unterschied darstellt und diesen dann auf D anwenden:

    $ git diff B A | git apply
    
  2. Da die Dateien im Repository unter dem Commit A gespeichert sind, können wir sie wieder herstellen:

    $ git checkout A foo.c bar.h
    
  3. Wir können den Commit von A auf B als Änderung betrachten, die wir rückgängig machen wollen:

    $ git revert B
    

Welche Lösung ist die beste? Die, welche Dir am besten gefällt. Es ist einfach, mit Git das zu bekommen, was Du willst und oft führen viele Wege zum Ziel.