Superstarke Continuous Delivery mit Git

Jetzt, da Git das mühevolle Mergen erleichtert, werden Branching-Workflows sehr viel attraktiver.

Sarah Goff-Dupont Sarah Goff-Dupont

Wir alle kennen den Ausspruch: "Vorsicht bei Code, den nur eine Person geschrieben hat." Genauso kennen wir die Vorteile von Teamwork bei der Softwareentwicklung: verschiedene Denkweisen, unterschiedliche Hintergründe und Erfahrungen ... und wenn du diese Unterschiede bei der Lösung von Problemen mit einbringst, hast du am Ende eine bessere Software. Sie ist einfacher zu verwalten, qualitativ hochwertiger und für die Benutzer letztendlich nützlicher.

Zusammenarbeit im Team | Atlassian CI/CD

Aber genauso wissen wir: Die Entwicklung im Team kann chaotisch sein.

Du versuchst zu verstehen, wer an welchem Codeabschnitt arbeitet, möchtest sicherstellen, dass Änderungen keinen Konflikt auslösen, bist bemüht, Fehler zu finden, bevor es die Kunden tun, und hast es dir zur Aufgabe gemacht, alle Projektbeteiligten stets auf dem Laufenden zu halten. Wie sich herausstellt, kann das Git-Branching oder die Continuous Delivery jedes dieser Probleme lösen.

Ich möchte dich gerne davon überzeugen, dass die Kombination aus beiden (vielleicht gemixt mit ein paar anderen Kick-Ass-Tools, nur zum Spaß) dein Zaubertrank-Rezept zum Erfolg ist.

Die Leistungsfähigkeit von Branch-basierten Workflows

Ehrlich gesagt ist Git an und für sich gar nicht so perfekt für die Continuous Delivery (CD). Aber Branching-Workflows sind ideal für CD und Git ist ideal für Branching-Workflows. Ein Branch-and-Merge-Workflow ist nicht nur der ideale Partner der CD – du kannst mit ihm auch lästige Fehler beheben, neue Technologien ausprobieren oder einfach eine neue Funktion von Grund auf neu programmieren, ganz ohne Risiko, dass deine Änderungen deinen Teamkollegen bei ihren eigenen Tasks in die Quere kommen.

Grundlegendes Workflow-Diagramm | Atlassian CI/CD

Klar, Branches kannst du auch mit Subversion und anderen herkömmlichen Versionskontrollsystemen erstellen. Aber machen wir doch einen kurzen Exkurs und lernen wir den bösen Zwilling von Branching kennen: den Merge.

Herkömmliche Versionskontrollsysteme wie Subversion sind einfach nicht so gut beim Nachverfolgen von Dateiversionen in verschiedenen Branches. Und wenn es Zeit für den Merge ist, muss Subversion sehr oft anhalten und nach dem Weg fragen. (Du weißt schon, dieses kleine Pop-up mit der Frage "Möchtest du diese oder jene Zeile in der Merge-Version?") Da beim Durchführen von Merges so viel menschliche Interaktion nötig ist, setzen Teams gerne Code-Freezes ein, damit die Person, die den Merge gerade durchführt, nicht von den Änderungen in einem der Branches unterbrochen wird. Code-Freezes kosten Zeit – und Zeit ist Geld.

Git dagegen ist wirklich gut darin, Änderungen an verschiedenen Dateiversionen in verschiedenen Branches nachzuverfolgen, und weiß immer, wie der gemeinsame Vorgänger dieser Datei aussah. Es hat quasi ein eingebautes GPS, mit dem es Merges durchführen kann, ohne ständig anzuhalten und dich nach dem Weg zu fragen.

Mit Git hast du die Freiheit, die Leistungsfähigkeit von Branching auf eine Art und Weise zu nutzen, die mit Subversion nicht umsetzbar wäre. Der geringe Aufwand für das Branching und Mergen macht Branches, die nur einen oder zwei Tage benötigt werden, nicht nur realisierbar, sondern auch vorteilhaft.

Okay, gut. Aber warum genau ist Branching überhaupt so gut für Continuous Delivery geeignet?

Branches keep main clean and releasable

We've established that short-lived branches provide a great way for developers to collaborate on a project or feature without stepping on each other’s toes. But more importantly for CD, isolating all the work in progress on development branches keeps main and any stable version branches in a clean state so you can ship at will.

Das bedeutet, du solltest alle deine automatisierten Tests über Entwicklungs-Branches ausführen. Entwickler erhalten eindeutige Signale bezüglich der Qualität ihres Codes und können dann zuversichtlich entscheiden, wann der Merge für ihre Änderungen durchgeführt wird. (Wenn du bei den automatisierten Tests noch nicht ganz durchsteigst, dann schau dir diesen Beitrag von RebelLabs an. Dort findest du eine lockere Einführung und Rezepte dafür, wie du deine ersten Unit-Tests schreibst.)

Es bedeutet auch, Pull-Requests von Git als eine Art Code-Review zu nutzen, damit sich dein gesamtes Team auf die Wartungsfreundlichkeit des Codes und die Interoperabilität mit anderen Bereichen der Codebasis verlassen kann. Ja, das ist mehr Arbeit im Vorfeld als bei herkömmlichen Bereitstellungsmodellen. Und ja, es lohnt sich.

Erfolgreiche Continuous Delivery ist davon abhängig, dass du deine Release-Branches blitzsauber hältst.

By way of example, all the development teams at Atlassian have an agreement that nothing is ever committed directly to main or the stable branches. Everyone does their work on branches. In fact, we're so bullish on branching that we've taken to creating a separate branch for each Jira issue we tackle – more on that in a bit.

Anyway, this means that people can break as many tests and do as much damage on their branches as they want! Main remains in a state where we can release from it, and where you can make new branches off it without inheriting a bunch of broken code. That's a win for CD and general developer productivity (not to mention morale).

Branches helfen dir dabei, Beiträge von außerhalb des Teams anzunehmen

Da in Git Branching möglich ist – und insbesondere auch das Abspalten ganzer Repositorys – wird es einfach, Beiträge von Personen außerhalb des unmittelbaren Teams anzunehmen: von Auftragnehmern, Entwicklern aus Partnerunternehmen, Entwicklern aus anderen Geschäftsbereichen usw. Du musst dir nicht mehr den Kopf darüber zerbrechen, dass andere, die mit deiner Codebasis nicht vertraut sind, einfach so Änderungen an wichtigen Branches vornehmen und dadurch verhindern, dass du neuen Code ausliefern kannst.

Here again, rigorous automated testing on their branches or forked repos is the key to collaboration happiness. You'll want to review their build and test results before approving any merges into your main code line.

Profitipp: Repository-Manager wie Bitbucket ermöglichen es dir, Git-Hooks zu nutzen, um Qualitätsstandards durchzusetzen. Du kannst zum Beispiel eine Regel festlegen, dass alle Branch-Builds bestehen müssen, bevor ein Pull-Request angenommen und zusammengeführt werden kann.

Korrektes Branching = Übersichtliche Projektverfolgung

Der aktuelle Trend: Erstelle einen Entwicklungs-Branch für jede Story, jeden Bugfix oder jede Task (d. h. jeden Jira-Vorgang), die du ausführst. Bei Atlassian haben wir dieses Branch-pro-Vorgang-Modell vor einigen Jahren eingeführt und wir haben es nicht bereut! Es erfreut sich auch bei unseren Kunden großer Beliebtheit.

Creating a branch for each issue makes it easy to hand-pick which changes to ship out to production or bundle into a release. Since you're not dog-piling changes onto main, you get to select what comes into main – and when. You can ship an epic's MVP plus one nice-to-have, rather than wait until all the nice-to-haves are fully baked. Or ship a single bug fix, and do it within the framework of a regular ol' release. Even if the fix is urgent, you won't have to deal with the 3-ring circus of backing out other changes that aren't ready to ship yet just to get that one change out the door.

Und diese bequeme Auslieferung einer einzigen Codeänderung ist die Quintessenz der Continuous Delivery.

Not only does this approach keep un-proven code off main, when you include the relevant Jira issue key and developer's name or initials in the branch's name, it's crystal clear what the state of development is for each issue in flight.

Bitbucket Commits Git Repository Screenshot | Atlassian CI/CD

Notice the naming convention used in the picture above: it's the unique key for the JIRA issue being implemented, plus a short, human-readable description of what that issue is all about. So as a release manager or other stakeholder, you could look at the repo shown above and know at a glance that the user story tracked by AMKT-13952 is ready for release because you can see that it's been merged to main. That's traceability without all the manual effort – boom.

Also wie funktioniert der Workflow mit Git + Continuous Delivery?

Gut, dass du fragst! Ich werde hier nur kurz darauf eingehen, denn in anderen Artikeln auf dieser Seite werden die einzelnen Phasen ausführlicher beschrieben.

  • Erstelle einen Branch für jeden Vorgang, an dem du arbeiten möchtest. Füge den Jira-Vorgangsschlüssel in den Namen des Branches ein, damit klar ist, wofür der Branch gedacht ist. Und wenn du andere Atlassian-Tools wie Bitbucket oder Bamboo verwendest, werden sie diesen Vorgangsschlüssel aufgreifen und Verknüpfungen zwischen dem Vorgang, deinem Branch, all deinen Commits, deinen Builds, deinen Pull-Requests und deinen Bereitstellungen erstellen, die mit diesem Vorgang zusammenhängen. Anders ausgedrückt: Vorgangschlüssel sind fantastisch.
  • Nimm Änderungen an den Branches vor. Du bist hier in deiner eigenen kleinen Welt, also tobe dich aus. Probiere Neues aus. Mach Dinge kaputt. Es spielt keine Rolle, denn du wirst auch ...
  • Deinen Branch unter CI stellen. (Bamboo macht das übrigens automatisch für dich). Du und dein Team entscheiden, ob hier spezielle Tests wie Belastungstests oder UI-basierte End-to-End-Tests durchgeführt werden, und ob jedes Mal, wenn Änderungen in deinen Branch gepusht werden, automatisch ein Testlauf durchgeführt wird. Die Teams bei Atlassian führen im Allgemeinen Tests auf Unit- und Integrationsebene für Entwicklungs-Branches durch. Sie lassen die Entwickler entscheiden, wie oft diese ausgeführt werden sollen, um Build-Ressourcen zu sparen und sicherzustellen, dass die Warteschlange nicht unnötig verstopft ist.
  • Update your branch with the latest from main frequently. You can use rebase or branch-commit to accomplish this. Totally up to you. (But remember not to rebase a branch that you share with other devs – this will make them grumpy.) Either way, you'll discover integration conflicts before you merge up, which in turn helps keep main clean.
  • Erstelle einen Pull-Request, wenn du bereit für den Merge bist. Das bedeutet, die Implementierung ist abgeschlossen, du hast Änderungen von deinen Teamkollegen miteinbezogen sowie alle entstandenen Konflikte gelöst und dein Branch besteht alle Tests.
  • Merge up, and deploy at will. Some teams prefer to automatically ship each change as soon as it's merged to main and all the tests pass there – the continuous deployment model. Other teams prefer to make a human decision about which changes to ship, and when. It's up to you and your team.

Git CI-Automatisierung | Atlassian CI/CD

Also: Branching-Workflows machen Continuous Delivery einfacher und Git macht Branching unkomplizierter. Lies weiter, um mehr darüber zu erfahren, wie du dein Git-Repository CD-freundlich einrichtest und all diese Ideen mithilfe der Tools von Atlassian in die Praxis umsetzen kannst. Wir sehen uns auf der nächsten Seite!