Einfache Git-Strategie für Single-Coder

26.11.2017

Mit einer einfachen Branching-Strategie für Git kann man sich das Leben auch als Single -Coder deutlich erleichtern.

Social Coding Plattformen wie GitHub, GitLab oder BitBucket gehören längst um Standard-Repertoir der meisten Entwickler. Wer jedoch bei Git gerade erst eingestiegen ist oder wie ich nur als Einzelkämpfer mit kleinen Projekten unterwegs ist, der nutzt GitHub oder GitLab vielleicht nur als einfaches Repository. Sprich, er schiebt seinen Code-Stand hin und wieder auf GitHub und verwendet die Plattform mehr oder weniger als externe Festplatte.

Das Problem mit den Bugs

Problematisch wird es jedoch, wenn ein Bug auftaucht. Denn solche Bug lassen sich nur schwer beheben, wenn man auf dem Rechner bereits am nächsten Feature gearbeitet hat. Denn dann unterscheidet sich die Code-Stand auf dem lokalen Rechner vom Code-Stand des Live-Systems und dem Code-Stand auf GitHub. Das Vorgehen müsste daher so aussehen:

  • Man setzt den lokalen Code-Stand wieder zurück auf den Live-Stand bzw. den Stand von GitHub.
  • Dann behebt man den Bug.
  • Anschließend pushed man den korrigierten Stand auf GitHub und deployed ihn live.
  • Danach kehrt man wieder zurück zum neuesten Code-Stand und arbeitet weiter am neuen Feature.

Genau das funktioniert bei Git mit dem sogenannten Branching. Oder besser gesagt: Das Branching gehört zum Kern der Versionierungssoftware Git, denn Branches sind Versionen. Und diese Versionierung hilft auch bei kleinen Einzel-Projekten, das beschriebene Dilemma zu lösen.

Eine einfache Branching-Strategie

Per Default befindet man sich bei Git immer im "Master" als dem Standard-Branch. Und beim Einstieg in Git coded man häufig einfach in diesem Master-Branch herum. Genau dadurch entsteht das oben beschriebene Problem. Die Lösung lautet daher ganz simpel:

Der Master-Branch auf dem lokalen Rechner gleicht immer dem Stand der Live-Applikation bzw. des Repositories auf GitHub, GitLab und Co.

Um das zu erreichen, coded man neue Features nicht im Master, sondern erstellt einen eigenen Branch. Das macht man bei Git ganz einfach mit dem Befehl "checkout" und dem Zusatz "-b":

git checkout -b newFeature

Danach befindet man sich direkt in dem neu erstellten Branch "newFeature". Mit dem Befehl "chekout" ohne "-b" kommt man wieder zurück in den Master-Branch:

git checkout master

Alle existierenden Branches kann man sich ganz einfach mit dem Befehl "branch" anzeigen lassen:

git branch

Die Navigation durch die Branches ist also ganz simpel.

Jetzt kommt der Bug

Wenn jetzt ein Bug kommt, kann man den Stand im "newFeature"-Branch kurz durch einen Commit sichern, in den Master wechseln und den Bug dort beheben.

Schritt 1: Den aktuellen Code-Stand sichern:

git add --all
git commit -m "Mein letzter Stand Feature XYZ"

Schritt 2: In den Master-Branch wechseln:

git checkout master

Schritt 3: Den Master kurz mit dem Stand auf GitHub abgleichen

git pull

Dieser Schritt (Abgleich mit dem GitHub-Master) ist eigentlich nur bei Social-Coding-Projekten nötig, wenn andere Coder Änderungen vorgenommen haben, die ich dann erst noch in meinen lokalen Master übernehmen muss.

Schritt 4: Bug beheben

Schaut man sich die Dateien auf dem Rechner an, dann stimmen die Dateien wieder mit dem Master-Stand überein. Sprich: Die Änderungen, die ich im Branch "newFeature" vorgenommen habe, sind auf dem Datei-System nicht mehr zu sehen. Das ist die Magic hinter Git. Der Einfachheit halber fixe ich den Bug mal direkt im Master.

Schritt 5: Bug pushen

Ist der Bug gefixt, pusht man den geänderten Master wieder zu GitHub:

git status
git add --all
git commit -m "Fix for Bug XYZ"
git push origin master

Jetzt ist der Bug gefixt und der Code auf GitHub wieder aktuell. Parallel macht man natürlich auch ein Live-Deployment.

Git-Merge

Nach der ganzen Prozedur kann man wieder in den newFeature-Branch wechseln und an der neuen Version weiterarbeiten. Ein Schritt fehlt allerdings noch: Man muss den BugFix aus dem Master-Branch in den newFeature-Branch übernehmen. Das geht bei Git mit dem "Merge" befehl.

**Schritt 1: In den newFeature-Branch wechseln

In den newFeature-Branch wechselt man wieder mit dem Checkout-Befehl:

git checkout newFeature

Schritt 2: Den Bugfix übernehmen

Jetzt übernehme ich mit "merge" den Bugfix aus dem Master-Branch:

git merge master

Damit ist im besten Fall schon alles fertig. Es sei denn, beim Mergen treten Konflikte auf.

Merge-Konflikte

Konflikte treten beim Mergen immer dann auf, wenn Code-Stellen im Master-Branch geändert wurden, die auch im newFeature-Branch bearbeitet worden sind. Die Konflikte werden dann im Code mit recht auffälligen Markern gekennzeichnet:

<<<<<<< HEAD
echo "Hello";
=======
echo "Welcome";
>>>>>>> branch-master

Die erste Version ist immer die Version aus dem Branch, in dem man sich gerade befindet, in diesem Fall also der newFeature-Branch. Die zweite Version ist der gemergte Branch, in diesem Fall also der Master.

Schritt 1: Konflikt lösen

Die Konflikte kann man Lösen, indem man eine der beiden Varianten übernimmt oder eine neue, finale Variante erstellt. In diesem Fall wird einfach die Code-Version aus dem Master übernommen und der Rest gelöscht. Es bleibt also nur eine Code-Zeile stehen:

echo welcome;

Schritt 2: Änderungen committen

Die finale Version wird anschließend über den üblichen Weg committet.

git add --all
git commit -m "Conflict resolved by incorporating the solution of the master-branch"

Schritt 3: Erneut mergen

Jetzt kann man den Master-Branch ohne Konflikte in den newFeature-Branch mergen und damit den Bugfix übernehmen:

git merge master

Die Strategie optimieren

Diese sehr einfache Strategie hilft bei dem beschriebenen Problem mit dem Bug. Durch den separaten Branch "newFeature" wird die Weiterentwicklung vom Master getrennt, sodass der Code-Stand des Masters immer dem Live-Stand und dem Stand auf GitHub entspricht.

Man kann die Strategie allerdings noch optimieren, indem man:

  1. Auch für den Bugfix einen eigenen Branch erstellt.
  2. Ggf. mit Versions-Nummern arbeitet, die zu dem Projekt passen.

Ich wende bei meinen sehr kleinen Projekten eine möglichst einfache Strategie mit drei Versionsnummern an, zum Beispiel "1.2.3". Die Nummern bedeuten:

1: Hauptversion. Ändert sich nur bei fundamentalen Neuerungen. 2: Nebenversion. Ändert sich bei größeren neuen Features. 3: Revision. Ändert sich bei Bugfixes und kleineren Neuerungen.

In der Regel arbeite ich immer langfristig an der nächsten Nebenversion mit größeren Änderungen und neue Features. Dafür erstelle ich einen neuen Branch:

git checkout -b version1.3.0

Wenn ein Bug reinkommt oder kleine Änderungen schon vorher live gehen sollen, dann erstelle ich dazu eine neue Revisions-Version:

git checkout -b version1.2.4

Ist der Bugfix fertig oder sind die Änderungen übernommen, merge ich die Revision 1.2.4 erst einmal mit dem Master. Der Master entspricht zu diesem Zeitpunkt ja noch der Version 1.2.3:

git add --all
git commit -m "Version 1.2.4 mit Bugfix und Änderung XYZ"
git checkout master
git merge version1.2.4

Version 1.2.4 ist jetzt im Master. Und diese Version pushe ich live:

git push origin master

Den alten Branch "version1.2.4" benötigt man nicht mehr, also kann man ihn löschen:

git branch -d version1.2.4

Anschließend wechsele ich wieder in die neue Nebenversion 1.3.0 und übernehme die Änderungen aus dem Master, der nun in der Version 1.2.4 vorliegt:

git checkout version1.3.0
git merge master

Die Strategie funktioniert für mich bei einem kleinen Projekt recht gut. Wenn man allerdings an größeren Projekten mit mehreren Leuten arbeitet, wird man mit dieser einfachen Strategie schnell an seine Grenzen stoßen. Man kann allerdings auch komplexere Strategien relativ einfach adaptieren, wenn man sich an die einfache Strategie mit Branches und Versionen einmal gewöhnt hat.

Dieser Beitrag gehört zu der Serie "git". Das sind alle Artikel der Serie:

Wenn du ein Web-Projekt von A-Z erstellen willst, findest du im Themenüberblick viele Artikel zu jedem Schritt.