Git war erst einmal "nur" eine weitere Quellcode-Verwaltung. Wie groß kann der Unterschied schon sein? Das waren meine ersten Gedanken. Bis ich mich mehr mit Git beschäftigte. Ich muss zugeben, Git ist für den Umstieg vom TFS gewöhnungsbedürftig. Die Lernkurve ist steil. Es ist einfach nach einem anderen Konzept gestrickt.
Der erste Unterschied ist, dass Git ein verteiltes Versionskontrollsystem (Distributed Version Control System, DVCS) ist. Der TFS hingegen ist ein zentralisiertes System (Centralized Version Control System, CVCS). D.h. im TFS sind alle Informationen zu Dateien, Historie, Changesets etc. auf einem Server abgelegt, während bei Git eine lokale Kopie auf dem Rechner vorliegt, mit allen Informationen zu Dateien, Commits, Historie etc. Es Bedarf keiner Verbindung zu einem Server, es sei denn man möchte seine Arbeit mit dem Remote-Repository synchronisieren.
Meine ersten Erfahrungen mit Git sahen so aus, dass ich mir erst einmal die Bedeutung der Befehle klar machen musste. Commit, Push, Pull, Fetch, Checkout, um hier einige zu nennen. Während Checkout im TFS bedeutet, eine Datei zum Bearbeiten zu öffnen, heißt es in Git in einen anderen Branch zu wechseln. Check-in im TFS besteht in Git aus zwei Befehlen: Commit und Push.
Hier eine kleine Gegenüberstellung der Befehle:
Der zweite Unterschied ist die Art und Weise wie Git Dateien betrachtet. Der TFS betrachtet Dateien einzeln, mit deren Änderungen über die Zeit. Git hingegen, betrachtet alle Dateien als einen Stream sogenannte Snapshots. Diese „Schnappschüsse“ entstehen jedes Mal, wenn ein Commit ausgeführt wird. Git speichert nun diesen Zustand aller Dateien, in diesem Moment als Snapshot.
Diese Art der Verwaltung hat natürlich Vorteile in Sachen Geschwindigkeit. Ein Commit dauert nur den Bruchteil einer Sekunde. Blame oder die Historie aufrufen und filtern geht unglaublich schnell. Da Git alles lokal vorhält und somit keine Verbindung zu einem Server benötigt, kann Git hier viel Performance rausholen.
Wirklich interessant, wurde es erst mit Branches und Mergen.
Die volle Power von Git bekam ich erst beim Anlegen und Arbeiten mit Feature-Branches zu spüren. Hier zeigt sich der dritte Unterschied. Der TFS muss für jeden Feature- oder Release-Branch einen eigenen Ordner angelegen und alle Dateien dorthin kopieren. Dieser muss dann vom Entwickler per „Get Latest“ abgeholt werden, was bedeutet, dass ein weiterer Ordner auf der Festplatte vorliegt und Speicherplatz verschwendet.
Git hingegen kopiert nicht den gesamten Parent-Branch. Stattdessen handelt es sich einfach um einen Zeiger auf den Parent-Branch, von wo aus wir unseren neuen Branch erzeugt haben.
Im Folgenden zeige ich euch wie das funktioniert.
Wir gehen davon aus, dass ihr bereits ein „git clone“ von einem Projekt eurer Wahl gemacht habt. Für gewöhnlich nennt sich dieser geklonte Branch „master“. Wir möchten nun ein neues Feature entwickeln und legen uns dafür einen Feature-Branch namens „tolles-feature“ an.
Mit dem folgenden Befehl kann ein neuer Branch angelegt werden:
$ git branch tolles-feature
Der Branch ist nun angelegt, wir sind aber noch nicht auf dem neuen Branch. Das sieht ungefähr so aus (man achte auf das Sternchen, es markiert den aktuellen Branch):
Wir führen nun folgenden Befehl aus, um zu wechseln:
$ git checkout tolles-feature
In Git sieht das wie folgt aus (auf das Sternchen achten):
Und hier noch die Kurzform der beiden oben genannten Befehle:
$ git checkout -b tolles-feature
Nun können wir auf dem neuen Branch arbeiten und Committen, Pushen etc.
Nachdem das Feature fertig entwickelt ist, müssen wir unsere Änderungen wieder zurück in den „master“-Branch integrieren. Wir führen ein Merge durch, um den Feature-Branch zurückzuführen. Um das zu bewerkstelligen, wechseln wir zurück auf „master“:
$ git checkout master
Anschließend kommt der Merge:
$ git merge tolles-feature
Das war’s schon. Und wo ist jetzt die Power? Nun, Git ist so intelligent und hat beim „mergen“ erkannt, dass in „master“ keine Änderungen (also Commits) vorliegen, die den Merge beeinflussen. Also wird ein „Fast-Forward“ gemacht. Das heißt, der Zeiger von „master“, wird einfach auf das letzte Commit von „tolles-feature“ gesetzt, wie in der Abbildung unten zu sehen ist:
Sollten Konflikte auftreten, weil in „master“ ebenfalls Commits vorhanden sind, können diese, wie im TFS auch, einfach aufgelöst (Resolved) werden. Im oben genannten Fall gibt es aber keine Konflikte, ergo kann der Zeiger verschoben werden. Im TFS würde dennoch eine große Merge-Operation stattfinden, die Dateien vergleicht und Änderungen übernehmen muss.
Da der Branch „tolles-feature“ nun nicht weiter benötigt wird, können wir den Branch mit folgendem Befehl löschen:
$ git branch -d tolles-feature
Und so wird in Git mit Branches gearbeitet. Cool oder?
Da ich nun seit ein paar Monaten mit Git arbeite und den anfänglichen Git-Schock überwunden habe, hat sich mein Arbeitsablauf verbessert. Ich bin schneller geworden. Dafür gibt es eine Reihe von Gründen:
Ich kann nur sagen: Der Umstieg lohnt sich!
Zum Abschluss möchte ich noch ein paar Tools erwähnen, die das Leben mit Git erleichtern, wenn man nicht auf der Kommandozeile arbeiten möchte: