Best Practices mit Git

Die beiden unteren Commits sind zwar physisch, aber nicht logisch getrennt. Besser wäre es, statt zweien nur einen Commit zu erzeugen. Das sollte bestenfalls geschehen, bevor der Bugfix Branch zurückgeführt wird. Git bietet hier ein hervorragendes Tool, und zwar den interactive rebase, der einfach mit git rebase -i gestartet wird. Der interactive rebase öffnet automatisch den voreingestellten Editor (in M.s Fall unter Ubuntu den vim, siehe Listing 1).

Listing 1
#start interactive rebase
git rebase -i HEAD~2
# in vim
pick fe8b38f Bugfix-4711 - correct condition for error label
pick fa227fb Improved Javadocs a bit
# Rebase 9950f83..fa227fb onto 9950f83
#
# Commands: 
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell

Über einen interactive rebase hat M. die Möglichkeit, die lokale Historie zu ändern, solange noch nichts in das zentrale Repository eingecheckt wurde. Die Möglichkeiten, die sich M. hier bieten, sind u. a. das Ändern einer Commit Message im Nachhinein (Option r – reword) oder mehrere Commits zusammenzulegen (in git auch als squashen bezeichnet):

git rebase -i HEAD~2

Die Syntax des interactive rebase ist sehr sprechend, beispielsweise besagt der verwendete Ausdruck HEAD~2, dass vom obersten Commit aus die letzten beiden (~2) Commits bearbeitet werden sollen. Die exakte Beschreibung des mächtigen rebase-Befehls würde den Artikel sprengen, ist aber ausführlich in [1] dokumentiert.

Da M. einige Commits zusammenfassen möchte, ist der interactive rebase das Tool der Wahl. Hierzu editiert er lediglich die Zeilen der betroffenen Commits und macht beispielsweise direkt im Editor aus dem pick am Anfang der Zeile ein f für fixup. Hierdurch werden die beiden Commits „gesquashed“ und ein neuer Commit entsteht, wobei die Commit Message des früheren Commits erhalten bleibt:

pick fe8b38f Bugfix-4711 - correct condition for error label
f fa227fb Improved Javadocs a bit
#now check the logs
git shortlog
initial project commit
Bugfix-4711 - correct condition for error label

Achtung, über einen interactive rebase wird die Historie verändert, da ggf. Commits verschwinden oder sich ändern können. Dieses Tool sollte also mit Bedacht verwendet werden und auch nur bei Commits, die nicht schon in einem öffentlichen Repository verfügbar sind.

Git Tags – Machen wirs gleich fix

Als Best Practice hat sich in M.s Team eingebürgert, dass sowohl Bugfix als auch Feature-Branches vor dem Zurückführen getaggt werden. Git verfügt über zwei Arten von Tags, Annotated- und Lightweight-Tags. Der Unterschied ist marginal, ein Lightweight-Tag ist lediglich eine Referenz auf einen Commit in der Historie, ein Annotated-Tag ist ein eigenes Objekt, welches auf einen Commit in der Historie referenziert. M. arbeitet grundsätzlich mit Annotated-Tags (Option -a), da diese beispielsweise signiert werden können:

#create a tag with name Bugfix-4711
git tag -a -m "Bugfix-4711" Bugfix-4711

Durch den Tag lässt sich später sehr einfach nachvollziehen, ob ein bestimmter Bugfix oder ein bestimmtes Feature bereits reintegriert wurde, indem die vorhandenen Tags betrachtet werden:

#list all tags
git tag
Bugfix-4711

Der nächste Schritt besteht für M. nun darin, den Bugfix-Branch sowohl auf den stable-release als auch den master zurückzuführen:

#reintegrate to stable-release 
git checkout stable-release
git merge bugfix-4711
#reintegrate to master 
git checkout master
git merge bugfix-4711

Warum aber auf beide Branches? Damit kommt exakt der Vorteil des dedizierten stable-release Branches zum Tragen. M. kann ein Bugfix-Release in das Produktivsystem veranlassen, der nur einen bestimmten Bugfix enthält, selbst wenn auf dem master eventuell schon weitere Features entwickelt wurden. Es ist sehr wichtig, dass der Bugfix sowohl auf den stable-release als auch den master zurückgeführt wird, da der stable-release bei jedem Major-Release gelöscht und neu vom master gezogen wird. Alternativ hätte M. den Bugfix auch nur auf den master zurückführen und diesen anschließend auf den stable-release mergen können (Abb. 2, Nr. 5), somit würden aber alle Features vom master mit ausgeliefert.

Der letzte Schritt besteht für M. nun darin, den master auf den next Branch zu mergen, sodass der Bugfix auch in zukünftigen Versionen verfügbar ist. (Abb. 2, Nr. 3).

#reintegrate to stable-release 
git checkout next
git merge master

Damit hat M. alles vorbereitet und kann im Prinzip, sobald er im Büro ist, direkt eine neue Lieferung in das Produktivsystem veranlassen. Wohlgemerkt, M. sitzt noch immer im ICE in Richtung Nürnberg.

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.