Git und Semver für Anfänger
Development
In dieser Folge sprechen wir über den Einsatz von Git in Zusammenhang mit Semver. Wir beschreiben die gängigen Funktionen und Herangehensweisen beim Umgang mit Git und automatischen Releases.
Automatisches Transkript:
Moin, herzlich willkommen bei Server-Side-Stories. In dieser Folge sprechen wir über Git und semantische Software-Versionierung und wie wir das angehen, automatische Releases erstellen und einiges mehr.
Ich kann mich noch erinnern, Mark, als wir angefangen haben, zusammenzuarbeiten, da war bei konzentrik noch SVN im Einsatz. Ich weiß nicht, kennt das außer uns überhaupt noch jemand? Ich habe das Gefühl, das kennt niemand mehr.
Ein Hoch auf die Schildkröte. Tortoise. Stimmt, stimmt, stimmt. Ja, ich muss aber sagen, ich bin auch, was so das Zeitliche angeht, recht spät, glaube ich, mit Git in Kontakt gekommen. Erst als ich so zusammen mit zwei Kollegen ein Startup gegründet habe und einer der Kollegen sagte dann, wir müssen da unbedingt mal Git benutzen. Vorher kannte ich es gar nicht, obwohl es ja schon durch Linux relativ lange irgendwie am Start war. Ja, und mir war auch erst so gar nicht wirklich klar, warum das alles so aufwendig sein musste.
Bei SVN hatte man da jetzt nicht so viele Möglichkeiten, wie man Dinge tun konnte oder die Dinge waren halt wirklich sehr, sehr aufwendig. Und ich habe mich dann halt gefragt, warum muss ich erst Dateien markieren, eine Message schreiben und dann muss ich den Kram noch pushen. Ja, hat sich dann aber, hat dann aber nicht besonders lange gedauert, bis ich dann doch auch die Vorteile gesehen habe und den Ablauf verändert, legt man ja doch dann auch relativ zügig, finde ich. Ja, das kann ich gar nicht so bestätigen. Tatsächlich hat es bei mir lang gedauert. Ich hatte meinen Flow, das war halt alles klar, wie das mit SVN läuft. Das war aufgesetzt, das war schon in Fleisch und Blut übergegangen.
Da war mir gar nicht bewusst, dass viele andere selbst in der freien Wirtschaft noch gar nicht mal irgendwie Commit-Messages nutzen und irgendwas pushen, sondern die gehen per SFTP auf den Server und legen los. Also da gibt es noch eine Vorstufe. Das hatte ich ja dann schlimmer sehr krass damals bei dem gemeinsamen Auftraggeber, wo wir uns kennengelernt haben. Ich wollte gerade sagen, das darf man gar nicht erzählen, da wurde, da war die Ansage erst mal auf dem Server ändern und später in SVN einchecken, wenn alles läuft. Genau, damit die Historie sauber ist. Ja, das waren schon echt verrückte Zeiten und das lief halt gut mit SVN. Also ich konnte mich tatsächlich nicht beklagen und dann kamen aber immer mehr Leute um mich zu und meinten, ja hier geht's, neu, besser, mach das unbedingt und dann wollte mir das irgendwie als mentales Modell überhaupt nicht im Kopf, dass da irgendwie erst was bei mir lokal passiert, was auf den Server schieben und hin und her und ständig noch mehr Knöpfe drücken, fand ich damals ganz, ganz schrecklich, weil es mich in der Regel aus meinem Flow rausgebracht hat.
Und irgendwie hatte ich ja auch immer meine riesen Monster-Commits über gefühlt dutzende Dateien, worüber wir auch nicht unbedingt noch laut reden wollen, das ist ja jenseits von wirklich professionellem Entwickeln nur, ja, das waren halt die juniorigen Zeiten und keiner der ein... Ein Commit, ein Feature, so ne? Ja, genau, ohne Branch und ja, da kommen wir ja gleich noch zu, was das eigentlich so alles bedeutet und wohin sich das da verändert hat und auch sehr zum Guten, also deutlich zum Guten. Und ja, so war es dann von dir als auch damals von den guten Gunnar, dass die Bitten, doch Git zu nutzen, immer lauter wurden und ich habe mich zum Glück überzeugen lassen. Ja, ja, ich glaube, ich weiß noch bei uns, bei unserem Startup damals, da gab es dann die ersten bösen Konflikte und die ersten bösen Fehler, die wir eingebaut haben und spätestens ab da war ich sehr froh, dass das mit Git dann alles einfach so rückabwickelbar war und man nochmal zurückspringen konnte und so, spätestens da war ich dann Fan.
Ohne Frage, also absoluter Fan. Ja, und im Grunde hat sich ja seitdem von den ganzen Abläufen, wie wir sie gerade so ein bisschen angedeutet haben, auch nicht viel geändert, also man arbeitet ja immer noch so, Git hat sich natürlich weiterentwickelt, es gibt inzwischen weitaus mehr Tools und Clients und Services rund um Git, aber das Prinzip ist ja im Grunde gleich geblieben. Ich markiere eine Datei, die ich geändert oder neu erstellt habe, ich schreibe zu diesen Änderungen eine kurze Zusammenfassung, erstelle daraus ein Commit, also im Grunde gruppiere ich damit so ein bisschen die zusammengehörigen Änderungen, die sind dann aber erst, was meintest du gerade, erst mal nur auf meinem Rechner, obwohl ich da was committet habe, es ist noch nirgendwo draußen in der Welt und erst wenn ich der Meinung bin, okay, jetzt ist die Aufgabe soweit fertig, ist ein guter Zwischenstand vielleicht auch, dann kann ich das rauspushen in die Welt und du könntest dir diesen Commit schnappen, den ich da gerade gepusht habe und damit weiterarbeiten. Und das ist ja tatsächlich auch ein riesen Game Changer gewesen, denn bei SVN habe ich es so gemacht, dass ich dann committet gepusht und es war raus und weil es da draußen alle sehen können, habe ich gewartet, bis ich ein Commit gemacht habe, das weiß ich noch nicht sehr genau, das soll ja irgendwie eine gewisse Seriosität haben und dadurch kamen ja diese Monster Commits zustande, wenn ich jetzt entgegen mit Git arbeite, kann ich viele kleine Änderungen immer wieder, wenn ich einen Zwischenschritt gemacht habe, für mich committen, am Ende kann ich mir das Ganze angucken, zusammenpacken, irgendwie wieder nochmal bearbeiten und, was ich auch in meiner Historie schon einmal hatte, dass einfach alles weg war, aber ich hätte zwischendurch halt kleine Commits gemacht und konnte dann irgendwo in den Untiefen von Git noch an diese Änderungen ran und da steckten halt wirklich Stunden über Stunden an Arbeit drin, mit ein bisschen Google, Stack Overflow, ein, zwei Tiffs in der Kommandozeile, war dann der verschwundene Code wieder hergezaubert und ja, also es ist einfach ein Riesengewinn und Wahnsinn, dass wir anders mal gearbeitet haben, unvorstellbar. Ja, das würde man sich heute eigentlich gar nicht mehr trauen, weil man weiß jetzt einfach, man hat eben diese Absicherung, in Anführungszeichen, dass man nochmal zurückspringen kann und nochmal wieder was herstellen kann und so. Total, ja. Da war man damals etwas mutiger, was das anging, womit wir auch so ein bisschen schon bei der Frage sind, warum man das eigentlich alles macht, also warum ist das, warum macht man sich diesen Aufwand da, so Nachrichten zu schreiben für kleinste Änderungen und warum ist uns das eigentlich so wichtig?
Hast du schon gesagt, das ist einfach für uns eine gewisse Sicherheit, da geht nichts verloren. Wir haben eine Historie, wenn wir ein Projekt starten, das Projekt läuft über fünf Jahre, dann können wir theoretisch zu Tag eins zurückspringen und uns angucken, was wir da gemacht haben und von da an jede Änderung uns anschauen, die so passiert ist, das gibt dann natürlich viel Sicherheit. Ja, was ich auch noch sehr wichtig finde, ist durch die Historie, die ich da dann habe und weiß, was ich am Ende deploye und auf einem Server am Laufen habe, macht es mir das dann auch sehr einfach, zumindest als Startpunkt zu wissen, wo ich für mein Bugfixing und Debugging einsteigen muss, denn ich habe halt eine klare Version, die kann ich bei mir auschecken und dann kann ich halt prüfen und muss da halt nicht raten. Das ist tatsächlich super angenehm und ich kann es halt schnell lokal alles abbilden. Ja, ich denke, es ist auch ganz cool, wenn man neue Projekte startet, dass man einfach mal sich so die letzten paar commits angucken kann, mal gucken kann, wie arbeiten die anderen Leute daran, was ist so passiert, wo kann ich mich irgendwie reinhängen und so. Das ist auch immer ein guter Startingpoint dann. Und was ich für mich als wirkliches Produktivitätsmerkmal entdeckt habe, wir hatten es vorhin kurz angedeutet, diese Atomic commits, die ich machen kann, also kleine, kleine Arbeitsschritte, die können, wenn ich im Frontend arbeite, hey, mein Button ist jetzt zentriert oder mein Overflow- oder Mobilansichtsfix tut das, was ich möchte, ich mache ein kleines commit, arbeite weiter und dann, wie es dann mal so gerne üblich ist, ob im Frontend oder im Backend, ich habe irgendeinen Seiteneffekt, irgendwas will nicht mehr, irgendwas ist kaputt.
Das ist dann immer der Moment, wo ich weiß, okay, gehen wir nochmal schnell irgendwie zurück in die letzte Version, vor 10 Minuten war da das Problem auch schon und so kann ich quasi nachgucken, ob meine letzten Änderungen das Problem hergestellt haben, die ich hier gerade in meiner Entwicklung so in den Rechner gehackt habe oder ist das vielleicht sogar, dass ich durch ein Zufall ein schon sehr lange inhärentes Problem entdeckt habe, an das ich dann separat mir ein Ticket schreibe und später irgendwie mich darum kümmere und solche Möglichkeiten habe ich, weil Steuerung Z kommt irgendwann auch an seine Grenzen. Ja, das stimmt wohl. Ich würde gerne nochmal einen Schritt zurückgehen und für all diejenigen, die jetzt vielleicht nicht so viel mit Git gemacht haben oder gerade davon zum ersten Mal hören, einmal kurz ein bisschen erklären, was das eigentlich alles ist. Wir sprechen jetzt hier immer so von commits und von Historie zurückgehen und so weiter. Also ein bisschen kann man sich ja so mal vorstellen, man startet da so ein neues Projekt, man macht keine Ahnung Webstorm oder faust Code auf oder so und man fängt jetzt an zu programmieren. Früher haben wir da gerade erzählt, dann wäre das wahrscheinlich so gewesen, dass man irgendwann einen Stand hätte, wo man gesagt hat, so jetzt könnte ich mal anfangen, das irgendwo auf dem Server zu spielen und mal auszuprobieren, wie es so funktioniert. So wollen wir heute natürlich nicht mehr arbeiten, besonders wenn wir in kleinen und großen Teams arbeiten, dann sollen ja auch die anderen quasi an dem Code teilhaben und du baust vielleicht ein anderes Feature, als ich gerade baue, weil wir parallel an dem Code arbeiten.
Und deshalb gibt es da so eine gewisse Struktur in Git und ich glaube, die kleinste Einheit, die wir da haben, die ist quasi das commit. Das ist so das, was ich lokal mache. Ich habe irgendeine kleine Änderung in einer Datei gemacht, dann markiere ich diese Datei, also ich die jetzt commiten will, markiere damit quasi, dass ich eine Änderung gemacht habe und fasse kurz in der sogenannten commit-Message zusammen, was ich da eigentlich gerade geändert habe. Gar nicht so einfach. Ja, das ist manchmal auch gar nicht so einfach, genau, weil man tatsächlich ja wirklich kurz sich fassen will, muss, soll und muss sich da schon auf das Wesentliche konzentrieren, was natürlich auch wieder dazu führt, wenn man merkt, dass man sehr lange commit-Messages schreiben will, kann das auch schon wieder ein Warnzeichen sein, dass man einfach auch zu viel Änderungen in einer, in einem commit gemacht hat, dass man da zu lange gewartet hat. Genau, das ist so die kleinste Einheit und irgendwo muss das Ganze, was ich ja jetzt hier commitet habe, hin und das landet auf einem sogenannten Branch. Also das ist ein Zweig des aktuellen Entwicklungsstands.
Bei Git gibt es meistens einen Hauptzweig, das ist der Main-Branch und dann kann man noch beliebige Zweige erstellen, die quasi sich abspalten von dem Hauptbranch. Das heißt, wenn wir jetzt ein Produkt haben, wir haben gerade Socialbly gelauncht und ich möchte jetzt ein neues Feature an Socialbly entwickeln, dann würde ich mir den Hauptbranch nehmen und dann würde ich den abzweigen und würde dieses Feature auf diesem Zweig quasi entwickeln und am Ende würde, würde ich diesen Branch dann wieder und damit wir beim nächsten Punkt zurückmergen in den Hauptbranch. Das heißt, ich habe meine ganzen commits, die habe ich auf meinen sogenannten Feature-Branch gepusht. Da sind die jetzt, da liegen die jetzt drauf, meine ganzen Änderungen und ich möchte jetzt, dass die auf der Webseite verfügbar sind und dazu würde ich sie quasi wieder zurück in den Hauptzweig führen. Aber sag mal Maurice, warum mache ich das trotzdem? Also ich könnte auch einfach auf meinem Haupt, auf meinem Main-Branch weiterentwickeln.
Was bringt mir das? Also der Main-Branch sollte zumindest, wenn man nach gewissen Prinzipien arbeitet, immer ein stabiler Branch sein. Ich könnte ja jetzt auf meinem Feature was bauen, was noch gar nicht fertig ist oder wo ein Bug drin ist oder was und wenn ich den auf Main schiebe und du sagst jetzt, okay ich baue jetzt ein neues Feature, ein zweites Feature, schnappst du den Main-Branch und stellst fest, da funktioniert gar nichts. Dann müsstest du erst mal sehen, dass mein Code, den ich kaputt gemacht habe, erst mal wieder funktioniert, bis du überhaupt arbeiten kannst. Okay, das ermöglicht uns also parallel zu arbeiten und trotzdem immer einen Code-Stand zu haben, der das abbildet, was produktiv ist, falls wir mal ein Hotfix machen müssen oder in irgendeiner Weise halt irgendwie da nächste Schritte auf dem jeweiligen Produktivstand tun wollen. Okay, das habe ich verstanden. Genau. Könnte auch sein, dass du parallel mit mir an dem Feature arbeitest und sagst, ich komme hier überhaupt nicht weiter, kannst du mal irgendwie bei mir mit in den Code gucken.
Dann könnte ich jetzt ohne Probleme einfach sagen, gut ich springe jetzt von meinem Feature-Branch, springe ich auf deinen Zweig und kann mir deinen Quellcode und deinen Stand angucken und wir können da zusammen daran arbeiten. Also auch das ist möglich, dass man zwischen diesen Zweigen sozusagen hin und her springt. Cool, sehr mächtiges Feature. Genau, dann gibt es noch ganz viel drumherum. Ich glaube, da gehen wir jetzt nicht so im Detail rein. Ich kann noch sogenannte Tags anlegen. Es gibt noch diverse Methoden.
Es gibt diese Historie, wo ich halt pro Branch ganz weit zurückgehen kann. Es gibt noch den sogenannten Head und wir können da glaube ich mit tausend Vokabeln um uns werfen, aber ich glaube so das Wichtigste ist halt dieser Ablauf. Ich habe ein Commit, das ist die kleinste Einheit, der landet am Ende irgendwo auf einem Branch und davon kann es mehrere geben und am Ende sollte es, wenn ich mit einem Feature oder fertig bin, alles wieder zurück in meinen Hauptbranch reinwandern. Du hattest noch so eine schöne Analogie, vielleicht kann man das noch mal erklären, was die Historie angeht zu einem Bankkonto. Die Analogie zum Bankkonto dahinter finde ich in der Form sehr passend, da die Historie in dem Moment widerspiegelt, wie sich mein Kontostand ergeben hat. Also in dem Moment, ich schaue halt hinein und sehe, anfangs hatte ich null, dann sind ein bisschen Geld drauf, ein bisschen Geld runter. Das sind dann halt die Dateiveränderungen, die hinzugefügt wurden.
Das sind Änderungen in den Dateien selber. Ich habe halt eine lange lange Historie und mental kann ich mir das Gedankenmodell eines Kontos halt vorstellen. Ich kann zu jedem Zeitpunkt zurückspringen. Ich wüsste genau, wie der Stand der Dinge ist, wie viel hatte ich im Saldo. Die Analogie ist, wie sah in dem Moment mein Code aus. Wir hatten das vorhin angesprochen mit dem Debugging, wenn dann halt die Live-Version auf dem Mainbranch ganz anders ist, als irgendwo auf meinen Feature-Branches oder ich meine Version sogar dann, wie es in Business-Applikationen üblich ist, released habe als Version 2, als Version 1.5. Ich kann zu den jeweiligen Situationen zurückspringen und dann schauen, kann ich in dem Code meinen Bug halt nachvollziehen und dafür hilft mir diese Historie.
Die Analogie zum Bankkonto ist halt, ich weiß, wann ich was auf meinem Konto hatte und wie ich dort hingekommen bin, welche Überweisungen haben stattgefunden. Vielleicht hilft euch das, wenn ihr geht unerfahren seid und generell mit Code-Historien nicht so viel zu tun habt, da eine gewisse Idee zu bekommen, warum das nützlich sein kann. Du hast noch gerade ein ganz gutes Stichwort ein bisschen damit reingeworfen. Das ist so, dass ich da einen Release 2.0 rausbringe. Das wäre ja so der nächste Schritt, sage ich mal. Das ist eigentlich unabhängig davon, ob ich mit Git arbeite oder nicht, aber es greift zumindest bei uns so ein bisschen ineinander und das ist so die sogenannte semantische Versionierung. Ja, sehr wichtig.
semver, weil wir das bestimmt nicht immer so aussprechen werden. Jeder kennt das ja, der schon mal irgendwie ein Programm sich runtergeladen hat oder auf GitHub irgendein Tool sich gezogen hat oder ein npm-Package benutzt oder sowas. So diese klassischen Versionsnummern 1.1.2 oder sowas. Und das ist so ein klassisches semver-Release, was aufgeteilt ist, getrennt durch diese Punkte in der Versionsnummer in drei Einheiten. Das ist das Major, das Minor und das Patch-Release sozusagen. Okay, jetzt habe ich diese drei Zahlen. Was helfen mir die jetzt genau?
Was ist der Unterschied zwischen 1.1.2, 2.3.4? Was bringt mir das? Ja, wir können quasi so ein bisschen mitteilen, wie, wenn man so will, wie drastisch die Änderungen sind, die wir da so hintergemacht haben. Also die letzte Zahl, wenn wir jetzt mal von der Version 1.2.3 ausgehen, wäre die 3.
Das wäre der Patch-Part. Das ist sozusagen die kleinste Einheit, die es da gibt, die kleinste Änderungseinheit. Das heißt, wir haben gerade ein kleines Tool rausgebracht und wir haben festgestellt, da ist ein Bug drin. Wenn ich den Button klicke, dann geht das Popup nicht auf, was da aufgehen soll oder so. Dann würde ich das, dann würde ich diesen Bug fixen und dann würde dieser kleine Fix, der jetzt nicht so weltbewegend ist, aber schon notwendig, der würde jetzt dafür sorgen, dass die letzte Ziffer von 3 auf 4 hochgeht. Das heißt, es gibt nur einen kleinen Patch, einen kleinen Fix, der da eingeflossen ist, jetzt aber keine weltbewegende Änderung, die jetzt die Software in irgendeinem Sinne großartig verändern würde.
Okay, da habe ich dann ja Version 1.2.4. Wenn ich jetzt 1.3.0 hätte, was wäre da so eine Geschichte dahinter? Wenn also die zweite Ziffer hochgeht, das ist unser Miner, dann könnte was passiert sein, nämlich, dass ich da ein tolles neues Feature zum Beispiel eingebaut habe. Ich habe jetzt irgendwie überlegt, dass da nicht nur dieser eine Button ist, den ich klicken kann, sondern es gibt auch noch einen zweiten und dann kommt von oben Konfetti reingeflogen. Total sinnvolles, tolles neues Feature, brauchen wir alle unbedingt. Habe ich jetzt also ein Git eingecheckt und habe jetzt ein neues Release gestartet und ein neues Feature löst eben eine Erhöhung der zweiten Stelle in der Versionsnummer auf. Das ist ein Miner Release, das ist jetzt ein neues Feature, was jetzt dafür sorgt, dass die Software, die wir vorher hatten, genauso weiterläuft, wie sie bisher läuft, aber es ist halt irgendwas Neues dazugekommen.
Ich erahne schon, worauf es hinausläuft. Was ist, wenn ich jetzt 200 habe, was ändert sich da, hast du da auch eine Geschichte parat? Genau, da haben wir das Major Release und da wird es spannend, weil das sind die richtig großen Releases, die kommen recht selten vor, die versucht man, wenn es geht, zu vermeiden, aber manchmal ist es halt so, dass man so große Änderungen in der Software oder an dem Package oder sowas drin hat, dass wir halt die erste Ziffer hochzählen müssen und das heißt, pass auf, hier sind Dinge passiert, die unsere Software durchaus grundlegend ändern können, wo vielleicht irgendwas passiert oder irgendeine Änderung stattgefunden hat, die dafür sorgt, dass irgendwas nicht mehr so funktioniert, wie es vorher funktioniert hat. Das sind, wenn ich ein NPM Package zum Beispiel benutze oder irgendein Composer Package bei PHP, dann kann das sein, dass ich in meinem Code irgendwas ändern muss, weil ich jetzt dieses neue Paket installiert habe und das hat so ein neues Major Release und irgendwas hat sich so grundlegend geändert, dass ich selbst bei mir Anpassungen machen muss, damit das alles noch funktioniert. Okay, jetzt habe ich ja, wie wir vorhin gelernt haben bei Git, ganz, ganz viele kleine Commit Messages und habe davon 30, 40, 50, wie auch immer groß die Features sind, die ich da entwickel oder die Fixes, die ich baue oder gar meine wirklichen Breaking Changes, die ich einbaue. Ich will die doch nicht alle durchgehen und durchlesen und mir dann überlegen, was ist meine neue Version? Das ist ja schrecklich.
Ja, da haben wir ja vorhin schon mal so angedeutet, dass man immer so schöne, kurze, vielsagende Commit Messages schreiben soll, was, wie wir angedeutet haben, schon gar nicht so einfach ist. Ich könnte jetzt natürlich in die Commit Message reinschreiben, ich habe hier ein neues Feature entwickelt und das heißt so und so und dann könnte ich, wenn ich dann eine neue Version erstelle, könnte ich durch die Commit Messages durchgehen und sagen, ah, guck mal, hier hat der Mark geschrieben, er hat ein neues Feature entwickelt, dann mache ich mal die zweite Stelle hoch jetzt. Das ist uns natürlich viel zu fehleranfällig und viel zu aufwendig, wenn wir da hunderte, dutzende Commits, was auch immer haben, dann funktioniert das so einfach nicht. Das heißt, wir benutzen dieses semver, das haben wir schon mal gesagt und haben dafür spezielle Commit-Syntax, wenn man so will. Das heißt, jeder unserer Commit Messages fängt mit einer Art Keyword an. Da gibt es zum Beispiel Feed-Doppelpunkt für ein Feature oder Fix-Doppelpunkt, wenn wir irgendeinen Bug behoben haben oder da gibt es auch so Sachen wie Chore oder Improvement, wenn sich so Kleinigkeiten geändert haben, die nicht so wirklich Auswirkungen auf die Funktionalität haben zum Beispiel. Und anhand dieser Keywords könnten wir jetzt viel schneller sehen, ist da ein neues Feature reingelaufen oder ist da ein Bug-Fix reingelaufen, aber selbst das wäre viel zu fehleranfällig und viel zu aufwendig, wenn man das alles mit eigenen Augen und Verstand machen müsste.
Ich würde sagen, wenn wir uns schon die Mühe machen, das da reinzuschreiben, dann das schreit auch nach Automatisierung. Das kann doch wirklich jetzt ein Computer verstehen, oder? Genau, dadurch, dass wir diese festgelegten Keywords da drin haben, können wir natürlich dem Computer sagen, reagier mal auf diese Keywords und der Computer ist in unserem Fall eine CI-CD-Pipeline, die wann immer wir was auf unseren Hauptbranch pushen, jetzt guckt, was steht da eigentlich in diesen Commit-Messages drinnen und die ist so schlau und sieht, okay, da ist fünfmal ein Fix drinnen, wüsste also, sie wüsste jetzt ganz hinten dieses Patch-Level erhöhen, stellt dann mal fest, ah, Moment, da der fünfte Commit, da steht aber Feed-Doppelpunkt drinnen, dann ist es also nicht hinten die letzte Stelle, die ich erhöhen müsste, sondern weiß jetzt, okay, da steht Feed-Doppelpunkt, dann muss ich die zweite Stelle erhöhen. Und so können wir über unsere Commit-Messages quasi steuern, wie die nächste Versionsnummer aussehen würde. Das ist gut, das reduziert definitiv den Aufwand, die Fehlanfälligkeit und gibt uns die Möglichkeiten, einen wirklich sehr stabilen Flow zu haben. Und damit wir als Entwickler nicht noch als Fehlerquelle davor sitzen und sagen, oh, ich habe jetzt aber ein neues Feature entwickelt und ich habe ganz vergessen, dieses Feed-Doppelpunkt davor zu schreiben, haben wir für uns immer noch so einen sogenannten Commit-Linter, der bei uns lokal quasi läuft. Das heißt, ich kann einen Commit gar nicht abschicken, wenn ich nicht eins dieser festgelegten Keywords in meiner Commit-Message vorne dran habe.
So stellen wir dann auch sicher, dass da auf jeden Fall immer die Commit-Message so ist, dass sie irgendeine Art von Release auslösen oder auch nicht auslösen würde. Sehr großartig. Wie sieht denn jetzt der gesamte Flow dann aus, wenn ich jetzt bei mir mein Feature habe, das Commit und ein paar Bug-Fixes und das alles zusammenführe? Wie läuft das Ganze, bis dann wirklich am Ende hinten irgendwo wieder ein Stück Software auf irgendeinem Server verfügbar ist?
Kannst du das einmal skizzieren? Ich nehme mal wieder unser schönes Beispiel, SocialBleaver will das gerade so am Wickel haben. Du hast dir jetzt überlegt, dass du da ein neues Feature erstellen möchtest und hast dir jetzt den Main-Branch geschnappt in unserem Fall und hast daraus einen Feature-Branch, der erstellt und hast da jetzt ein neues Feature drauf entwickelt und hast dann entsprechend da deine ganzen Commit-Messages eingegeben und sagst jetzt, so ich bin jetzt der Meinung, mein Feature ist fertig, das kann jetzt rausgehen in die Welt und würdest jetzt deinen Feature-Branch wieder auf den Hauptzweig, auf den Main-Branch zurückführen wollen und dann würden wir erst mal sagen, nö, darfst du nicht. Warum nicht? Weil der Flow wäre jetzt erst mal so ohne weiteres, ohne dass dann nochmal irgendjemand hier geguckt hat, ob du da nicht noch irgendwo einen Tippfehler drin hast oder so. Darf das nicht auf unseren Haupt-Branch gehen, weil der Haupt-Branch, der muss immer stabil sein, da dürfen keine Fehler drin sein. Also würdest du jetzt sagen, okay, ich möchte das aber gerne und würdest einen sogenannten Pull-Request erstellen oder Merge-Request, je nach Plattform, die man so nutzt und sagst, hier ist mein Feature, das ist jetzt soweit fertig, hier sind meine ganzen Commit-Messages, Maurice guck dir das bitte nochmal an. Okay. Dann würde ich diesen Pull-Request bekommen, bekomme hier irgendwie bei mir eine Notification, dass du da was für mich hast und dann würde ich mir den Code angucken, den du gebaut hast.
Vielleicht würde ich mir deinen Branch sogar auschecken, würde den bei mir in der Lokal nochmal hochfahren, selber nochmal ein bisschen ausprobieren und so und habe jetzt gesehen, da funktioniert alles und der Code sieht sauber aus, alle Tests laufen durch, super und würde jetzt sagen, den approve ich dir jetzt. Ich finde das gut, wie einfach du das darstellst, ich glaube, wir können die Situation des Pull-Requests in eine komplett eigene Session hier ausüben, was einen guten Pull-Request ausmacht, wie der geschrieben wird, worauf wir zu achten haben, wie ein Review aussehen sollte, worauf man da auch achten könnte, können wir, glaube ich, als Notizmuff für uns als Geistige machen, denn das ist so ein wichtiges Thema, insbesondere, wenn mehrere Leute dabei sind, da wollte ich hier unbedingt einmal einhaken, weil das so einfach klingt mit dem Pull-Request. Das ist vor allem als guter Teamplayer ein sehr wertvolles Merkmal, um die Zeit und Ressourcen der Mitarbeitenden wertzuschätzen, das hier wirklich gut vorzubereiten. Ja und ist auch als jemand, der das reviewt und approven soll, unter Umständen auch ein sehr direkt im Zweifel Kritik äußert und das sollte man natürlich auch in einer Art und Weise machen, dass die Person, die diesen Pull-Request erstellt hat, nicht irgendwie gleich rückwärts vom Stuhl fällt, von daher, ja, da kann man wahrscheinlich mindestens eine eigene Folge von machen, das schreiben wir uns mal direkt auf für künftige Folgen. Aber du bist ja ein exzellenter Entwickler, ich habe überhaupt keine Fehler bei dir im Code gefunden, läuft alles wunderbar und super smooth und ich bin völlig begeistert von dem, was du da so gemacht hast, also drücke ich den Approve-Button, bei dir klingelt jetzt irgendwie am Rechner, geht das grüne Lichtchen an und Konfetti schießt hinter deinem Monitor vor und du drückst den Merge-Button und in dem Moment würdest du jetzt nochmal die Möglichkeit haben zu sagen, dieses ganze Feature, was jetzt in einzelnen Commits auf deinem Feature-Branch drauf ist, das fasst du jetzt zu einem Commit zusammen in unserem File. Das heißt, du würdest jetzt nochmal da deine ganzen Commit-Messages werden jetzt zu einer großen Commit-Message zusammengefasst und du würdest da jetzt nochmal durchgehen, das ein bisschen aufräumen und dann sagst du Merge und dann landet dein neues Feature bei uns auf dem Main-Branch und jetzt läuft die Magic los bei uns, wir nutzen GitHub und bei GitHub gibt es die sogenannten GitHub-Actions, das heißt, bei GitHub auf dem Server läuft jetzt die Maschinerie los, da laufen quasi verschiedene Skripte los und die schnappen sich jetzt deinen Quellcode, den du geändert hast und auch da würden nochmal alle unsere Unit-Tests zum Beispiel durchlaufen, da würden alle Linter durchlaufen, die gucken, dass der Quellcode auch keine Fehler enthält und wenn diese ganzen Tests grün sind, dann würde am Ende unser Samware-Skript loslaufen und sich deine ganze Commit-Message angucken und eben diese ganzen Keywords durchgehen und feststellen, ah, da steht ein Feed-Doppelpunkt drin, der Mark möchte ein neues Feature releasen und würde dann aus unserer 1.0.0 eine 1.1.0 machen, würde ein Git-Tag schreiben mit dieser Versionsnummer und dieser Git-Tag, dieser geschriebene würde wiederum dafür sorgen, dass ein anderes Skript losläuft, sich diese Version von diesem Tag schnappt und diese dann irgendwohin deployed in irgendeine Cloud, irgendeinen Server, vielleicht irgendein Docker-Image erstellt oder irgendein npm-Package oder was wir da auch gerade so entwickelt haben. Und wenn wir von Packages sprechen, wir haben jetzt auch gerade als Konzentrik gerade unser erstes Kirby-Plugin released, da sorgt es dann halt auch dafür, dass wenn ich jetzt als Anwender sage, Composer Upgrade, das Composer merkt, ah, guck mal, da ist jetzt das Social Kirby-Plugin, das ist jetzt von Version 1.0.0 auf 1.1.0 gegangen, da erstelle ich mal das Update.
Das heißt, auch diese ganzen Package-Manager, die verlassen sich dann natürlich auch darauf, dass wir uns an diesen Versions-Syntax halten, weil sonst würde diese ganze Welt da gar nicht funktionieren. Das zwingt mich oder uns als Entwickler natürlich, ganz genau darauf zu achten, wie wir unsere Commit-Messages schreiben und nicht aus Versehen einen Breaking-Change in unserer Schlittstelle nur als kleines, nettes Feature zu verpacken. Und jeder, der dann dieses Update fährt, hat das Dilemma, dass sein Code schlichtweg nicht geht. Und wenn dann vielleicht bei persönlichen kleinen Side-Projects Unit-Tests fehlen, bedeutet das dann, dass deren Produktiv kaputt ist, was wirklich schrecklich ist und ziemlich sicher dazu führt, dass unser Tool nicht mehr genutzt wird. Darum der Appell an alle, die diesen Weg gehen wollen, macht euch klar, was ihr da tut, was ihr dort wirklich ändert, denkt über Seiteneffekte nach und benennt eure Commits in dem Moment sehr präzise. Ja, es ist eben nicht nur eine Nachricht, die man mal eben so da reintippelt, damit man irgendwas irgendwo hochschieben kann, sondern das kann im Zweifel Auswirkungen auf ganze Systeme haben, die eben dieses Package oder was auch immer nutzen. Da muss man sich auf jeden Fall, sobald man damit rausgeht, quasi mit irgendeinem Produkt oder Plugin oder was auch immer, bewusst sein, dass man da eine gewisse Verantwortung dann auch hat in dem Moment einfach. Ja. Hast du denn noch eine Reihe von Tipps, wenn ich mich jetzt für Git und GitHub Actions und semver und mir die Mühe mache, mich da irgendwie mit zu beschäftigen?
Gibt es noch so ein paar Punkte, wo du sagst, hey, die Fehler müsst ihr nicht machen oder nach den und den Schlagworten könnt ihr immer googlen, die mir quasi direkt schon einen ganz wichtigen Support liefern, wie ich mit dem gesamten System sinnvoll umgehen kann? Hast du da noch was im Petto? Wenn man jetzt ein bisschen neuer startet mit Git, vielleicht das schon mal genutzt hat, aber eher so in einem kleineren Rahmen und das jetzt ein bisschen, sag ich mal, größer aufziehen will oder vielleicht sogar eher sagt, man möchte es ein bisschen robuster noch gestalten, dann sollte man sich vielleicht nochmal anschauen, was es da so für verschiedene Modelle der Nutzung gibt. Also wir haben ja jetzt gerade unseren Ablauf erklärt. Unser Ablauf ist so ein bisschen eine Mischung aus zwei Modellen, wenn man so will, und orientiert sich schon sehr stark an einem sehr populären Modell, das ist das sogenannte Git-Flow-Modell, wo eben nicht nur ganz klar festgelegt ist, wie wir es jetzt gerade beschrieben haben, wie die Commit-Messages lauten müssen, sondern da gibt es auch einen ganz, ganz klaren und sehr, sehr strengen Ablauf, wie ich mit Branches zum Beispiel arbeite. Bei einem Git-Flow habe ich grundsätzlich zwei Branches, die es immer gibt, das ist der Main-Branch, der Haupt-Branch, den man hat und es gibt den Develop-Branch und ich will da jetzt nicht in Details gehen, ich glaube, über Git-Flow alleine könnte man wahrscheinlich auch nochmal eine Podcast-Folge machen und über Für und Wider streiten, aber der grundsätzliche Ablauf ist, ich würde jetzt ein neues Feature bauen wollen und würde mir dementsprechend einen neuen Feature-Branch erstellen und in Git-Flow würde ich mir diesen neuen Feature-Branch von dem Develop-Branch abzweigen. Ich würde dann auf diesem Feature-Branch mein Feature entwickeln und dann würde das wieder, wie wir es eben beschrieben haben, mit Pull-Requests und so weitergehen und der Feature-Branch würde dann wieder zurück in den Develop-Branch laufen.
Da könnten im Parallel noch andere Features wieder reingelaufen sein, das heißt, ich habe dann einen Develop-Branch, der ein oder mehrere Features enthalten kann und ich sage jetzt diese ganzen Features, die sollen jetzt raus in die Welt, die sollen jetzt in mein Produkt rein, dann würde ich aus dem Develop-Branch den Release-Branch erstellen, da können jetzt nochmal ganz viele Tests loslaufen, da würde vielleicht nochmal QA raufgucken und sagen hier, wir schauen mal, wenn wir jetzt im Fall einer Website oder sowas sind, wir lassen da nochmal unsere Tests drüber laufen und wir klicken selber nochmal rum und was man sich dann so alles ausdenkt und wenn auch das Release dann, was aus diesen verschiedenen Features dann besteht, sauber ist und alles gut ist, dann kann ich diesen Release-Branch wiederum in den Main-Branch reinschieben, würde einen Tag erstellen für dieses Release, das ist das, was wir gerade beschrieben haben, das kann man automatisiert machen durch die semver-Geschichte, ich könnte das natürlich auch händisch machen und sagen, ich lege jetzt hier einen Tag an und wenn ich diesen Tag erstellt habe, dann kommt der Release-Branch auch wieder zurück in den Develop-Branch, damit alles in Sync ist und am Ende lösche ich den Release-Branch und habe im besten Fall wieder meinen Main und meinen Develop-Branch und kann von da wieder weiter in weitere Features aufsplitten. Da sehe ich bei ganzen Branches und Zweigen den Wald vor Bäumen nicht mehr, das ist ja verrückt, gibt es da ein bisschen was Einfacheres, wenn ich im Kleinen unterwegs sein möchte, denn das Git-Flow klingt gewaltig. Das ist ziemlich groß und das kann, glaube ich, auch ein bisschen überwältigend sein, wenn man da neu mit anfängt, aber es gibt zum Beispiel noch sowas wie Trunk-Based-Development, da habe ich quasi meinen Haupt-Branch, das ist so meine Source of Truth, wenn man so will und da passiert dann die ganze Magie drin und ich könnte noch einen Feature-Branch erstellen und darauf arbeiten, aber letztendlich läuft immer alles in meinen Haupt-Branch wieder rein und ich zweige da gar nicht so viel ab, wie ich das irgendwie gerade beschrieben habe. Was wir quasi mit unseren Branches, was wir gerade beschrieben haben, mit unseren Feature-Branches und Pull-Requests und so, das ist so ein bisschen der Mittelweg zwischen diesem ganz einfachen ich habe einen Branch und der läuft durch, zu ich habe einen Git-Flow, wo es irgendwie etliche Release-Branches und was weiß ich immer gibt. Alles klar und ich glaube, es gibt noch viele, viele weitere Möglichkeiten, wie man das machen kann, googeln hilft da sicherlich und wo es dann wirklich spannend wird aus meiner Sicht, ist dann der Punkt, was ist, wenn ich irgendwo mittendrin einen Hotfix habe, wie funktioniert das in Git-Flow, wie führe ich den überhaupt wieder in irgendwelche Branches zurück. Und das ist je nach Modell unterschiedlich, einfach oder schwierig und hat dann sicherlich auch damit zu tun, wie dann die jeweiligen Branches dann in Produktiv überführt werden, also welche Compliance-Regeln ich erfüllen muss, welche Testabdeckungen, habe ich da gewisse Regularien, dass irgendwelche manuellen Tests abgezeichnet werden müssen, weil ich im streng regulierten Markt bin und was weiß ich, Medizinprodukte oder ob ich im kleinen Hobby-Site-Projekt bin, das macht glaube ich einen großen Unterschied aus, wie ich da sinnvoll rangehe, weil am Ende muss das immer den Zweck erfüllen und zwar, dass ich weiß, wo was ist und wie ich verschiedene Entwicklungsstränge sinnvoll zusammenführe. Ich glaube, letztendlich, so haben wir es ja auch gemacht, ist es sinnvoll, sich mal diese ganzen Modelle anzuschauen, zumindest die populärere Modelle Git-Flow und so und dann für sich selber zu entscheiden, das vielleicht mal auszuprobieren und zu sagen, okay, da ist bei uns, da ist uns zu viel Overhead, das macht uns mehr Arbeit, als dass es uns Nutzen bringt und das dann für sich so anzupassen, dass man für sich die beste Kombination aus diesen Welten hat und dann ist glaube ich einfach nur wichtig, dass man sich dann aber auch wirklich an dieses Konzept, was man sich überlegt hat, hält.
Ich glaube, das ist das A und O, egal was man nutzt, es müssen sich halt auch wirklich alle dran halten, sonst funktioniert es nicht. Genau, vielen Dank Maurice, dann weiß ich ja, ich entscheide mich für irgendeinen Flow und da waren ja jetzt jede Menge Themen. Magst du das nochmal für mich zusammenfassen, wie starte ich, worauf achte ich jetzt nochmal, wenn ich loslegen möchte? Ich glaube, ein guter Tipp ist an der Stelle, wenn man mit Git startet oder auch einfach nur ein neues Projekt geht, wo mit Git gearbeitet wird und man selber hat auch schon mit Git gearbeitet, wie gesagt, sich einfach mal den Branch, den Hauptbranch schnappen, einfach mal ein bisschen zurück in die Git-Historie gucken, gucken, wie werden da Commit-Messages geschrieben, wie groß sind die Commits, die da passieren, einfach, dass man so ein bisschen ein Gefühl dafür kriegt, wie andere schon damit arbeiten und dann im Zweifel nochmal in Dialog gehen mit den Leuten, mit denen man da arbeitet und sagt, pass auf, wie habt ihr euch das hier eigentlich gedacht, wie sind denn hier die Abläufe und ich glaube, dann ist das schnell, dass man von dieser Git- und semver-Welt. Absolut. Wenn ihr Git nutzt, dann schreibt uns doch mal, wie ihr Git nutzt, vielleicht welches Prinzip ihr nutzt, ob ihr Git-Flow nutzt oder irgendeinen anderen Workflow für Git, vielleicht habt ihr auch noch spannende Tools, von denen ihr erzählen könnt, so oder so, wir freuen uns von euch zu hören, wir packen euch nochmal alle Infos, die wir hier so rausgehauen haben, in die Show-Notes, da findet ihr den Link zu unserem Beitrag zu dieser Folge, da kann ich euch auch nochmal so ein Cheatsheet mit reinpacken und so, dass ihr da nochmal ein bisschen weiter in die Recherche gehen könnt, wenn ihr denn wollt. Sehr gute Idee.
Wenn ihr mögt, lasst uns gerne auch ein Review da, das hilft uns sehr und empfiehlt uns gerne weiter, damit unser Podcast hier auch nochmal so ein bisschen die Runde macht, das würde uns sehr freuen. Wir hören uns auf jeden Fall in zwei Wochen wieder und bis dahin würde ich sagen, Mark, mach's gut, bis in zwei Wochen. Ciao Maurice, ich freue mich, bis dahin.