Serie: Versionskontrolle for the rest of us
- Teil 1: Das Prinzip hinter Subversion a.k.a. SVN
- Teil 2: SVN-Prinzipien an Beispielen erklärt
- Teil 3: Git für SVN-Umsteiger
- Teil 4: Das Prinzip Git an Beispielen erklärt
- Teil 5: Git für so halb-Fortgeschrittene
- Teil 5: Git und Branches
Jetzt wo wir die trockene Theorie gepaart mit einem genialen Schema meinerseits hinter uns gelassen und verinnerlicht haben, auf zu konkreten Beispielen.
Vorneweg muss ich euch darauf hinweisen, dass ich diesmal von der allseits beliebten Kommandozeile aus arbeite. Das hat keinen besonderen Grund, außer dass ich es diesmal – im Gegensatz zu SVN – so gelernt habe. Und gepaart mit ein paar TextExpander-Snippets geht das auch flinker von der Hand, als ich es mir in einem Client mit graphischem Interface vorstellen kann. Wenn ihr aber meinem Blog-Kompagnon Pipo lang genug auf die Nerven geht, stellt er euch bestimmt mal Source Tree vor.
Windows-User: werft mal einen Blick hierhin.
Aller Anfang ist git init
Wir machen es diesmal richtig Hands-On. Also sucht euch einen Ordner aus, den ihr mit ein paar Git-Dateien zumüllen wollt und los geht’s. Terminal auf und in den Ordner ge-cd-t. In meinem Fall
cd /Users/Enno/Sites/git-tut/
Weiter geht es mit der Initialisierung:
git init
Was passiert? Es werden die initialen Dateien angelegt – und zwar im Unterordner .git. Alles was hier drin ist braucht und soll euch nicht interessieren. Finger weg dort, schließlich geschieht hier die ganze Magie.
Git packt übrigens im Gegensatz zu SVN nicht in jeden Unterordner noch mal einen .git-Ordner. Dieser eine reicht.
Immer informiert mit git status
Einen Befehl werdet ihr gar nicht verinnerlichen müssen, weil ihr ihn immer und immer und immer und immer wieder eintippen werdet.
git status
Hier erhaltet ihr eine Übersicht über:
- neue Dateien, die Git noch nicht in seine Versionkontrolle aufgenommen hat,
- gemachte Änderungen an bestehenden Dateien,
- Änderungen, die darauf warten comittet zu werden (Staging, siehe letzter Teil),
- mögliche Konflikte,
- sowie den aktuellen Branch (normalerweise der Master als Haupt-Branch).
Im Laufe dieses Tutorials werdet ihr die Wichtigkeit dieses Befehls bereits erkennen. Nehmt ihn erstmal als das hin, was er ist: die zentrale Anlaufstelle für alle weiteren Befehle.
Nach der Initialisierung sieht sein Output so aus:
# On branch master
#
# Initial commit
#
Wir sind also im Master-Branch und auf der Stufe des initialen Commits. Ein Zeichen, dass es sich um ein leeres Git-Repository handelt. Zeit das zu ändern.
Neue Dateien hinzufügen und stagen
Wir legen erstmal prophylaktisch ein einfaches Readme-File an. Wir können uns ja für unser Projekt wenigstens vornehmen, uns ein wenig um Dokumentation zu kümmern.
touch readme.txt
Was sagt git status
jetzt?
# On branch master
#
# Initial commit
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# readme.txt
Wir sind immer noch in der selben Situation wie vorher (Master-Branch, Initital Commit), allerdings informiert uns Git nun darüber, dass es auf Dateien gestoßen ist, die noch nicht der Versionkontrolle unterliegen.
Ihr erkennt an dieser Stelle auch schon, dass Git uns hier und da sinnvolle Hinweise hinterlässt. In diesem Fall sagt es uns, dass wir git add
verwenden sollen, um unsere Readme-Datei von Git tracken zu lassen. Lassen wir heute die Anarchie mal außen vor und tun, was uns befohlen wird.
git add readme.txt
Was sagt uns git status
anschließend? (ja ihr seht schon, dieses git status
drängt sich ziemlich auf…)
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached <file>..." to unstage)
#
# new file: readme.txt
#
Aus den Untracked Files sind Changes to be committed geworden. Unsere readme.txt befindet sich nun offiziel im Staging. Das bedeutet – zur Erinnerung – dass diese Datei beim nächsten Commit berücksichtigt wird. Was ihr tun müsst, um das rückgängig zu machen, zeigt euch Git wieder an. Doch das wollen wir nicht. Wir wollen produktiv sein. Wir machen weiter mit einem Commit.
Commit
Was genau das ist, solltet ihr als aufmerksame Leser dieses Blogs schon durch meine Ausführungen zu SVN wissen. Oder aber ihr habt das tolle Schema aus dem letzten Teil verinnerlicht (und ja, ich verlinke ein weiteres Mal auf den vorangegangen Artikel dieser Serie). Umgesetzt wird er in Git folgerichtig mit git commit
.
Die duften Typen unter euch wissen: zu jedem Commit gehört eine Commit-Message, also eine Nachricht, die beschreibt, was man eigentlich genau gemacht hat. Erleichtert später das Suchen bestimmter Änderungen und macht Projektfortschritte besser nachvollziehbar.
Die Nachricht lässt sich über den Parameter -m
mitgeben. Also tippen wir in unserem Fall ungefähr sowas hier ein:
git commit -m "added documentation file"
Commit-Identifier
Der Terminal-Output sagt jetzt folgendes:
[master (root-commit) 9f19cd4] added documentation file
0 files changed
create mode 100644 readme.txt
Die Zahlenfolge 9f19cd4
wird bei euch anders sein. Diese ist der Anfang der Commit-Nummer, die weltweit eindeutig ist. Hier wird also nicht wie bei SVN die Revisionsnummer einfach hochgezählt. Stattdessen gibt es unique Commit-Identifier. Das ist dahingehend sinnvoll, dass Git eigentlich von dezentraler Natur ist. Da es keine zentrale Stelle für ein Repository gibt, macht auch das Hochzählen einer zentralen Revisionsnummer keinen Sinn. In der Praxis sieht das mit den dezentralen Repositories ein bisschen anders aus, aber das ist halb so wild. Wichtig ist, dass ihr mit der kryptischen Zahlenfolge etwas anzufangen wisst.
Der Rest der Ausgabe sagt nur etwas über die Vorgänge beim Commit aus. Erstmal nicht weiter wichtig. Ein anschließendes git status
wird uns bestätigen, dass wir keine Änderungen mehr zu comitten haben. Man spricht von einem cleanen Working-Directory. Unterstützend noch mal der genaue Output:
# On branch master
nothing to commit (working directory clean)
Batch-Staging bei Änderungen
Wir haben bisher nur eine neue Datei angelegt. Wie genau unterscheidet sich der Vorgang, wenn wir eine existierende Datei ändern?
Unwesentlich. Öffnet die readme.txt und schreibt Ich bin die erste Zeile (oder irgendwas anderes) hinein. Anschließend rufen wir einmal mehr git status
auf der Kommandozeile auf. Was sagt Herr Output?
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
Die Datei unserer Begierde taucht plötzlich unter Changes not staged for commit auf. Wer aufgepasst hat, weiß: die Datei muss noch gestaged werden. Wer nicht aufgepasst hat, könnte dies auch aus den stets hilfreichen Kommentaren im Output sehen.
- use “git add …” to update what will be committed oder
- no changes added to commit (use “git add” and/or “git commit -a”).
Stagen also. Bei einer Datei mag das ja noch ok sein. Was aber wenn wir 10 Dateien haben, die alle noch geadded bzw. gestaged werden müssen? Muss man für jede Datei einzeln git add <Dateiname>
aufrufen?
Nein. Es gibt 2 Möglichkeiten. Numero Uno: wir benutzten den Punkt als Wildcard für alle Dateien:
git add .
Was auch funktioniert – übrigens immer, wenn es um Datei- bzw. Pfadangaben geht – ist der von den regulären Ausdrücken bekannte Stern. Beispiel:
git add path/to/files/*.png
Die zweite Möglichkeit für das Batch-Staging besteht darin, direkt im Commit zu bestimmen, dass alle ungestageten Änderungen mitcomittet werden sollen. Das geschieht über den Parameter -a
für all:
git commit -a -m "Committed all unstaged files automagically"
Dass ihr hier auch tunlichst darauf achten solltet, dass tatsächlich auch alle Änderungen den aktuellen Commit betreffen, versteht sich von selbst.
What’s left?
Puh, ich hätte anfangs gar nicht gedacht, dass es so viel wird. Und trotzdem gibt es noch eine Reihe von Aspekten, die ich erklären möchte. Darum dürft ihr euch auf den nächsten Teil freuen.
Inhalt?
- Stashing
- Reverting
- GitHub, push und pull
- Merge
Anschließend solltet ihr aber perfekt gewappnet sein, um in den ersten Kneipengesprächen mit ein bisschen Git-Halbwissen protzen zu können 😉
Wer bis dahin ein bisschen Lust auf Hausaufgaben hat, darf sich gern mal den von Code School (in Kollaboration mit GitHub) erarbeiteten interaktiven Kurs TryGit anschauen. Empfehlung meinerseits!