Releasemanagement und CONTACT Elements¶
Contents
Ein geordnetes Releasemanagement ist reproduzierbar, trägt zu einer Verkürzung der Durchlaufzeiten von Änderungen bei und mindert die Risiken in Projekten. Kurzum; das Releasemanagement ist ein wichtiger Baustein der Projekt-Planung und -Durchführung. Softwareentwicklung ist immer eine Team-Leistung bei der die Team-Mitglieder ihre Änderungen aus verschiedensten Projekten in EINE Infrastruktur einbringen. Diese Änderungs-Beiträge durchwandern i.d.R. noch (Anwender-) Tests und BugFixing bevor sie schlussendlich in den Rollout gehen. Aufgabe des Releasemanagement ist es, Entwicklungsprozesse über alle Phasen des Projekts hin zu erfassen und einem geordnetem Verfahren zu unterwerfen.
Das Releasemanagement kann nicht willkürlich ausgelegt werden, es wird maßgeblich bestimmt durch die Verfahren, mit denen eine Änderung durch eine Infrastruktur transportiert werden kann. Bei CONTACT Elements basiert der Transport von Änderungen auf der Komponentenarchitektur (s.a. Foliensammlung CDB Komponenten & Entwicklung). Die Komponentenarchitektur kennt eine Teilung nur entlang der Pakete. Damit ist gemeint, dass ein Transport immer alle Änderungen eines ganzen Pakets umfasst, die Pakete zueinander aber entkoppelt sind.
Die parallele Entwicklung an unterschiedlichen Paketen ist durch die Komponentenarchitektur ausreichend entkoppelt.
Dieser Artikel befasst sich ausschließlich mit der Problematik die entsteht, wenn mehrere Veränderungsprojekte in einem Paket parallel umgesetzt werden müssen (was quasi für alle Kunden-Pakete der Fall ist).
Der Transport einer Änderung umfasst immer das ganze Paket.
Ein (Kunden-) Paket kann immer nur als ganze Einheit transportiert werden. Es ist nicht möglich zwei unterschiedliche Entwicklungen an einem Paket gleichzeitig aber doch für sich getrennt durch ein System (z.B. QS) zu transportieren.
Aus Sicht der Weiterentwicklung von Kundenanpassungen (cust.plm
) wird hier
schon die erste maßgebliche Einschränkung des Releasemanagement deutlich: Im
Grunde können Weiterentwicklungen an einem (Kunden)-Paket nur nacheinander
entwickelt, getestet und ausgerollt werden.
In der Praxis wird man ein Releasemanagement finden müssen, dass einem unter den gegebenen Rahmenbedingungen mehr Flexibilität bietet: Es muss immer mal wieder ein HotFix angebracht werden und es muss ein Verfahren zur parallelen Entwicklung geben. Auch wenn dieses Verfahren nicht über eine so schöne Entkopplung wie die Pakete zueinander verfügt und deshalb auch etwas aufwendiger sein wird als in getrennten Paketen parallel zu entwickeln.
Bei typischen CDB-Kunden existiert in der Kundenanpassung i.d.R. nur ein Paket
(cust.plm
) und es wird dafür ein geordnetes Releasemanagement benötigt. Die
hier im Artikel aufgezeichneten Entwicklungslinien aus Abbildungen wie big
picture zeigen immer die Entwicklungslinie eines
Pakets. An der Trennung der Pakete wird schon deutlich, dass auch die
Architektur der Kundenanpassung einen maßgeblichen Einfluss auf die
Projekt-Planung resp. das Releasemanagement haben kann.
Exkursion: Design & Architektur der Kundenanpassung
Auch eine Kundenanpassung kann in mehrere Pakete aufgeteilt werden. Die eigentliche Herausforderung dabei ist es, geeignete Schnittlinien zu finden, die der Projekt-Planung und dem Releasemanagement auch zukunftssicher mehr Freiheiten einräumen. Bei den sich heute rasch ändernden Unternehmen sind Schnittlinien – die auch in weiter Zukunft noch ihre Berechtigung haben – im Vorfeld schwer festzulegen. Eine mögliche Schnittlinie könnte entlang der Sparten eines Unternehmens erfolgen, wenn man weiß, dass die Sparten mit unterschiedlichen Geschwindigkeiten Änderungsanforderungen an die CONTACT Elements Infrastruktur stellen werden. Es gibt dafür aber keine allgemeingültige Regel, weshalb wir hier nicht weiter auf dieses Thema eingehen wollen.
Die hier vorgestellten Verfahren zum Releasemanagement basieren auf einem allgemein als Feature Branch bekanntem Workflow. Dieser wird auch im CDB Handbuch zur Komponentenarchitektur vorgestellt.
Die im CDB Handbuch zur Komponentenarchitektur vorgestellten Verfahren gehen von idealen Bedingungen der CONTACT Elements Infrastruktur aus. Unter solch idealen Bedingungen werden theoretisch alle Änderungen innerhalb eines Pakets auch vom Paket erfasst. Für Softwarepakete von CONTACT oder Drittanbietern mag das (inzwischen) auch stimmen. In der Praxis wird eine Weiterentwicklung an den Kundenpaketen jedoch von Faktoren geprägt sein, die über den Scope des Pakets hinaus gehen. Dazu gehören Objekte zum Testen, Objekte die ggf. noch nicht im Kundenpakt aufgenommen wurden (z.B. Bugs wie ‚Zuordnung zum Paket fehlt‘ / ‚mangelhaftes DB-Schema‘) oder beispielsweise die Anbindung von (Unternehmens-) Software an die Kundeninstanz, welche nicht von CDB-Komponenten abgedeckt wird.
komplette Instanz wird SCM-System versioniert
Es werden alle Dateien aus $CADDOK_BASE
in die Versionsverwaltung mit
aufgenommen. Das umschließt die komplette Installation des
Applikation-Servers mit den Paketen in $CADDOK_BASE/site-packages
und den
Konfigurationen (z.B. aus $CADDOK_BASE/etc
). Nicht dazu gehören der
BLOB-Store und temporäre Speicher wie z.B. ./tmp
und ./app_conf
.
Eine CONTACT Elements Installation verfügt immer über Anpassungen:
im Source Code und
in der DB
Sourcen und Konfiguration in der DB bilden eine Einheit.
Jede Änderung und sei es nur eine kleine Änderung an der Konfiguration muss dem Releasemanagement untergeordnet werden! Man sollte nicht einfach irgendwo in einem uralten System was konfigurieren und davon ausgehen, man könne diese Änderung mal eben kurz ausrollen und dabei das Releasemanagement umgehen. Jede Änderung steht potentiell im Konflikt mit anderen, parallelen Entwicklungslinien und muss eingeplant werden.
Da wir nicht sicher sein können, dass alle Konfigurationen auch im cust.plm
Paket enthalten sind (aus oben genannten Gründen) und weil wir auch die
Nutzdaten im Rahmen einer Entwicklung brauchen gilt für das hier vorgeschlagene
Releasemanagement zusätzlich noch:
DB Export zu jedem Branch-Point
Sobald eine Entwicklung abzweigt (branch) wird ein Export der DB gesichert. Die Entwickler können sich dann ein Entwickler-System aus dem DB Export aufbauen (s.a. Initialisieren eines CDB Spiegel-Systems).
Näheres zum DB-Export kann weiter unten im Abschnitt zum Anlegen des Branch-Point nachgelesen werden. Hier noch ein paar umgangssprachliche Nomenklaturen:
- Rollout
Markteinführung einer Änderung
- PROD
Im Betrieb befindliche CONTACT Elements Infrastruktur, Ziel aller Weiterentwicklungen.
- QS
CONTACT Elements Infrastruktur die für die Anwendertests der Änderungen bereit gestellt wird.
- Commit
Kleinste Einheit einer Änderung die im SCM-System versioniert werden kann auch atomare Änderung genannt und in den Abbildungen mit einem Kreis dargestellt (Hintergrundfarbe kann in den Abbildungen je nach Bedeutung des Commits variieren)
- HotFix
Eine Fehlerbehebung (i.d.R.) im PROD-System um den Betrieb erst mal aufrecht zu erhalten. Auch solche Änderungen müssen im Releasemanagement beachtet werden und werden im SCM-System versioniert. Jeder HotFix ist auch ein commit, in den Abbildungen mit einem Kreis dargestellt:
- Merge
Die Zusammenführung zwei oder mehrerer Entwicklungen, meist aber die Zusammenführung zweier Entwicklungslinien. Abgesehen von seltenen Ausnahmen (fast-forward) ist der Merge auch immer eine Änderung, ein commit im SCM-System der auch merge-point bezeichnet wird. In den Abbildungen mit einem Kreis dargestellt:
- Branch:
master
Haupt-Entwicklungslinie und i.d.R. auch gleichzeitig Stand des PROD
- Branch:
qs
Entwicklungslinie der QS
- Branch-Point
Abzweigung resp. Start-Punkt einer Entwicklungslinie. In den Abbildungen durch einen gelben Kreis gekennzeichnet.
- System-Branch
Entwicklungslinie einer Instanzen wie QS oder PROD. Zu diesen Branches gibt es immer eine aktive Instanz an der sich Anwender & Entwickler anmelden können. Beispiele hierfür sind die QS zum Testen und die PROD für den regulären Betrieb. Diese Instanzen verfügen über eine voll ausgebaute und lauffähige CONTACT Elements Infrastruktur inklusive der Kopplungen zu externen Systemen wie beispielsweise SAP oder Konvertierungs-Diensten.
- Feature-Branch
Entwicklungslinie eines Veränderungsprojekts. Wird z.T. auch als Dev-Branch bezeichnet. I.d.R. sind die Instanzen zu solchen Branches nur für die Entwickler zugänglich. Sie verfügen auch nur über einen, für die Änderung minimal erforderlichen Ausbau. Fremdsysteme wie SAP werden beispielsweise nur dann angebunden, wenn dies für die Umsetzung des Feature erforderlich ist. Die Instanzen zu dem Feature-Branch existieren teilweise nur beim Lieferanten und nur für die Zeit der Entwicklung bis zum Rollout, danach können die Instanzen wieder verworfen werden.
Big Picture¶
Bereits in der Einleitung wurde festgestellt, dass ein sauberess Releasemanagement nicht willkürlich sein kann; es muss kausalen Ketten folgen und unter den gegebenen Rahmenbedingungen (s.o. Transport) abbildbar sein. Welche Rahmenbedingungen im Einzelnen zu beachten sind soll im Weiterem erarbeitet werden. Als Gegenstand dient eine exemplarische Infrastruktur mit:
einer PROD Instanz für den Betrieb der Anwendung im Unternehmen und
einer QS Instanz in der (Anwender-) Tests durchgeführt werden.
Eine solche Infrastruktur (big picture) ist sicherlich die kleinst-mögliche, sie reicht aber aus um die Anforderungen und Verfahren rund um das Releasemanagement zu erörtern. In der Praxis wird man oftmals eine etwas größere Infrastruktur, evtl. mit einem HotFix-System und einer gemeinsamen Entwickler Umgebung (DEV) vorfinden und für Planung und Test des Rollout wird man sich ggf. noch einen Spiegel des PROD Systems anlegen. Ganz gleich wie aufwendig die Infrastruktur letztendlich ist, es wird eine koordinierende Instanz benötigt; der Maintainer.
Der Maintainer koordiniert alle Änderungen (im SCM)
Die Koordination der Änderungen im Entwicklerteam, den Anwendertests und den Rollouts übernimmt der Maintainer. Der Maintainer verwaltet das zentrale Repository und vermittelt zw. den Projekt-Terminen und den dadurch erforderlichen Planungen in der Entwicklung & im Test.
Um die am System angebrachten Teil-Änderungen zu verwalten bedient man sich eines Source-Code-Managment-Systems (SCM). Die parallelen Entwicklungen auf Basis der CDB Komponentenarchitektur bedingen entsprechend viele parallele Entwicklungslinien (a.k.a. Branches, s.a. SCM-Branching). Damit empfiehlt es sich git als SCM-System einzusetzen, da es über ein besonders leichtes, schnelles und flexibles Branching-Model verfügt.
Als SCM-System bietet sich git an
Andere SCM-System insbesondere zentrale SCM-Systeme wie SVN eignen sich weniger, da sie bei der Arbeit mit Branches zu schwach sind und kaum brauchbare Unterstützung bieten. Sollten Sie noch SVN verwenden, dann wechseln Sie JETZT zu git. Siehe auch Foliensammlung zur pragmatischen Einarbeitung: get git started.
Die Abbildung big picture zeigt den zeitlichen Verlauf dreier Änderungen in einer Infrastruktur mit PROD und QS. Der gezeigte verlauf ist exemplarisch. In den eigenen Projekten wird der Verlauf von der Projekt-Leitung und dem Maintainer gemeinsam geplant. Insbesondere wenn es zu Verzögerungen im Verlauf eines Veränderungsprojekts kommt, besteht ein hoher Abstimmungsbedarf zw. Projekt-Planung und Release-Planung. Dabei wird die Projekt-Planung dominiert von den Faktoren Resourcen und Terminen und die Release-Planung muss abschätzen in wie weit sie die Entwicklungslinien insbesondere der System-Branches unter den gegebenen Rahmenbedingungen (s.o. Transport) möglichst ohne Verluste und mit vertretbarem Aufwand der Projekt-Planung entsprechend anpassen kann.
Jeder kreisförmige Punkt in der Abbildung big picture entspricht einer Teil-Änderung die im SCM-System
erfasst wird (commit). Die Teil-Änderungen entlang einer
Entwicklungslinie wie z.B. foo
beschreiben in ihrer Gesamtheit die
Implementierung eines Änderungsauftrags resp. des Features. Eine Linie von
Teil-Änderungen wird auch als Patch-Serie bezeichnet.
Links von t0 (jetzt-Zeit) ist die Historie und rechts der
Planungsverlauf zu sehen. In oberster Linie ist die Entwicklungslinie des im
Betrieb befindlichen PROD Systems zu sehen. Darunter die Entwicklungslinie des
QS-Systems. Des Weiteren sind noch die Entwicklungslinien zweier
Weiterentwicklungen (Feature-Branch) zu sehen,
die im Folgenden nur mit den Platzhaltern foo
und bar
unterschieden
werden sollen. In der Projekt-Planung ist vorgesehen, die aktuellen Änderungen
aus dem QS noch in den Rollout zu bringen, danach soll der foo
Branch in die
QS gemerged werden und dann ebenfalls in den Rollout gehen. Die Planung für den
Feature-Branch bar
ist nur bis zum Merge in die QS dargestellt. So
zumindest die Planung zum Zeitpunkt t0. Der hier gezeigte Verlauf ist
exemplarisch; er soll u.A. erkennen lassen:
Die Abspaltung von Entwicklungslinien sollte immer vom aktuellen PROD (master) aus erfolgen.
Abspaltung immer von der Entwicklungslinie des PROD (master)
Ob und in welcher Form eine aktuelle Änderung z.B. aus dem QS-System überhaupt in Betrieb genommen wird, kann im Vorfeld nie mit absoluter Sicherheit gesagt werden. Deswegen empfiehlt es sich, jede Änderungen immer direkt vom aktuellen PROD ausgehend zu starten (s.a. Branch-Point).
In der Praxis wird die Entwicklungslinie eines System-Branch wie QS etwas anders ausgeprägt sein als die Entwicklungslinie eines Feature-Branch wie
foo
.
System-Branches regelmäßig aus PROD aktualisieren
Abspaltungen für Systeme wie z.B. QS werden regelmäßig aus der PROD aktualisiert, z.B. nach Abschluss eines Rollouts. Um Konflikte beim Merge in die PROD zu reduzieren sollte die Distanz der aktuellen Zustände von PROD und anderen Branches, insbesondere der System-Branches so klein wie möglich gehalten werden.
Zusammenfassung der Entwicklungslinien aus der Abbildung big picture:
foo
&bar
Zwei exemplarische Weiterentwicklungen die z.B. an einen Lieferanten beauftragt wurden oder aber im eigenen Haus abgewickelt werden. Beide Entwicklungslinien wurden, wie die QS vom PROD abgespalten (branch) und beide werden später wieder mit der PROD zusammengeführt (merge).
- PROD
Die letzte Änderung vor t0 war ein HotFix. Planmäßig sollen als Nächstes (in der Reihenfolge) die letzten Änderungen aus QS, aus
foo
und ausbar
in den Betrieb genommen werden.- QS
Zum Zeitpunkt t0 befindet sich eine Änderung in der QS, die in der Projektplanung als nächstes ausgerollt werden soll. Für den Rollout muss die QS mit dem PROD zusammengeführt werden (merge). Etwaige Konflikte aus den Änderungen aus dem HotFix mit den letzten Änderungen aus dem QS müssen aufgelöst werden.
Zusammenführung zweier Entwicklungslinien¶
Die Zusammenführung zwei Entwicklungslinien wird allgemein auch als merge bezeichnet. Der Merge ist die eigentliche Herausforderung im Rahmen des Releasemanagement. Ziel ist es, die Änderungen aus der einen Entwicklungslinie mit denen aus einer anderen Entwicklungslinie zusammenzuführen. Im Folgendem Beispiel sollen die vier Änderungen aus dem QS Branch in den PROD Branch gemischt werden. Die Abbildung qs-merge zeigt die Entwicklungslinie des QS Branch bevor (obere Hälfte) und nachdem (untere Hälfte) die Änderungen aus diesem Branch in den master (PROD) gemerged wurden.
Die Vorgehensweise beim Mergen ist immer gleich, egal ob man einen (Feature-) Branch merged, oder wie hier eine Änderung aus dem QS übernehmen will. Die Abbildung merge-qs ist von daher, für sich alleine erst mal nur abstrakt. Um das Beispiel etwas konkreter zu machen sei folgender Kontext gegeben:
Im PROD war ein Maskenfeld mit einem Auswahlbrowser konfiguriert. Dieser Auswahlbrowser lieferte aber falsche Werte. Damit die Anwender erst mal weiter arbeiten können wurde im PROD ein HotFix angebracht, mit dem die Editierbarkeit des Maskenfeld von ‚nur aus dem Katalog zu befüllen‘ (
catalog
) in ‚frei editierbar‘ (free
) geändert wurde. Anschließend hat man das Problem mit dem Auswahlbrowser (zeitnah) in der QS korrigiert. Dazu wurde keine neue QS aufgesetzt, sondern die bestehende genutzt, die wurde allerdings bereits abgespalten (branch) als der HotFix noch nicht im PROD war.
Das Beispiel mag etwas konstruiert anmuten, es beschreibt aber einen typischen
Fall (conflict), dem bei einem Merge besondere Beachtung geschenkt werden
muss. Schon aus der Beschreibung oben wird klar, dass im PROD und im QS parallel
und unabhängig voneinander an dem problematischen Maskenfeld (bzw.
Auswahlbrowser) Änderungen vorgenommen wurden: im PROD ist das Feld free
und
im QS muss es – mit dem korrigierten Auswahlbrowser – auf catalog
konfiguriert sein. Werden die beiden Entwicklungslinien nun zusammengeführt, so
besteht ein Konflikt zw. dem HotFix und dem letztem Stand der QS
, der nun gemerged werden soll.
An welchem Commit der Konflikt mit der QS Entwicklungslinie auftritt brauchen wir nicht zu wissen, wir sollten nur wissen, dass es immer zu Konflikten kommen kann, wenn zwei Entwicklungslinien zusammengeführt werden. Konflikte müssen erkannt und dann fachlich aufgelöst werden, so dass aus der Summe der beiden Entwicklungslinien eine funktionierende und sinnvolle Anwendung entsteht.
Konflikte müssen fachlich/inhaltlich aufgelöst werden, dafür gibt es keine Tools.
Vorausgesetzt die Entwicklungslinien sind kurz und bauen aufeinander auf, so sind die meisten Konflikte eher inhaltlicher/fachlicher Natur. Tools können helfen solche Konflikte zu erkennen, sie können aber keine fachlichen Fragen beantworten und sind somit auch nicht in der Lage die detektierten Konflikte selbständig aufzulösen.
Bei Weiterentwicklungen auf Basis der CONTACT Elements gibt es zwei Arten von potentiellen Konflikten:
Konflikte im Quellcode: meist werden diese schon durch das SCM System (git) beim Merge erkannt. Der Merge Vorgang bleibt an der Stelle dann stehen und man muss ggf. manuell noch korrigierend eingreifen.
Konflikte in der Konfiguration: Die Konfigurationen in der DB werden in JSON Dateien exportiert und im (Kunden-) Paket transportiert. Die JSON Dateien kann man nicht mit dem SCM mergen. Für die Zusammenführung zweier Konfigurationen gibt es die Tools
cdbpkg diff
undcdbpkg patch
. Nach demcdbpkg patch
kann man die Konflikte in CDB recherchieren und diese (fachlich) in CDB interaktiv auflösen.
Die Vorgehensweisen beim Merge werden im Abschnitt Merge mit git und cdbpkg Tools detailliert beschrieben. Egal ob mit oder ohne Änderungen an der Konfiguration, es gilt immer:
Der Merge zweier Entwicklungslinien wird immer mit SCM-Commit abgeschlossen.
Beim Merge wird die Patch-Serie aus der einen Änderungslinie (QS) nahtlos an die andere Entwicklungslinie (PROD/master) angehängt. Alle einzelnen Commits aus QS sind jetzt Teil von PROD. Der merge-point ist auch ein Commit, er trägt u.A. die Änderungen in sich, die im Rahmen des Merge zur Konfliktauflösung vorgenommen wurden.
Im unteren Teil der Abbildung qs-merge: Zusammenführung der Änderungen aus QS mit PROD ist bereits die PROD Entwicklungslinie nach dem Merge dargestellt. Die Abb. big-picture (tqs-merge): Entwicklungslinien nach merge-qs zeigt das Eingangs gezeigte big picture nach dem Merge. In beiden Darstellungen ist zu sehen, dass sich die Commits, die vor dem Merge nur in der QS-Linie waren, nun in der PROD-Linie wiederzufinden sind. Der HotFix aus dem PROD verbleibt ebenfalls in der Historie, der ggf. vorhandene Konflikt wurde ja im merge-point aufgelöst.
Schaut man auf die Abbildung, so kann man schon erahnen, wie ein Merge des
Foo-branches aussehen würde. Ebenso wie eben beim Merge des QS in die PROD würde
später (gestrichelte Linien) der foo
Branch in die QS gemerged werden, wobei
die Patch-Serie der grünen Linie (foo
) an das Ende der QS angehängt werden
würde.
Merge mit git und cdbpkg Tools¶
Die Zusammenführung zweier Entwicklungslinien soll wieder am Beispiel qs-merge erfolgen, bei dem der QS-Branch in die PROD-Linie gemerged wird (PROD ist das Ziel).
Vor einem Merge oder Branch den letzten Änderungsstand comitten.
Bevor ein Merge durchgeführt oder einen Branch abspaltet wird, muss sichergestellt sein, dass der aktuelle Stand im SCM commited wurde. Insbesondere die Konfiguration aus der DB sollte dabei nicht vergessen werden, hierzu siehe Dump der Konfiguration ins SCM.
Sobald der aktuelle Stand im SCM-System ist, kann mit dem eigentlichen Merge angefangen werden. Ein Merge in CONTACT Elements besteht dabei immer aus zwei Teilen (s.a. potentielle Konflikte beim Merge):
Source Code: wird mit SCM (git) gemerged
Konfiguration in der DB: wird mit
cdbpkg diff & patch
in CDB gemerged.
Die Konfiguration ist zwar in den JSON Dateien und somit im SCM-System enthalten, für einen Merge mit dem SCM-System eignet sich das JSON Format aber nicht.
Vor einem Merge muss das Diff der CDB-Konfigurationen ermittelt werden.
Für die Zusammenführung zweier Konfigurationen erzeugt man mit cdbpkg
diff
einen Patch den man mit cdbpkg patch
einspielen kann. Anschließend
kann man die Änderungen in CDB recherchieren und ggf. vorhandene Konflikte
auflösen.
Das Kommando cdbpkg diff
erechnet die Differenz zwischen zwei Ständen der
Konfiguration eines Pakets. Um die Differenz des Kunden-Pakets (cust.plm
) in
der Änderungslinie (QS) zu berechnen wird dazu der Ausgangspunkt, also
Branch-Point der QS Linie und der letzte Stand der Änderungslinie (QS)
benötigt, siehe Abb. merge: cdbpkg diff & cdbpkg patch:
Der Ausgangspunkt des Feature-Branch ist der branch-point an dem die Änderungslinie abzweigt. Den Commit der Abzweigung kann man mit folgendem Kommando ermitteln:
$ git log --oneline --decorate --graph --all
...
| * 8e448cd (hello-world) hello-world: add changelog
| * 0dd2abe add hello-world script
* | c1ce07c add remark about 'hello world' order
|/
* 9af1a51 add README
* 849c175 inital boilerplate
Obiges Log-Beispiel stammt aus der Foliensammlung get git started, das
Repository dazu ist github.com/return42/git-teaching. Es soll hier ersatzweise
als ein Beispiel dienen um den Commit zu finden, an dem der branch-point
abzweigt. In dem Beispiel ist zu erkennen, dass der
(hello-world)
Branch bei Commit 9af1a51
abzweigt. Neben dem git log
kann man aber auch andere Werkzeuge wie z.B. die Git Extensions verwenden um die Historie zu visualisieren
(s.a. git GUI Clients).
Im Beispiel der Abb. merge: cdbpkg diff & cdbpkg patch zweigt die QS Linie zum Zeitpunkt
tqs ab, hier im Beispiel nehmen wir mal an, dass der Commit zu diesem
Stand die ID 4711
trägt. Damit wir den Diff anfertigen können muss der Stand
zum Zeitpunkt tqs (also Commit 4711
) nun in einen separaten Ordner
ausgecheckt werden. Hier im Beispiel verwenden wir /tmp/qs-branch-point
(kann später wieder gelöscht werden).
# !!! Auf dem Quell-System / im Feature-Branch (z.B. foo oder qs) !!!
# $ git checkout qs # sollte i.d.R. bereits ausgechekt sein
...
# git worktree add <workspace-folder> <branch-point>
$ git worktree add /tmp/qs-branch-point 4711
Nachdem Feature-Branch qs
und der Branch-Point ausgecheckt wurden, kann nun
mit cdbpkg diff
die Differenz zwischen den beiden Konfigurationsständen des
cust.plm
Pakets berechnet werden.
$ cdbpkg diff -p /tmp/qs-branch-point/cust.plm -d /tmp/merge-qs-patch cust.plm
Writing changes to directory /tmp/merge-qs-patch
...
Der cdbpkg-Patch liegt nun im Ordner /tmp/merge-qs-patch
. Der Workingtree
/tmp/qs-branch-point
wird nicht mehr benötigt, er kann jetzt (oder auch
später) aus dem /tmp
gelöscht werden. Mit prune
löscht man ihn dann auch
aus dem lokalem git Repository:
$ rm -r /tmp/qs-branch-point # Worktree im Dateisystem löschen
$ git worktree prune
Nachdem der cdbpkg-Patch vorbereitet ist, kann mit dem eigentlichen Merge angefangen werden. Als Erstes werden die Sourcen mit dem SCM-System gemerged. Dazu wechselt man in den Branch, in dem man die Änderungen mergen will. Wichtig ist wieder, dass die cdbpkg Tools auf einen BLOB-Store und die DB (des Ziel Systems) zugreifen können.
Die cdbpkg Tools müssen beim Merge Zugriff auf das Ziel System haben
Bei einem Merge z.B. von einem Feature-Branch in die QS wird man den Merge meist direkt im QS-System ausführen, da hier die Ausfallzeiten flexibler sind. Die im Betrieb befindliche PROD bietet nur kurze Wartungsfenster für den Rollout, weshalb dieser dezidiert vorbereitet werden muss. I.d.R. findet die Vorbereitung und der Test des Rollouts zeitnah in einem Spiegel-System der PROD statt. Die PROD darf dann bis zum Rollout gegenüber dem Spiegel keine Änderung an den Sourcen oder der Konfiguration erfahren.
Hier in den Beispielen mergen wir immer direkt in das Ziel System, in diesem
Beispiel also direkt in die PROD (master
). Bereits oben wurde erwähnt: Bei
einem Merge muss beachtet werden, dass nur der Source-Code nicht aber die ganze
Konfiguration in den JSON Dateien gemerged werden. Der Merge beginnt deshalb
erst mal ganz normal:
# !!! Auf dem Ziel-System / im Ziel-Branch (z.B. master) !!!
# $ git checkout master # sollte i.d.R. bereits ausgechekt sein
...
$ git merge qs --no-commit --no-ff # SCM merge
Auto-merging cust.plm/cust/plm/module_metadata.json
...
CONFLICT (content): Merge conflict in cust.plm/cust/plm/module_metadata.json
Automatic merge failed; fix conflicts and then commit the result.
Ganz gleich ob man an dieser Stelle (wie hier im Beispiel) einen CONFLICT
erhalten hat oder nicht, das merge
Kommando eines SCM-System führt
i.d.R. immer alle Dateien im Workingtree zusammen. Es werden also auch immer die
JSON Dateien mit dem Kommando gemerged. Hier im Beispiel gab es dabei einen
CONFLICT
, das muss aber nicht unbedingt der Fall sein: manchmal merged das
SCM-Merge auch irgendwas zusammen, was es für richtig hält und dann meldet es
keinen Konflikt. Egal wie, ein SCM-Merge ist nicht für die JSON Dateien
geeignet und wir müssen diesen Teil wieder zurück spulen zu dem, was im
Ziel-Branch (hier der master) versioniert wurde. Am einfachsten geht das im
Rahmen eines git-Merge mit checkout --ours
:
$ cd cust.plm/cust/plm
$ git reset configuration module_metadata.json
$ git checkout --ours configuration module_metadata.json
Bei älteren CDB Versionen (10.x) müssen noch zwei weitere Objekte zurück gespult werden:
$ cd cust.plm/cust/plm
$ git reset content_metadata.json patches # ab CDB 15 nicht mehr erforderlich
$ git checkout --ours content_metadata.json patches # ab CDB 15 nicht mehr erforderlich
Konfiguration (JSON) darf nicht vom SCM-System gemerged werden.
Die Konfigurationen in den JSON Dateien werden nicht gemerged! Für den Merge
der Konfiguration hat man sich mit cdbpkg diff
einen Patch erzeugt, den
man einspielen muss. Anschließend kann man die Änderungen in CDB
recherchieren und ggf. vorhandene Konflikte auflösen..
Mit git status
kann man nun überprüfen ob es auch Konflikte außerhalb der
JSON Dateien im Source-Code gab. Sollte in der Ausgabe noch ein Unmerged paths
auftauchen, so hat man noch nicht alle Konflikte im Source-Code aufgelöst.
Unmerged paths:
both modified: cust/plm/foo.py
Wenn das der Fall ist, muss man diese Konflikte auflösen und die dabei
angebrachten Änderungen wieder mit git add
in den Stage aufnehmen.
Nachdem alle Konflikte aufgelöst sind sollte in der git status
Ausgabe ein
Satz wie All conflicts fixed but you are still merging. zu finden sein, hier
eine beispielhafte Ausgabe:
On branch master
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: cust/plm/foo.py
Der merge der Dateien ist damit abgeschlossen und wir kommen zum zweiten Teil
des Merge, bei dem die Konfiguration gemerged wird. Dazu spielt man den
cdbpkg-Patch ein und nach Prüfung in CDB wird nochmal ein build
erzeugt.
Erst wenn alle Konflikte im Source-Code aufgelöst sind hat man wieder eine
lauffähige Instanz! In deren DB nun der zuvor erzeugte cdbpkg-Patch
/tmp/merge-qs-patch
eingespielt wird:
$ cdbpkg patch /tmp/merge-qs-patch # CDB-Merge
Service-Daemon im Update-Modus
Falls erforderlich kann der Service-Daemon so gestartet werden, dass keine Konsistenzprüfung der Paketinstallation durchgeführt wird [ref]:
cdbsvcd --debug --for_update
Nun kann man in CDB die Änderungen recherchieren und etwaige Konflikte auflösen (Dazu einen build erstellen, alternativ Dev-Build in CDB).
$ cdbpkg build cust.plm
Der Merge ist abgeschlossen, sobald man der Überzeugung ist, dass alle Änderungen aus dem Branch korrekt übernommen wurden. Man hat dann Änderungen im Dateisystem und an der Konfiguration in der DB, die beide noch nicht ins SCM Commited wurden (der Merge ins SCM ist noch nicht abgeschlossen). Um den Merge abzuschließen und ins SCM-System aufzunehmen, muss man wieder einen build erzeugen und dann alles im SCM-System als auch in CDB (app_conf) committen:
$ cdbpkg build cust.plm
...
$ git add --all cust.plm/cust/plm
$ git commit -m "merged branch 'qs'"
$ cdbpkg commit cust.plm
Die Änderungen sind (der Merge ist) jetzt im lokalem Klone des Repository. Er muss irgendwann dann auch mal an den SCM-Server gepusht werden. Bei einem Feature-Branch oder der QS wird man den Push vermutlich gleich durchführen. Bei der PROD (master) gehört dieser Push allerdings zum Rollout und sollte deshalb ggf. für später – am besten kurz vor dem Rollout Termin – eingeplant werden.
Branch-Point¶
Die Aufgabe des Branch-Point ist es, einen klar definierten Zustand festzuhalten
(s.a. Branches-in-a-Nutshell) auf
dem eine Änderungslinie aufbaut. Dieser gesicherte Zustand wird später beim
Merge von CDB benötigt um die Differenz zwischen zwei Konfigurationsständen
(JSON) eines Pakets zu berechnen (vgl. merge: cdbpkg diff & cdbpkg patch). Die Abbildung
branch point zeigt die Entwicklungslinie eines
exemplarischen Feature-Branch foo
in einer Infrastruktur mit PROD und QS.
Inital beginnt der foo-Branch am Branch-Point zum Zeitpunkt tfoo. Die Abspaltung von Entwicklungslinien sollte immer vom aktuellen PROD master aus erfolgen. Dort fangen alle Entwicklungen an, dort müssen sie am Ende auch wieder hin: Abspaltung immer von der Entwicklungslinie des PROD. Ebenfalls in Abbildung branch point zu sehen ist, dass ein System-Branch wie QS regelmäßig aus der PROD aktualisiert wird: System-Branches regelmäßig aus PROD aktualisieren.
Die Aktualisierung eines Feature-Branch aus der PROD sollte nach Möglichkeit nur
selten erforderlich sein, ist aber im Bedarfsfall grundsätzlich möglich. Eine
Aktualisierung des Feature-Branch foo
ist z.B. dann erforderlich, wenn man
im Verlauf des Projekts feststellt, dass eine andere Änderung, die erst nach der
Abspaltung von foo
implementiert wurde (z.B. die Änderungen aus der QS) nun
doch in foo
benötigt wird. In diesen Fällen muss man sich die benötigte
Änderung (Patch-Serie) in den foo
Branch holen, was einem Merge entspricht, bei dem ‚foo‘ das Ziel ist. Alternativ
kann man aber auch einen sogenannten Rebase durchführen, sofern der Feature
noch nicht schon von anderer Stelle aus geclonet wurde (s.a. Merging
vs. Rebasing &
The Golden Rule of Rebasing).
Ein anders Beispiel ist der Fall, bei dem man foo
ins QS gemerged hat und
beim Testen dann weitere Änderungen angebracht hat die man nicht verlieren will,
man aber gleichzeitig feststellt, dass es noch weiterer und ausführlicher
Nacharbeiten bedarf, die nicht mehr im QS – sondern wieder zurück – im
foo
Branch umgesetzt werden müssen, weil jetzt erst mal eine andere
Änderung durch die QS gezogen werden soll.
Vorausschauende Planung hält den Aufwand für Merges klein.
Egal was die Gründe sind, ein Merge ist immer mit einem gewissen Aufwand verbunden, der um so größer wird, um so weiter sich zwei Entwicklungslinien voneinander entfernen. Insbesondere Langläufer die sich unnötig früh von der PROD abspalten sollten schon in der Projekt-/Release-Planung vermieden werden. Dennoch muss man aber immer flexibel reagieren können: Ein Plan ist ein Plan und man weiß nie, wann im Projektverlauf einem die Risiken schlussendlich um die Ohren fliegen.
Branch mit git anlegen¶
Für das Anlegen eines Branch-Points braucht man kein CDB-Tool und keinen CDB-Dienst. Ein Branch-Point lässt sich sehr einfach auf einem Klone des git Repository anlegen, den man sich beispielsweise auf seinem Desktop PC erzeugt hat. Dennoch sollte sichergestellt sein, dass sich auch letzte Änderungen bereits im SCM-System befinden. Insbesondere die Konfiguration aus der DB sollte dabei nicht vergessen werden, hierzu siehe Dump der Konfiguration ins SCM. Ist das erledigt kann der Branch-Point ohne CDB angelegt werden. Hier im Beispiel soll der Branch-Point vom letzten Commit des PROD (master) ausgehen:
$ git clone http://gitserver/cust_plm # falls nicht eh schon vorhanden
$ git checkout -b master # falls nicht bereits ausgecheckt
$ git pull # falls nicht eh schon aktuell
Mit Letzterem hat man den aktuellen Stand des masters ausgecheckt (was i.d.R. auf dem PROD-Server ohnehin immer der Fall sein sollte). Der Branch-Point kann nun auf dem aktuellen Stand des master angelegt werden, das geschieht immer erst mal lokal und dann schiebt man diesen Branch-Point auf den git-Server:
$ git branch <branch-name> # Branch lokal anlegen aber nicht aus-checken
$ git push -u origin <branch-name> # Branch auf dem zentralem Server bereitstellen
Vergleicht man die bisherige Vorgehensweise mit dem im CDB Handbuch zur Komponentenarchitektur vorgestelltem Verfahren, so wird man merken, dass die Verfahren dort, an diesem Punkt enden und nicht über das (Kunde-) Paket hinaus gehen. In der Praxis wird man aber bei der Weiterentwicklung auf Nutzdaten angewiesen sein, die nicht im Paket enthalten sind und für die man sich nun ein Transport-Mechanismus ausdenken müsste.
Diesen und anderen Problemen (s.o. Scope des Pakets) geht man am einfachsten aus dem Weg, indem man zu jedem Branch-Point einen Export der DB erstellt.
DB Export zu jedem Branch-Point
Das Spiegelsystem für die Entwicklung der geplanten Änderung wird aus dem DB Export aufgebaut (s.a. Initialisieren eines CDB Spiegel-Systems).
Der DB Export wird im jeweiligen Management Tool des DB-Systems erstellt. Für die Ablage eignet sich ein Share auf den die Entwickler zugreifen können um sich Spiegel-Systeme aufbauen zu können. Evtl. reicht aber auch schon die tagesaktuelle Sicherung des DB-Managment für einen Import im Spiegel-System aus. Egal wie man es macht, man sollte sich den Export zum Branch-Point solange aufheben, bis die Änderung im PROD gemerged wurde (die Änderung also in Betrieb genommen wurde). Hilfreich können Namen oder Listen sein, die das Datum des Exports und den Namen des Branch-Points erkennen lassen, wie z.B.:
PROD-EXP-<YYYYMMDD-HH:MM>-<branch-name>.
Dump der Konfiguration ins SCM¶
Bevor man einen Branch-Point anlegt oder einen Merge durchführt, muss der
aktuelle Stand der Konfiguration – der sich u.U. nur in der DB befindet – in
die JSON Dateien exportiert und in das SCM-System commited werden. Hierfür
empfiehlt es sich prophylaktisch einen build
zu erzeugen. Im dem folgendem
Beispiel soll ein Dump der Konfigurationen des PROD Systems (master)
erfolgen, also wird der build
auch dort im PROD-System ausgeführt. Der Dump
von QS oder einem Feature-Branch wäre analog, nur eben im jeweiligen System:
# !!! Auf dem jeweiligen System, hier z.B. dem master (PROD) !!!
# !!! sollte der richtige Branch eigentlich schon ausgechekt sein !!!
$ git checkout master
Wichtig ist, dass die cdbpkg Tools auf einen BLOB-Store und die DB zugreifen können, hier im Beispiel ist das der Applikation Server der PROD.
$ cdbpkg build cust.plm # DB export
Sollte ein git status
eine Differenz anzeigen, so muss der aktuelle Stand
noch in das SCM-System commited werden:
$ git add --all . # SCM-Commit ..
$ git commit -m "retain last changes from PROD"
$ cdbpkg commit cust.plm # CDB-Commit
$ git push # auf SCM-Server ablegen
Die hier in den Beispielen verwendeten Commit-Messages sind exemplarisch und für die Praxis ungeeignet, hierzu siehe Abschnitt Commit-Messages.
Commit-Messages¶
In der Praxis wird den Commit-Messages in viel zu vielen Projekten und leider auch von vielen Zulieferern noch zu wenig Beachtung geschenkt, dabei sind die Commit-Messages insbesondere bei langlebigen Projekten und wechselnden Projektteams von besonderem Wert.
Saubere Commit-Messages sind erste Voraussetzung für eine Recherche. Eine Commit-Message gibt Auskunft darüber, was eine Änderung bezwecken soll und was die Motivation zu dieser Änderung war. Die Historie eines Änderungsverlaufs wird durch die Summe der Commit-Messages beschrieben. In dieser Historie will man sich als Entwickler bewegen und einen Änderungsverlauf verstehen, ohne dass man dazu die einzelnen Teil-Änderungen im Detail anschaut. Es muss im Verlauf der Historie zumindest grob erkennbar werden, was, wann, wo und warum geändert wurde.
Wie wichtig gut gewählte Commit Messages sind wird z.B. deutlich wenn es um die Auflösung von Konflikten geht. Dabei (beim Merge) muss man wissen, warum diese Änderung hier im Branch anders ausgefallen ist als die gleiche Änderung im anderen Branch. Ohne die inhaltlichen, fachlichen und ggf. auch technischen Hintergründe einer Änderung muss derjenige, der den Merge durchführt selber erahnen was die Gründe dafür waren und wie man den Konflikt am besten auflöst .. etwas zu erahnen ist keine solide Basis für eine Entscheidung.
Die Commit-Message sollte einheitlich und ausdrucksstark sein.
In der Praxis hat sich ein einfaches Schema bewährt:
<tag>: <Zusammenfassung>
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
voluptua.
Es hat sich bewährt die ersten Zeile am Anfang mit einem <tag>
mit
anschließendem Doppelpunkt zu beginnen. Das <tag>
sollte einen Hinweis auf
den Kontext geben, zu dem diese Änderung gehört. Der Kontext kann sein:
Eine Fehler- oder Vorfallnummer wie z.B.:
I004711:
für issue 4711Die Kurzbezeichnung des Projekts, z.B.
FooFoo:
für alle Commits (Beiträge), die das FooFoo-Feature implementieren und/oder korrigieren.Eine Sparte oder eine Modulzuordnung, wie z.B.
doc:
für Korrekturen an der DokumentationManchmal kann der Kontext aber auch ganz allgemeiner Natur sein wie z.B.
HotFix:
Die erste Zeile sollte ein kompakter one-liner mit Kontext und Zusammenfassung sein, der aber auch nicht mehr als 80 oder 120 Zeichen haben sollte. Darauf folgt eine Leerzeile und danach kann ein ausführlicherer Text kommen der die Hintergründe dieser Änderung beschreibt. Dabei beschreibt man nicht den Source-Code, sondern das, was die Änderung bezwecken soll. Für das Beispiel von oben, bei dem ein HotFix angebracht wurde, könnte man beispielsweise schreiben:
HotFix: Maskenfeld XYZ auf 'free' gesetzt
Das Maskenfeld XYZ war mit einem defekten Auswahlbrowser XYZ konfiguriert,
welcher falsche Werte lieferte. Damit die Anwender erst mal weiter arbeiten
können wird dieser HotFix angebracht, mit dem die Editierbarkeit des
Maskenfelds von 'catalog' (nur aus dem Katalog zu befüllen) in 'free' (frei
editierbar) geändert wird.
Eine Überarbeitung des Auswahlbrowser XYZ findet derzeit schon im QS statt und
soll später diesen HotFix ersetzen.
Wenn man später (so wie oben gezeigt) dann die Überarbeitung aus dem QS in die PROD merged, dann weiß man aufgrund der ausführlichen Commit-Message genau, wie man mit dem Konflikt rund um das Maskenfeld XYZ umzugehen hat.
Ohne eine derartige Commit-Message und ohne die Hinweise auf HotFix & Überarbeitung im QS wüsste man beim Merge nicht mehr warum die Änderung damals angebracht hatte. Hier noch das negativ-Beispiel dazu:
BugFix: Maskenfeld XYZ auf 'free' gesetzt
Das Maskenfeld XYZ sollte auf 'free' gesetzt werden; ist hiermit
erledigt.
Letztere Commit-Message hat für andere Personen als den Ersteller kaum einen Informationsgehalt. Es fehlt der Hinweis darauf, dass es sich eigentlich nur um einen HotFix handelt, das eigentlich der Auswahlbrowser kaputt ist und das dieser noch überarbeitet wird und das diese Überarbeitung diesen HotFix dann ersetzen wird. Wie soll ein Maintainer der den Merge dazu durchführen will mit dem Kontext aber evtl. nicht vertraut ist, wie soll der wissen welche Entscheidungen er bei der Konfliktauflösung treffen soll. Ohne stundenlange Recherchen und Nachfragen ist es bei derart schlechten Commit-Messages oftmals kaum möglich vernünftige Entscheidungen treffen.
Schlechte Commit-Messages kosten Geld
Hört endlich auf damit und schreibt Eure Commit Message aus der Perspektive des Maintainers, der Euer Projekt nicht im Detail kennen kann!!!!
Common Pitfalls¶
Ein paar Hinweise zu gern gemachten Fehlern:
- Branch im laufendem Prozess wechseln
Man darf auf einem System, auf dem CDB Prozesse laufen nicht einfach den Workingtree ändern, indem man z.B. ein checkout eines anderen Branches macht. Zum Einen mögen es die gerade aktiven Prozesse nicht, wenn man ihnen den Workingtree unter dem Arsch wegreißt und zum Anderen hat jeder Branch seine eigene DB .. im schlimmsten Fall wird dann noch gegen die falsche DB Verbunden und diese dann sabotiert!