Benutzer:Lord Horazont/Tutorial Versionskontrolle mit GIT

Aus DGL Wiki
Wechseln zu: Navigation, Suche

Versionskontrolle mit git

Hallo und herzlich willkommen zu meinem dritten Tutorial. Heute soll's um Versionskontrolle gehen und zwar demonstriert anhand von git. Warum überhaupt Versionskontrolle? Warum für Hobbyprojekte? Was ist git? Wie macht man das? – diese und andere Fragen werde ich (hoffentlich) beantworten.

Theorie der Versionskontrolle

Nun, jeder der schon einmal einen Wikiartikel geschrieben hat, hatte schon indirekt Kontakt mit Versionskontrolle. Sowas ist nämlich in jedes MediaWiki eingebaut. Immer, wenn man einen Artikel bearbeitet, wird die vorherige Version erhalten, man kann sie später anschauen oder Änderungen rückgängig machen.

Dies gibts nicht nur für Webseiten wie unser Wiki, sondern, in anderer Form, auch für Projekte. Viele werden schonmal irgendwo SVN oder CVS gehört haben, weniger von GIT oder Mercurial. Diese vier sind vermutlich die populärsten Versionskontrolle-Werkzeuge, die im Moment im Einsatz sind.

Häufige Probleme…

Problem 1: Mist gebaut?

Der große Vorteil der Versionskontrolle liegt auf der Hand. Habt ihr schonmal selbstsicher angefangen, an einem Feature zu arbeiten, dann festgestellt, dass es irgendwie nicht ganz so gut läuft wie erwartet und zum schluss einen Haufen Konflikte im Code gehabt? Da hilft meist nur noch eins: Rückgängig drücken, und zwar oft. Mist! Das Undo-Limit der IDE ist erreicht, aber nichtmal die Hälfte der Änderungen wurden rückgängig gemacht. Dann hat man noch die Möglichkeit, auf ein Backup zurückzugreifen (falls das überhaupt existiert), oder eben alles von Hand wieder Rückgängig machen.

Problem 2: Zusammenarbeit

Anderes Szenario: Man hat ein Projekt, was gut läuft und was andere (Programmierer) interessant finden. Sie möchten Beitragen, aber natürlich hat man eher wenig Lust immer Archive mit allen Sourcedateien per Mail oder sonstwas zu verschicken. Auch will man den Leuten nicht unbedingt Schreibzugriff auf den eigenen Rechner geben. Also könnte man immer noch, um das Datenvolumen zu reduzieren, Patches verschicken.

… und ihre Beseitigung durch Versionskontrolle

Aus beiden Szenarien gibt es einen gemeinsamen Ausweg: Versionskontrolle und Repositories solcher müssen her!

Anhand von git sei nun im folgenden gezeigt, wie man die beiden genannten Probleme umgeht. Aber wir wollen von Grund auf anfangen, damit ihr das ganze gleich sofort ausprobieren könnt. Dazu beginnen wir damit, wie man Git verwendet. Es sei vorrausgesetzt, dass ihr mit dem Terminal (oder der git-bash, was nichts weiter als eine Bash mit Git für Windows ist) umgehen könnt. Außerdem sollte Git bzw. die Git-Bash natürlich installiert sein ;).

Ein Git-Repository anlegen und befüllen

Das ist recht einfach. Wir wechseln (mit cd) in das Verzeichnis, wo wir ein Git-Repository anlegen wollen. Das ist im optimalfall leer oder das Wurzelverzeichnis unseres Projektes. Dann initialisieren wir ein git Repo mit:

$ git init

War einfach, oder? Jetzt können wir schauen, was git so sagt (vorrausgesetzt, es sind schon Dateien im Verzeichnis, sonst erstmal ein Projekt oder so reinkopieren):

$ git status

Das sollte eine Ausgabe ähnlich dieser erzeugen:

# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	a
#	b
nothing added to commit but untracked files present (use "git add" to track)

Wobei anstatt a und b bei euch vermutlich andere Dateien und Verzeichnisse aufgelistet sind. Diese können wir nun mit:

$ git add file1 file2 …

hinzufügen. Das geht aber auch einfacher:

$ git add directory/* # fügt alle Dateien im Verzeichnis directory hinzu (mit Unterverzeichnissen)
$ git add directory # wie oben
$ git add *.c # fügt alle Dateien, die auf .c enden und im Wurzelverzeichnis liegen hinzu
$ git add directory/*.c # könnt ihr sicher erraten: fügt alle Dateien, die auf *.c enden und in directory liegen hinzu (sollte dort ein Ordner auf .c 

enden, wird dieser auch hinzugefügt…)

$ git add -A # fügt *alle* dateien, die es im Ordner finden kann, hinzu. Kann zu viel sein, evtl. mit git rm --cached wieder welche entfernen.

Soweit. Nun haben wir git mitgeteilt, dass wir diese Dateien hinzufügen wollen. Das müssen wir noch committen, sozusagen „amtlich“ machen:

$ git commit -v

Das wird euren bevorzugten Terminal-Editor öffnen und ihr könnt eine Commit-Message eingeben, die später im Log zu diesem „Commit“ auftauchen wird. Ein „Commit“ ist sozusagen ein Satz an Änderungen, der logisch zusammen gehört. Was logisch zusammen gehört, definiert sich daran, was ihr zusammen committed ;). Wenn nichts schief gegangen ist, wird git sowas sagen wie:

[master (root-commit) 050a498] * Bla
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bla/bakery/bread
 create mode 100644 bla/cookie
 create mode 100644 bla/keks
 create mode 100644 c.c

Ansonsten sollte die Fehlermeldung aufschluss darüber geben, was nicht geklappt hat. Eventuell möchte git, dass ihr ihm sagt, wer ihr seid. Das tut ihr mit den Befehlen, die es euch da vorschlägt. Diese Informationen werden in die Commits mit eingebunden, damit man diese den Entwicklern zuordnen kann.

Änderungen durchführen und committen

Nun können wir an unserem Code rumschreiben. Wenn wir einen Schritt weiter zu unserem Ziel gekommen sind, können wir die Änderungen ins Repo committen. Ich mache das meist, wenn ich kompilierfähigen Code habe oder wenn ich einen größeren Schritt erledigt habe oder wenn ich von einer logischen Einheit des Codes in eine andere wechsle (z.B. unterschiedliche Packages oder Module). Jetzt können wir entweder alle Dateien, die wir geändert oder neu hinzugefügt haben mit

$ git add path/to/file.pp path/to/file2.pp

“stagen”, d.h. für den Commit vorsehen, oder wir nutzen

$ git commit -av

wobei das “a” in der Kommandozeile sagt, dass es automatisch alle geänderten Dateien mit in den Commit aufnehmen soll. Beachtet aber, dass es neu erstellte Dateien nicht als “changed” sondern als “untracked” sieht, also werden sie nicht beachtet. Neu erstellte Dateien muss man explizit mit

$ git add path/to/new/file.pp

ankündigen. Das kann man aber ohne Probleme zusammen mit git commit -av benutzen, sodass man nur die neu erstellten Dateien mit git add stage't, aber die anderen mit git commit -av.

$ git log

sollte nun schon ein paar schöne Commits ausgeben.

Pushs, Fetchs, Merges, Pulls und Branches

Ähhh. Was? Ok, der Reihe nach.

Was wir bisher haben ist eigentlich nichts weiter als eine History von Dateiversionen. Das ist schonmal sehr schön, wenn mal was abbrennt (man also einen kritischen Fehler beim Entwickeln gemacht hat und zu einem alten Stand zurückkehren möchte), aber das ist bei weitem nicht alles, was man in moderner Versionskontrolle hat (und zu schätzen lernen wird).

Zunächst ist git ein sogenanntes DVCS, ein Distributed Version Control System. Das Distributed lässt erahnen, dass wir Daten auch auf anderen Rechnern haben können. Wer einen eigenen Server hat (sei es nun zu Hause oder im Internet), der kann mit gitolite ganz einfach einen sicheren git Repository Server aufsetzen. Für Public Access findet man auch schnell was im Internet.

Der Vorteil liegt auf der Hand: Die Daten liegen nicht mehr nur auf einem Rechner. Wenn da also mal die Festplatte abraucht oder der Blitz einschlägt – der Code ist sicher (ausreichende Push-Frequenz vorrausgesetzt). Man hat die Daten sogar Unterwegs zur Verfügung.

Ich möchte jetzt nicht genau darauf eingehen, wie man mit gitolite einen Repository-Server aufsetzt, sondern lieber ein bisschen die Bedienung von git erläutern und ein paar Beispiele durchgehen.

Branches

Wer noch nicht viel mit Versionskontrolle zu tun hat, dem sei das Konzept von Branches ans Herz gelegt.

Clones, Fetches und Pulls

Wenn man an einem mit git verwalteten Projekt mitmachen möchte, wird man häufig auf so eine Kommandozeile stoßen:

$ git clone https://...

Das ist der Befehl, um ein Git-Repository zu klonen, wobei die Quelle als remote names origin eingetragen wird. Das ist so git Tradition und sollte nicht unbedingt gebrochen werden (kann aber ohne weiteres).

Ein remote ist erstmal nicht viel mehr als ein Eintrag in Git's „Datenbank“, wo es Commits herbekommen kann und welche branches dort existieren.

“A successful git branching model”

Auf dieser Seite bin ich auf ein sehr hilfreiches Arbeitsmodell für das Arbeiten mit Branches unter Git gestoßen. Das könnt ihr euch am besten Ausdrucken und an die Wand pinnen.