Blog

Versionskontrollstrategien und kontinuierliche Bereitstellung

Freek Wielstra

Aktualisiert Oktober 21, 2025
12 Minuten

Continuous Delivery ist eine Praxis der Softwareentwicklung, bei der ein Team oder ein Unternehmen bestrebt ist, seine Software stets in einem lieferbaren Zustand zu halten. Eng damit verbunden ist die kontinuierliche Bereitstellung, bei der die Software selbst so oft wie möglich für die Produktion freigegeben wird. Continuous Delivery ist eine Voraussetzung für Continuous Deployment. Aus geschäftlicher Sicht ermöglicht die kontinuierliche Bereitstellung einem Unternehmen, sich schnell an veränderte Marktentwicklungen anzupassen, auf Benutzerfeedback zu reagieren usw. Was jedoch meiner Meinung nach ein viel stärkeres Argument für CD ist, ist die Tatsache, dass es eine große Anzahl von Softwareentwicklungspraktiken durchsetzt. Es ist ein Kernprinzip, auf das man sich beziehen kann, wenn man Entscheidungen über die Praxis der Softwareentwicklung trifft, angefangen bei der Handhabung der Versionskontrolle, der Test- und Release-Automatisierung usw. In diesem Beitrag werde ich auf die Softwareentwicklungspraxis der Versionskontrolle eingehen und eine Reihe von Strategien im Zusammenhang mit Continuous Delivery diskutieren.

Versionskontrolle, automatische Überprüfungen und kontinuierliche Integration

Eines der Grundprinzipien von CD ist es, den Build grün zu halten. Alle Entwickler eines Projekts arbeiten an einer gemeinsamen Codebasis und müssen sich darauf verlassen können, dass diese immer in einem funktionierenden, einsatzfähigen Zustand ist. Ich werde hauptsächlich Begriffe aus Git verwenden, aber das gilt für alle Versionskontrollsysteme.

Trunk-basierte Entwicklung

Der einfachste Weg, mit mehreren Entwicklern an einer einzigen Codebasis zusammenzuarbeiten, ist wahrscheinlich die trunk-basierte Entwicklung, bei der alle Entwickler an einem einzigen Zweig arbeiten, in der Regel dem Zweig master. Diese Methode der Zusammenarbeit impliziert in hohem Maße die kontinuierliche Integration, bei der Änderungen, wie der Name schon sagt, mehrmals am Tag kontinuierlich integriert werden. So bleiben alle auf dem neuesten Stand der Entwicklung, so dass neue und aktualisierte Funktionen schnell im gesamten Team bekannt sind. Damit soll verhindert werden, dass Mitarbeiter auf Inseln arbeiten, die länger als einen Tag vom Rest des Teams isoliert sind.Das Risiko bei der trunk-basierten Entwicklung besteht jedoch darin, dass jeder Vorstoß eines Entwicklers das Risiko mit sich bringt, dass er den Build beschädigt. Ein Bruch des Builds führt dazu, dass sich master in einem nicht freigegebenen Zustand befindet. Das unterbricht den Fluss der kontinuierlichen Bereitstellung und behindert alle, die an der Codebasis arbeiten, bis das Problem behoben ist. Es gibt eine Reihe von Möglichkeiten, dieses Risiko zu minimieren. Ein wichtiger Faktor für die erfolgreiche Anwendung von CD ist die Testautomatisierung. Eine Möglichkeit, um zu verhindern, dass der Build unterbrochen wird, besteht darin, sicherzustellen, dass die automatisierten Tests alle grün sind, bevor sie wieder in den Master integriert werden. Dies kann z.B. durch die Einrichtung eines Pre-Push- oder Pre-Commit-Hooks erzwungen werden. Ein wichtiger Hinweis in diesem Zusammenhang ist, dass bei der Rückintegration in die Hauptcodebasis alle vorgenommenen Änderungen lokal integriert werden sollten, bevor die Tests ausgeführt werden.Eine Herausforderung besteht darin, dass die Ausführung aller Tests nicht für alle Kategorien von Projekten geeignet ist. Wenn die Ausführung aller Tests länger als eine Minute dauert, was bei der Ausführung von Integrationstests oder End-to-End-Tests für kundenorientierte Anwendungen (z.B. mit Selenium) häufig der Fall ist, wird es immer wahrscheinlicher, dass auf Änderungen vorgenommen wurden, die nicht in die lokale Arbeit integriert wurden, bevor der Test beendet wurde. Dieses Problem wird auch umso größer, je mehr Entwickler an der Codebasis arbeiten. Man kann sich dafür entscheiden, nicht alle Tests auszuführen und zu akzeptieren, dass der Build / die Veröffentlichung bei Tests, die länger dauern, fehlerhaft sein kann, aber das verringert die Zuverlässigkeit und wird schließlich die kontinuierliche Bereitstellung behindern - ganz zu schweigen davon, dass sich die Entwickler weniger verantwortlich fühlen, wenn der Build fehlerhaft ist. Ein anderer alternativer Ansatz ist, wie Facebook zu sagen pflegte und immer noch praktiziert, "schnell zu arbeiten und Dinge zu brechen". Das bedeutet, dass man sich weniger auf automatisierte Tests verlässt, sondern einfach in die Produktion geht. Facebook stellt neue Versionen automatisch einer kleinen Gruppe von Nutzern zur Verfügung und überwacht dann die eingehenden Fehlermeldungen. Wenn Fehler auftauchen, wird die Version nicht für weitere Benutzer zur Verfügung gestellt, sondern die Entwickler müssen sie beheben und eine neue Version erstellen. Wenn keine neuen Fehler auftreten, wird die Anzahl der Benutzer, die die neue oder geänderte Funktion sehen können, allmählich erhöht, bis sie für 100 % der Benutzer bereitgestellt wird. Dies funktioniert hervorragend für nicht so kritische Anwendungen, was meiner Meinung nach die meisten kundenorientierten Anwendungen sind. Kritische Fehler, die den Benutzern alles kaputt machen, sollten natürlich vermieden werden, aber in der Praxis sind die meisten Fehler subtil oder einfach nur "nicht ideal", anstatt wirklich kritisch. Ob dieser Ansatz für Ihre Anwendung funktioniert, hängt natürlich von einer Vielzahl von Faktoren ab. Meiner Meinung nach ist es wichtig zu überlegen: "Wie schlimm ist es, dass etwas nicht funktioniert?" Ich bin der Meinung, dass die meisten Fehler in veröffentlichter Software am Ende nur geringfügige Unannehmlichkeiten mit sich bringen. Und wenn die Software nur für eine kleine Gruppe von Anwendern bereitgestellt wird, sind es auch nur für eine kleine Anzahl von Anwendern geringfügige Unannehmlichkeiten. Wenn es ein großes Problem gibt, sind die Auswirkungen selbst dann gering - und wenn Sie die CD richtig eingerichtet haben und schnelle Releases durchführen können, kann ein Fix schnell ausgerollt werden. In meiner persönlichen Erfahrung habe ich nur bei zwei Projekten mit diesem Ansatz gearbeitet. Das eine war eines meiner ersten Projekte bei Xebia bei UPC, in einem kleinen Team (4-5 Entwickler), wobei das Projekt nur sechs Wochen dauerte. Für viele in diesem Team war es das erste Mal, dass sie mit Git arbeiteten, so dass es ein wenig Eingewöhnungszeit gab. Es schien für diese Anwendung gut genug zu funktionieren, da wir eine gute Kommunikation hatten und die meisten Dinge zu zweit machten, aber das Projekt war zu kurz, um CD in die Praxis umzusetzen.Das andere Projekt war bei NS, wo normalerweise nur zwei Leute an einem Projekt arbeiteten. Anfangs arbeiteten wir auf der Basis des Stammes, wobei die meisten Funktionen in nur wenigen Tagen fertiggestellt wurden, aber wir entschieden uns regelmäßig für einen Feature-Branch-Ansatz, vor allem, um mich oder den anderen Entwickler (und umgekehrt) bei der Entwicklung nicht zu stören. Das Feature-Branching ermöglicht es den Entwicklern, ihren Code zu testen und bereitzustellen, bevor er mit der Mainline zusammengeführt wird. Dadurch kann vermieden werden, dass der Build unterbrochen wird und sowohl andere Entwickler als auch der Continuous Deployment Flow gestört werden.

Feature Verzweigung

Kurz gesagt: Beim Feature-Branching erstellt ein Entwickler eine Verzweigung vom Mainline-Quellcode, erledigt seine Arbeit und führt sie wieder mit dem Mainline-Quellcode zusammen. Bevor diese Zusammenführung erfolgt, wird eine Reihe von Überprüfungen durchgeführt. Es werden alle automatisierten Tests ausgeführt, ein Code-Review wird von Kollegen durchgeführt (entweder im selben Team, in einem anderen Team, von einem erfahrenen Entwickler usw.), ein Product Owner inspiziert die neue Funktion und gibt Feedback usw. Um sicherzustellen, dass der master Build nach dem Zusammenführen grün bleibt, ist es am besten, nur das Zusammenführen von Zweigen zuzulassen, die mit dem Master auf dem neuesten Stand sind, d.h. nach dem Zusammenführen ist alles, was gegenüber der Mainline geändert wurde, die eine neue Funktion. Die meisten Versionskontrollprogramme (github, gitlab, bitbucket usw.) verfügen über Verwaltungsoptionen, um dies zu erzwingen; suchen Sie nach einer Option, die nur das Vorspulen erlaubt. Dies gewährleistet eine lineare Historie und stellt sicher, dass nach jedem Merge eine Veröffentlichung mit einer relativ kleinen Änderung im Vergleich zur vorherigen Version möglich ist.Feature-Branching ermöglicht es Teams und Entwicklern, isoliert zu arbeiten und nicht unterbrochen zu werden, wenn der Build rot ist - falls das aus welchen Gründen auch immer noch passiert. Außerdem ermöglicht es einen formelleren Ansatz für die Überprüfung von Software sowie die Optimierung der Commit-Inhalte und -Nachrichten vor dem Zusammenführen. Meiner Meinung nach ist dies eine skalierbarere Lösung für die Softwareentwicklung als die trunk-basierte Entwicklung. Auch sie kann mit dem Facebook-Ansatz kombiniert werden, bei dem die Software nur für eine begrenzte Anzahl von Benutzern bereitgestellt wird. Das Schreiben und Pflegen einer vollständigen Suite von End-to-End-Tests ist sehr zeit- und arbeitsaufwändig und zahlt sich möglicherweise nicht so sehr aus. Der Ansatz des 'partiellen Deployments' erlaubt es den Entwicklern, weniger Zeit auf umfassende Tests zu verwenden, was wiederum mehr Zeit für das Hinzufügen oder Ändern von Funktionen sowie häufigere Deployments ermöglicht. Nach meinen persönlichen Erfahrungen sind End-to-End-Webanwendungstests (zunächst mit FitNesse, später mit Protractor, beide mit Selenium / WebDriver unter der Haube) tendenziell instabil, langsam, nicht umfassend, schwer zu debuggen und eine Herausforderung, sie auf dem neuesten Stand zu halten. Wenn die Testtools nicht stabil sind, tragen sie nicht zur CD bei. Wenn sie nicht umfassend sind, hinterlassen sie Lücken und bergen die Gefahr, dass Endbenutzer etwas kaputt machen. Eine Erweiterung des Feature-Branching-Modells ist das Git-Flow-Modell, das eine zusätzliche Ebene zwischen dem Integrationszweig (master in den vorherigen Beispielen, in Git-Flow develop genannt) und dem "ready for deployment"-Zweig einfügt. Dadurch wird eine indirekte Ebene hinzugefügt, sozusagen ein Puffer, in dem mehr Spielraum für Fehler besteht und der Build abgebrochen werden kann. Ich glaube nicht, dass dies eine gute Strategie ist. Da ein Abbruch des Builds nicht so sehr schmerzt, gibt es weniger Anreize, die Ursachen zu beheben. Die Überführung in die Produktion ist mit mehr Ritualen und Prozessen verbunden, es sind mehrere Schritte erforderlich. Diese Rituale könnten bis zu einem gewissen Grad automatisiert werden, aber es ist besser, die Rituale gar nicht erst zu haben, als zu versuchen, sie zu verstecken - je mehr Rituale, ob automatisiert oder nicht, desto mehr Overhead gibt es, der die CD behindert. Der Ansatz des "einfachen" Feature-Branching ist derjenige, den ich in meinen Projekten am häufigsten verwendet habe. Ich habe festgestellt, dass sowohl ich als auch andere Entwickler sich zu diesem Ansatz hingezogen fühlen; Es erspart eine Menge Kopfzerbrechen, wenn es darum geht, den Master auf dem neuesten Stand zu halten, es verschiebt die Lösung von Konflikten (wenn nötig) auf den Zeitpunkt der Integration statt auf die ganze Zeit, es ermöglicht automatisierte Tests auf einem CI-Server und vermeidet das Zusammenführen, wenn es eine Regression oder ein Problem gibt, und was wahrscheinlich die Codequalität am meisten verbessert hat, war, dass mit Hilfe von Tools wie Github, Gitlab und Stash formellere Code-Reviews möglich waren. Bevor wir auf diese Systeme umgestiegen sind, sind wir herumgelaufen und haben jeden gesucht, der bereit war, unseren Code zu überprüfen. Das bedeutete, dass wir jemanden aus seiner Konzentration reißen mussten, was wir als ziemlich lästig empfanden. Das andere Problem bei unseren Code-Reviews war, dass der Reviewer sich nicht die Zeit nahm, den Code durchzugehen, sondern dass der Entwickler den Code nur zeigte, durchblätterte und erklärte. Mit den formelleren Werkzeugen wurde daraus ein asynchroner Prozess, bei dem der Prüfer den Code in seiner eigenen Zeit und zu seinem eigenen Zeitpunkt prüfen konnte. Das Wichtigste dabei ist, dass Sie sich darauf einigen müssen, die Überprüfungen nicht zu lange offen zu lassen, da der ursprüngliche Entwickler sonst bereits zum nächsten Punkt übergegangen ist. Das passiert in der Regel sowieso, sollte aber auf ein Minimum beschränkt werden, um ein übermäßiges Umschalten des Kontexts sowohl für den Entwickler als auch für den Prüfer zu vermeiden.


Die meisten Versionskontrollsysteme sind eine Variation der oben genannten zwei oder drei Ansätze. Der von Code-Hosting-Plattformen wie GitHub populär gemachte Fork & Pull Request Flow ist eine Variante des Feature-Branch-Ansatzes, mit der Besonderheit, dass der Fork nicht in die Upstream-Codebasis integriert werden muss - er kann als eigenes Produkt weiterleben, wenn die ursprünglichen Autoren des Fork-Projekts mit den vorgenommenen Änderungen nicht einverstanden sind. Das Linux-Projekt, das Projekt, für das Git ursprünglich entwickelt wurde und das eine der größten Codebasen ist, die Versionskontrolle verwenden, verwendet einen stark verteilten Ansatz für die Versionskontrolle. Anstelle von Zweigen, Pull-Requests usw. gibt es eine Hierarchie von Maintainern, wobei Linus Torvalds der Hauptintegrator ist, der am Ende alle Änderungen, die per E-Mail von den Top-Maintainern geschickt werden, in seine Mainline-Version des Linux-Kernels zusammenführt. Seiten wie Submitting Patches und First Kernel Patch versuchen, den Prozess bis zu einem gewissen Grad zu erklären. Für welchen Ansatz Sie sich als Team auch immer entscheiden, achten Sie darauf, dass Sie bei einem Ansatz bleiben und konsistent sind, damit jeder weiß, was vor sich geht. Zweitens sollten Sie als Team lernen, Git zu verstehen; lernen Sie den Status Ihres lokalen Repositorys anhand der Befehlszeilenausgabe kennen, seien Sie sich des Unterschieds zwischen lokalen und entfernten Zweigen bewusst, wissen Sie, was Sie lokal haben und was mit anderen geteilt wird. Halten Sie Ihre Historie sauber und verwenden Sie unentgeltlich Tools wie amend und interactive rebase, um die Historie, die Sie erstellen, zu bereinigen - aber nur, solange Sie sie noch nicht mit anderen geteilt haben. In der Tat bieten alle großen Git-Hosting-Lösungen die Möglichkeit, einen Zweig zu schützen. Ich empfehle, dies für den Master-Zweig immer zu aktivieren, damit niemand die Geschichte umschreiben kann. Ich schreibe die Historie in Zweigen um, indem ich (interaktives) Rebasing und Force-Pushing einsetze. Das liegt vor allem daran, dass die anfängliche Arbeit an einem Feature vielleicht nur eine Handvoll Commits umfasst, aber die Korrekturen und Überarbeitungen, die nach der Überprüfung des Codes oft anfallen, fügen eine Menge Commits hinzu, in denen "dies behoben" und "das behoben" wird. Das ist natürlich falsch und es werden später noch Änderungen hinzugefügt, aber zumindest wird der anfängliche Entwicklungsaufwand in Ihrem Git-Verlauf sauber dargestellt. Tun Sie dies auch nicht, wenn mehr als eine Person an demselben Zweig arbeitet, denn das verursacht eine Menge Ärger. Ziehen Sie die Paarprogrammierung vor, wenn Sie wirklich müssen, oder vereinbaren Sie, dass Sie die Historie während der Entwicklung durcheinander bringen, aber nur einen Entwickler die Historie bereinigen lassen, sobald die Entwicklung abgeschlossen ist. Denken Sie auch daran, dass es sich hier um fortgeschrittenes Material handelt Denken Sie daran, dass Sie bei jedem branch-basierten Ansatz (z.B. bei allem, was nicht trunk-basiert ist) Änderungen am Code, an den Commits und an allem bis zum endgültigen Merge vornehmen können - wenn Sie sich für einen Ansatz entscheiden, nutzen Sie diese Option, um sicherzustellen, dass Ihre Historie so sauber wie möglich ist und dass Ihr Produkt, wenn Sie den Merge-Button drücken, bereit für die Produktion ist.

Verfasst von

Freek Wielstra

Freek is an allround developer whose major focus has been on Javascript and large front-end applications for the past couple of years, building web and mobile web applications in Backbone and AngularJS.

Contact

Let’s discuss how we can support your journey.