Painless Branching

Nach Painless Bug Tracking (Spolsky), Painless Iterations (Myself) und Painless Wireframing (Myself) möchte ich die „Painless“ Serie um Painless Branching erweitern.

Versionskontrolle ist heutzutage doch wirklich ein Standardtool. Völlig egal ob SVN, GIT, Mercurial oder TFS zum Einsatz kommt. Als professioneller Entwickler sollte man wissen, wie man korrekt branchen und mergen kann.

Branching ist wichtiger als Merging!

In (Tortoise) SVN z.B. hat man unzählige Möglichkeiten für den Merge. Aber wer sich zunächst mit dem Merge beschäftigt, macht schon etwas falsch. Bevor man etwas entwickelt, sollte man sich die Branchstrategie gut überlegen! Und die kann ganz unterschiedlich sein. Ich habe selbst nicht alle eingesetzt und kann daher nicht über alle praktisch urteilen, aber ein Grundprinzip gilt:

so viel Branches wie nötig, so wenig wie möglich

Merges verursachen Aufwand. Mit guten Tools und guter Strategie weniger, mit schlechten Tools und planlos umso mehr. Aber Merges verursachen immer Aufwand! Wenn man diesen vermeiden kann, dann sollte man es tun.

Dann könnte man natürlich auf die Idee kommen, dass man gar keine Branches benötigt. Für mich gilt aber die minimale Branch-Regel:

  • ein Development Branch (oft im trunk)
  • ein Maintenance-Branch je veröffentlichter Version

Ein Maintenance-Branch je Version wird benötigt, um einen Bug in der konkreten Version zu fixen und unabhängig von anderen Versionen zu veröffentlichen.

Für eine Webanwendung, Website bzw. SaaS-Anwendung könnte es im einfachsten Fall bedeuten, dass es einen Maintenance-Branch gibt und einen Development-Branch. Wenn man eine installierbare Anwendung vertreibt, benötigt man je noch unterstützter Version einen Maintenance-Branch.

Ob man jetzt die Entwicklung auch noch in verschiedene Branches z.B. Feature Branches unterteilt ist dann schon eine „Advanced“ Entscheidung und eine Frage der Kultur und Kür, die Trennung von Maintenance und Development ist hingegen Pflicht.

Maintenance-Merge von Alt nach Neu

Um bei Merges nicht den Überblick zu verlieren, ist eine klare Richtung des Merges wichtig. Bewährt hat sich dabei die Methode, Änderungen immer von alt nach neu zu mergen. In den alten Versionen werden tendenziell am wenigsten Änderungen – wohl nur kritische – vorgenommen, während im Development sich die Code-Basis eventuell sehr intensiv verändert.

Was würden Sie vorziehen – den Bugfix zunächst in der neuesten Version zu machen, wo im Log 25 Commits pro Tag stehen und dann den Bugfix in ältere Versionen zu übertragen?

Die Frage war natürlich rhetorisch. So müssen Merges ablaufen:

LowToHi

Die Abbildung ist zwar idealisiert, aber typisch. Ich habe es noch nicht erlebt, dass ein Bug in Version 1.0 enthalten ist, in 1.1. nicht, dann aber wieder in 2.0 – jedenfalls wenn eine korrekte Branching-Strategie umgesetzt wird.

So ist das Vorgehen für einen Bugfix:

  • Ein Bug wird gemeldet, reproduziert und als Must-Fix eingestuft und eingeplant
  • Ausgehend von der gemeldeten Version, wird die niedrigste unterstützte Version gefunden, in welcher der Bug auftritt
  • Der Bug wird in der niedrigsten Version gefixt, getestet und deployed
  • Der Bugfix wird stufenweise in alle neuen Branches übertragen, in denen er noch reproduzierbar ist (er kann sich natürlich durch Änderungen erübrigt haben)

Tools wie Tortoise SVN helfen wirklich ungemein beim Merge. So werden bspw. alle bereits übertragenen Revisionen im Change-Log beim Merge grau dargestellt.

Mit dem richtigen Vorgehen und gutem Tooling ist ein Merge und der aktuelle Merge-Stand jederzeit einfach nachvollziehbar.

Easy.