 Okay, jetzt sind wir nach und darum an der Stelle, einen großen Willkommen an Florian Haas mit seinem Vortrag, ein kurzer Blick ins Git. Okay, jo, hallo. Willkommen zu meinem Vortrag für alle, die schon mal von Git verwirrt worden sind. Wenn man täglich mit Git arbeitet, hat man meistens mit der Hand voll einfacher Kommandos zu tun, die meistens das tun, was man will. Aber manchmal fällt einem Git dann doch in den Rücken und gibt dann irgendeine kryptische Fehlermeldung aus und man muss den lokalen Git-Guru suchen oder Dinge funktionieren einfach nicht so, wie man es sich wünscht. Dann kann es hilfreich sein, wenn man versteht, was Git im Hintergrund eigentlich tut. Wenn wir uns das angucken wollen, brauchen wir erstmal ein leeres Verzeichnis und darin legen wir uns ein Repository an. Git sagt, hier hat ein leeres Repository angelegt, aber tatsächlich gibt es in dem Verzeichnis jetzt ein Unterverzeichnis, nämlich dieses Punkt Git und da hat Git einige Dinge angelegt. Paar davon sind Beispiel-Dateien, die brauchen wir nicht, aber der Rest ist durchaus interessant. Wir haben da die Config-Datei, da wird Grundanstellung für dieses Repository konfiguriert, das interessiert uns heute nicht. Es gibt die Beschreibung, die können zum Beispiel GitLab anzeigen oder andere Tools. Und es gibt noch eine dritte Datei, die da liegt, Het, die enthält im Moment eine Referenz auf einen Dateinamen, der den aktuell ausgecheckten Branch beschreibt. Das Verzeichnis, in dem diese Datei liegen, liegen soll. ResHats können wir oben in der Liste sehen, aber die Datei gibt es noch nicht. Das Verzeichnis ist leer. Und auch wenn man guckt, fast alle anderen Verzeichnisse, die Git angelegt hat, sind leer. Aber wenn wir jetzt mehr mit Git arbeiten sehen, wer das darin einiges passieren wird. Und deshalb werden wir ein paar von diesen Verzeichnissen für den Rest des Vortrages rechts im Auge behalten. Was Git mit diesen Verzeichnissen macht, ist, dass es über das normale Dateisystem, in dem man Dateien über ihren Namen identifiziert, ein virtuelles inhaltsadressiertes Dateisystem legt, in dem Dateien über ihren Inhalt identifiziert werden. Der Unterschied ist, dass bei einem normalen Dateisystem man ein Dateinamen hat und dann sagt man dem Dateisystem, okay, gib mir eine Datei mit diesen Namen, zum Beispiel, theWalkBackgroundPing, um hier den Hintergrund um mich herum zu bekommen. Und wenn man das macht, dann gibt einem das Dateisystem diese Datei zurück, die so heißt, egal was da drin ist. Bei einem inhaltsadressierten Dateisystem kennst du dagegen den Inhalt der Datei, zum Beispiel die Häschen und Karotten da. Und du bittest das Dateisystem, gib mir ein Datei mit diesem Inhalt und das Dateisystem macht genau das. Das klingt jetzt erstmal doof. Ich meine, warum soll ich die Datei vom Dateisystem anfordern, wenn ich den Inhalt schon kenne, dann habe ich den doch schon. Der Trick ist, das gibt für die Identifizierung einer Datei nicht direkt den kompletten Inhalt benutzt, sondern einen eindeutigen Häschwert. Gucken wir uns ein Beispiel an und wir nehmen die Zeichenkette FU und schicken die an den befähigen GishatObject. Dann bekommen sie einen Häsch zurück, hier BC56C4 und dieser Häsch identifiziert eindeutig eine Datei mit dem Inhalt FU. Wir können diesen Häsch zum Beispiel nehmen und ihnen zusammen mit ein paar Schlüsselworten, die ein Git Repository einigermaßen eindeutig identifizieren, an eine Suchmaschine unseres Vertrauenswerfer dann. Und wenn wir diese Gernfrage jetzt abschicken, sehen wir hoffentlich, gestern war das Suchergebnis noch da, eine Datei in dem Source Code Explorer von Chromium, diese FALSE1-Bar. Wir können die Datei aufmachen und wir sehen, okay, das ist ein Blob mit genau dem Häsch BC56C4 und der Inhalt dieser Datei ist FU, genau der, den wir haben wollten. Wir haben die Datei über ihren Inhalt gefunden. Jo, Google hat so eine Datei, muss cool sein, wir wollen auch eine haben und wir machen sie mit KitAt, Kit auch gleich bekannt. Diese Aktion KitAt, das sagt man auch dazu, man hat die Datei dem Index hinzugefügt. Wenn ihr euch gefragt habt, woher dieser Ausdruck kommt, wenn ihr jetzt rechts guckt, ihr seht, wir haben eine neue Datei, die heißt Index. In dieser Datei verweitet Kit Information über den Zustand der ihm bekannten Dateien im Arbeitsverzeichnis. Das ist eine Binärdatei, mit der man im normalen Fall nicht viel zu tun hat, aber man kann mal direkt reingucken mit OD und man stellt fest, dass wir da ein paar Dinge drinnen wiederfinden, die wir schon kennen, nämlich genau unseren Häsch BC56C4 und so weiter, den wir hier in der Mitte sehen und auch rechts unten in der Ecke der Dateiname FU Text und das Thema noch in der nächsten Zeile. Ja, die andere neue Datei, die wir da rechts sehen, ist in diesem Objects Unterverzeichnis entstanden und der Dateiname ist offensichtlich direkt von unserem Häsch abgeleitet. Es liegt in einem Unterverzeichnis BC, das ist gerade die Hexdarstellung des ersten Bytes von dem Häsch und der Rest des Dateinamens in der Datei ist dann auch einfach der Rest des Häschs. Wenn man Kit schon mal benutzt hat, dann sieht dieser Häsch der Datei erstmal nicht anders aus, als der Häsch von irgendeinem Komet und tatsächlich kann man sich mit Kit Show nicht nur Komets angucken, sondern ebenso gut einzelne Dateien. Also wir machen jetzt Kit Show mit genau dem Häsch. Wenn das jetzt der Häsch von einem Komet wäre, würden wir erwarten, dass wir irgendwie das Komet Datum kriegen, den Namen des Kometters oder der Kometterinnen und Komet Text, aber das ist jetzt halt kein Komet-Hasch, sondern ein Dateihasch und wenn wir jetzt Kit Show mit einem Dateihasch abschicken, was kriegen wir? Den Inhalt der Datei, keine große Überraschung. Wenn wir unsere neue Datei jetzt kometten, passiert wieder ein bisschen was in dem Kit unter Verzeichnis rechts. Wir kriegen zwei neue Dateien in dem Objektsverzeichnis. Die eine Datei ist offensichtlich das Komet-Objekt. Wir sehen der Dateiname unter Verzeichnis 8,4 und dann Dateiname weiter e748b und so weiter passt genau für den Häsch von unserem Komet auch 8,4, e748b. Und was ich auch gesehen, was ich auch geändert hat, wir sehen jetzt endlich unsere Resheds Master Datei auf die Het ganz oben schon die ganze Zeit verwiesen hat. Und wenn wir da reingucken, sehen wir, der Inhalt dieser Datei ist auch wieder genau der Häsch von dem Komet, 8,4, e748b und so weiter. Ja, wenn wir uns jetzt diesen Komet angucken mit dem Häsch, dann finden wir das, was wir erwarten. Den habe ich gerade angelegt. Er hat eine Komet-Message, nämlich genau Import FU, was ich oben als Komet-Message angegeben habe. Und wir sehen da ein Diff, der zu dem Komet gehört, was sich gegenüber dem Vorgänger Komet geändert hat. In diesem Fall war es ein leeres Repositories. Er hat genau eine Datei hinzugefügt namens FU Text mit dem Inhalt Häsch BC564CD. Genau, mit der Einzahle drin FU. Wir sehen hier aber noch einen zweiten Häsch, der in diesem Komet referenziert wird, hier oben mit dem Schüsselwort Tree. Dieser Häsch, 8f3761e und so weiter, passt genau zu dem zweiten Objekt, das in dem Objectsverzeichnis neu angelegt worden ist. Den können wir uns auch wieder mit GitShow angucken. Sehen wir nicht so richtig viel, sagt uns, es ist ein Tree-Objekt und es gibt genau eine Datei, die in diesem Tree liegt, nämlich FU Text. Wir kriegen ein bisschen mehr Informationen, wenn wir GitAllestree benutzen. Dann sagt er uns nicht nur, dass wir die Datei FU Text haben, sondern auch, dass es ein Block ist, dass es Gitsname für eine ganz normale Datei, die irgendein Inhalt haben kann. Wir sehen vorne Standard Unix Dateizugrufsrechte für eine Datei mit dem Inhalt FU erwarten. Fügen wir auch noch eine weitere Datei hinzu. Hat den gleichen Inhalt, wir machen sie Git bekannt und wir sehen rechtserst mal, dass sich nicht viel in dem Git Unterverzeichnis geändert hat. Der Inhalt der Index Datei hat sich natürlich geändert, aber die können wir in dieser Ansicht nicht sehen. Aber obwohl wir eine neue Datei hinzugefügt haben, haben wir kein neues Objekt in unserem Unterverzeichnis. Auch weil die Datei hat den gleichen Inhalt wie die Datei, die schon da ist. Und damit ist es für Git das selbe Objekt. Wir können jetzt die Datei kommenten und wir sehen rechts wieder zwei neue Objekte. Eins ist wieder das Commit Objekt 8B168C und so weiter. Können Sie genauer angucken. Wir sehen hier wieder den Tree und der Tree rechts ist genau der gleiche. Und der Inhalt von diesem Tree Objekt ist jetzt zwei Dateien. Eine heißt FU Text, eine heißt Bar Text und beide haben genau den Hasch von einer Datei, in der einfach nur FU drinnen steht. Was gegenüber dem ersten Commit noch neu ist, ist dieses Parent Feld in dem Commit, der den Hasch des vorherigen Commits enthält. Wir sehen genau das 8V ist genau der Hasch das wir rechts in dem Objekt Verzeichnis sehen können. Diese Verweise auf Parent Commits sind alles, was aus dem inhaltsadressierten Dateisystem Git an Versionsverwaltungssystem macht. Wir haben die fundamentalen Objekte von Git, das ist der Commit, der verweist immer auf ein Tree, also auf den momentanen Zustand des Dateisystems, also des Projektverzeichnisses. In diesem Fall ist es halt das Tree Objekt mit dem FU und Bar Text und wir haben Parents, also Parent Felder, die aus dieser Menge von Commits, also von Dateisystem Zuständen eine Versionshistorie macht. Dadurch wird Git halt zu einem Versionsverwaltungssystem und es macht aus dieser Menge von Commits einen gerichteten Graphen. Den können wir uns mit Gitlock Graph angucken und wir sehen, wir haben jetzt einen relativ einfachen Graphen. Es hat einfach nur zwei Commits, die mit einer Linie verbunden sind. Das ist im Prinzip das gesamte Dateimodell von Git, was man hier auf dieser Folie jetzt sehen kann. Es gibt Commits, es gibt die Tree Objekte und es gibt die eigentlichen Daten in Blobs. Und alles wird gleichermaßen über Hashes identifiziert, die man da rechts in dem Object Verzeichnis sehen kann. Zusätzlich gibt es dann noch Branches, wir haben hier diesen einen Branch, den Master Branch und den Graph Hats Verzeichnis. Dass aber so ein Branch in Git ist erstmal nur eine einfache Datei, die den Hash eines Commits enthält. Das ist anders als von manchen anderen Versionsverwaltungssystemen. Darauf gehe ich aber später noch genauer ein. Jetzt möchte ich erstmal eine sehr angenehme Eigenschaft von Git erläutern Das ist, Git wirft diese ganzen Objekte, die es da anlegt, typischerweise ganze Zeit lang nicht weg, selbst wenn nichts mehr auf so ein Objekt verweist. Typischerweise bewahrt es alte Objekte, selbst die man nicht mehr braucht, noch zwei Wochen auf. Und das macht es häufig möglich, wenn man einen Merch oder Rebase-Unfall hatte und man hat sich den kompletten Repository zerschossen und alles besteht nur noch aus Konfliktmarkern, häufig möglich, die verloren geglaubten Daten wiederherzustellen, wenn man weiß, wo man suchen muss. Nehmen wir zum Beispiel an, dass wir unseren letzten Commit durch ein falsches Kommando verloren haben. Ich mache das einfach in dem Hats, den kommt den Commit davor auschecken. Jetzt ist unser neue Datei Bar Text weg und auch in dem Graphen aller Versionen in dem Repository taucht der zweite Commit nicht mehr auf. Aber rechts in dem Git-Unterfall-Zeichen ist, können wir sehen, dass alle die Objekte, die wir hatten, auch das Commit-Objekt von dem zweiten Commit, alle noch da sind. Und wir sehen eine neue Datei, Urequette, und die enthält den hash des gerade eben verloren gegangenen Commits enthält. Darüber konnten wir den Commit jetzt wiederfinden, wenn uns der Fehler rechtzeitig auffällt. Aber halt nur, wenn wir das gleich merken, ist das eine andere Möglichkeit, die auch immer funktioniert, wenn man auch ältere Commits oder mal eine Stunde später oder so das erst merkt. Und so wiederzufinden ist, dass man über das Ref-Lock geht. Das enthält Informationen darüber, welche Commits schon mal ausgecheckt waren. Hier sehen wir das Ref-Lock. Wir hatten drei verschiedene Commits ausgecheckt. Während dieses Repository existiert, ganz am Anfang haben wir den Initialen Commit, der Food Text importiert haben. Dann hatten wir den zweiten Commit, wo wir Bar Text hinzugefügt haben. Und dann der dritte Verstand, den wir ausgecheckt haben, das war, als wir wieder auf den ersten Commit den Branch zurückgesetzt haben. Der Commit, den wir jetzt haben wollen, ist der Zweite aus dieser Liste. Den können wir uns den Commit hash merken und wir können den aktuellen Branch, z.B. ebenso wie wir ihn hart auf den falschen Commit auf den ursprünglichen Commit zurücksetzen. Und wenn wir das machen, sind wir genau da, wo wir eben schon mal waren. Wir haben wieder zwei Commits, die durch diese eine Linie verbunden sind. Eine andere Situation, in der man sich manchmal befindet, insbesondere wenn man alte Version im Ref-Lock untersucht, ist die, dass man einen Commit ausgecheckt hat, sich aber nicht auf einem Branch befindet. Hier check ich z.B. jetzt einfach mal den Commit vor dem aktuellen Commit aus. Jetzt zeigt Het nicht mehr auf einen Branchnamen, sondern direkt auf einen Commit. Hier sehen wir jetzt in der Grafenansicht. Wir haben den Master Branch, der oben auf den Commit 8b16 verzeichnet. Aber der Het, also das momentan ausgecheckte Zustand, ist unten der erste Commit 8b4e7. Und wir können jetzt auch die Het-Datei angucken. Da war vorhin die Referenz auf RedHatsMaster drinnen, also ein Verweis auf eine Datei-Namen von einem einer Branchdatei. Und da steht jetzt direkt die ID eines Commits drinnen. Das ist zunächst mal eigentlich überhaupt kein Problem. Man kann in dieser Situation fast normal weiterarbeiten. Wenn man jetzt aber irgendwie ein Ding geändert und die committet, dann hat man es eventuell schwierig, diesen Commit wiederzufinden. Und man muss ihn dann irgendwie im Reflog suchen, was häufig eine doofe Situation ist. Und vor allem nach zwei Wochen, wäre der Commit dann tatsächlich weg. Aber gibt uns hier mit dieser langen Mitteilung eine Möglichkeit, und sagt uns, wie wir aus dieser Situation rauskommen. Einfach man sich das durchliest. Aber wenn Sie einen neuen Branch erstellen möchten, um Ihre erstellten Commits zu behalten, können Sie das jetzt oder später durch einen weiteren Checkout mit der Option Minus B tun. Machen wir das doch einfach. Wir legen einen Branch Morfu an. Jetzt zeigt Het wieder auf einen Branch und nicht mehr auf einen Commit, nämlich auf die neue Datei in RedHats. Und der Branch, der da neu angelegt worden ist, zeigt genau auf unseren Commit 8b4e7. Wir können uns das auch nochmal in der Grafenansicht ansehen. Der Graf sieht genauso aus wie davor. Nur unten ist Het jetzt nicht mehr direkt auf den Commit, sondern Het zeigt erst mal auf den Morfu-Branch, der auf den Commit zeigt. Mit diesem Branch können wir jetzt ganz normal arbeiten, als wenn nichts gewesen wäre. Wir können zum Beispiel eine Datei ändern, zum Beispiel eine Zeile hinzufügen. So, können wir uns angucken. Die Datei ist eine Zeile länger geworden. Wir fühlen, machen Sie Git bekannt oder die Änderung, sagen, Git add Datei. Und wir sehen, es ist ein neues Objekt rechts angelegt worden, das gerade halt das Objekt ist von dieser Datei mit zwei Zeilen. Wir können das Committen und kriegen wieder zwei weitere neue Objekte in dem Objektsverzeichnis. Der Het ist immer noch unser Branch, aber der Branch zeigt jetzt nicht mehr auf den Commit 8b4e7, sondern natürlich auf den neuen Commit e50d72b. Wenn wir uns den Grafen angucken, sehen wir, wir haben jetzt eine Abzweigung. Wir haben den Anfangskommit und von der zwei Commits, die von diesem Anfangskommit abgehen. Der eine hat die Datei Bar Text hinzugefügt und der andere hat noch ein paar Fuß in die erste Datei hinzugefügt. Ja, jetzt können wir diesen Branch in den Master Margen. Dazu wechseln wir erst mal wieder auf den Master Branch. Wie erwartet hat sich jetzt der Het geändert? Er zeigt nicht mehr auf Resets Morphu, sondern auf Resets Master. Das genau heißt es, den Branch zu wechseln und wir können den Branch merken und löschen. Der Branch ist gemirkt. Wir brauchen ihn eigentlich nicht mehr. Das ist eine gute Angewohnheit, Branches, die gemirkt sind, möglichst bald zu löschen. Das macht viele Dinge übersichtlicher. Jetzt können wir uns den letzten Commit auf den Master angucken und wir sehen, sieht genauso aus wie ein normaler Kommit. Der einzige Unterschied zu den Commits, die wir bisher gesehen haben, ist, dass er zwei Parent-Felder hat. Und das ist dann auch der einzige Unterschied zwischen einem Merch-Kommit und einem normalen Kommit. Ein Merch-Kommit hat zwei oder mehr Parents. Ein normaler Kommit hat höchstens einen Parent. Wenn wir uns den Grafen angucken, sehen wir auch genau die Situation. Wir haben drei einfache Commits. Der Unterste, der allererste, hat keinen Parent. Dann die beiden Commits da drüber, 8B16 und 5E0D haben beide einen Parent, nämlich den ersten. Und der letzte Commit hat die beiden anderen Commits als Parents. Das sind, ja. Jetzt haben wir mit zwei Branches gearbeitet, zwischen ihnen gewechselt und Dinge gemirrt. Und jetzt ist eigentlich ein guter Punkt, um nochmal darauf einzugehen, was eigentlich ein Branch ist. In vielen Versionsverwaltung sind Branches schwierig, schwerwiegende aufwendig zu verwaltende Dinge. Subversion zum Beispiel hat man dann fast ein Kopie, um die ganzen Repositories um ein Branch anzulegen. Und wenn man einen Code zwischen verschiedenen Branches zusammenfügen will, kann das schon mal schwierig sein. Oder man muss auf jeden Fall gut darüber nachdenken, was man da machen will. Vergleichend damit gibt es in Git eigentlich fast gar keine Branches. Wie gesagt, Branches ist wirklich einfach nur eine Datei da rechts unten in dem Resets Verzeichnis. Und dann ist das Commits drinnen. Branches ist wirklich nur ein Name, der auf einen Commit zeigt und macht es einfacher macht, diesen Commit wiederzufinden. Und es gibt halt nur noch diese eine zusätzliche Konvention, die wir eben auch schon in Aktionen gesehen haben. Wenn der Head auf einen Branches zeigt und ich da einen neuen Commit anlege, dann wird der Branches so aktualisiert, dass er auf diesen neuen Commit zeigt. Gucken wir uns den Merge-Commit von eben nochmal an. Branches und Branchnamen werden hier tatsächlich nur, indem man zukünftige Benutzer gerichteten Freitextfeld der Commit-Message erwähnt. Für Git und für die Versions-Historie, die Git verwaltet, sind nur die Verweise auf die Parent-Commits wichtig und transitiv dann deren Parents. Aber ob diese Commits jeweils auf einem Branch waren, oder ob dieses alles mit losgelösten Hets passiert wird und man nur irgendwie später, nachdem man alles gemirkt hat, dann ein Master-Branche auf den letzten Commit gesetzt hat, das ist Git völlig egal, das kann man anhand der Git-Historie auch nicht feststellen. Diese Information, ob dieser Commit früher, also sagen wir jetzt, der Parent-Commit 8b, 1, 6, ob der irgendwann mal auf ein Master-Branch war oder auf irgendeinem anderen Branch war, diese Information gibt es im Git nicht. Auch wenn man sich den Graphenansicht anguckt, hier sehen wir eine Referenz auf einem Branch, nämlich ganz oben in der allerersten Zeile, dass der Head, der gerade ausgesteckte Head auf den Master-Branche zeigt, der gerade dann wiederum auf den Merch-Commit zeigt. Sonst, diese ganzen Linien sind einfach nur Beziehung zwischen einem Commit und seinem Parent-Commit, aber es gibt keine Identität von Branches entlang dieser Linie. Also diese Linien, man denkt bei Branches ein Ast oder ein Zweig und das ist irgendwas, was irgendwo abzweifelt und hinwächst, aber in der Konzeption von Git sind diese Linien erst mal kein Branches zugeordnet. Branches ist natürlich nur der Name für den aktuellen Stand des Repositories. Dass Branches im Wesentlichen nur Namen, nur Schall und Rauch sind, ist was das für manche Leute, die von anderen Systemen kommen anfangs Schwierigkeiten bereitet. Das führt dann manchmal dazu, dass die komischen Regeln aufstellen, wie man mit Branches umgehen soll und dass man irgendwelche Branchverwaltungsregeln aufstellen, die eigentlich nicht hilfreich sind und auch überhaupt nicht zu den Konzepten von Git passen. Klassisches Beispiel dafür ist das Git Flow, das vor ein paar Jahren aufgekommen ist. Das ist um die Idee strukturiert, dass der Branch, auf dem ein Commit gemacht wurde, eine ganz wesentliche Eigenschaft dieses Commits ist. Das sieht man dann, ich weiß nicht, wenn jemand die Grafiken von Git Flow, von der Webseite kennt, an diesen langen, geraden Linien, die alle Commits einer Farbe verbinden. Master ist alles blau und Develop ist alles gelb und so was, aber das passt überhaupt nicht zu den Konzepten von Git. In Git haben Commits einfach keine Farbe und Branches sind nicht irgendwelche langliebigen Versionen von Source Code oder so was, sondern wirklich die Verweisen auf den aktuellen Stand. Das ist ein Name für einen bestimmten Stand des Repositories. Es kann sein, dass es Projekts Setups gibt, wo man tatsächlich solche schwergewichtigen Branches haben will, aber wenn man das möchte, sollte man überlegen, ob Git wirklich das System ist, das man haben will. So wie es in Git Flow realisiert wird, führt das meiner Ansicht nach nur dazu, dass es einen ganzen Haufen Bürokratie gibt und einen ganzen Haufen Merge-Commits, die eigentlich überhaupt nichts dazu beitragen, die Geschichte des Projekts irgendwie einfacher verständlich oder besser handhabbar zu machen. Ja, das sind so die grundlegenden Konzepte und haben einen ganzen Haufen Objekte angesehen. Wir sehen rechts da, das passt gar nicht mehr in das Fenster. Es läuft schon über die Baumansicht von diesem Objects Verzeichnis. Da mag man sich fragen, wie so viele Dateien in vielen Verzeichnissen anlegen, wird das nicht auf Dauer ziemlich langsam, wenn Git da immer diese ganzen Verzeichnisse durchsuchen muss. Im Prinzip würde es das tun, wenn das alles ist. Also wie gesagt, das ist das logische Modell. Logisch, man kann alles, was Git macht, mit dem einfachen Modell verstehen, aber physikalisch aus Effizienzgründen macht Git noch ein paar andere Sachen. Und zwar räumt es regelmäßig dieses Verzeichnis auf oder auch auf Verlangen. Dazu gibt es den Befehl GitGitC für Garbage Collection oder Müllabfuhr. Und wenn ich den ausführe, dann räumt Git das Objects Verzeichnis auf und packt alle die Objekte, die da waren, in eine sogenannte Pack-Datei. Weniger Datei-System überhaupt, das ist eine Binär-Datei, in der Git effizienter drinnen suchen und mitarbeiten kann. Die Objekt-Dateien sind alle weg, aber die Objekte selbst leben halt weiter in den Pack-Dateien und ich kann sie alle noch sehen. Hier gibt es der Graph, alles noch da, alle unsere Commits sind da. Und mit den Commits natürlich auch die referenzierten Tree-Objekte und die ganzen Blobs, in denen fuhr drinnen steht. Dieses Aufräumen ist übrigens eine der wenigen Situationen, in denen Git tatsächlich mal Daten wegwirft. Nicht mehr referenzierte Objekte, gewisses Alter übersteigen. Normalerweise sind das halt wie gesagt zwei Wochen, werden bei einer Garbage Collection unwiederbringlich gelöscht und dann hilft es auch einem nicht mehr, wenn man die Commit-It noch im Reflog findet oder sie von früher irgendwie noch weiß, weil sie irgendjemand mal ausgedruckt hat, dann sind die Daten weg, aber vorher nicht. Also wenn man letzte Woche einen Fehler gemacht hat, man Git in der Default-Konfiguration betreibt, dass man die Daten, die man letzte Woche aus Versehen mal gelascht hat, einfach nochmal wiederfinden kann. Das ist so mein kurzer Einblick in das, was Git da alles an Magie in diesem Punkt Git-Unterzeichnis macht. Ich hoffe, es hat ein paar Leuten geholfen, besser zu verstehen, was da passiert und vielleicht auch die eine oder andere Fehlermeldung besser verständlich gemacht, über die man in der Zukunft stolpert und die senkt vielleicht auch die Arbeitslast für den lokalen Git-Guru. Ja, vielen Dank für eure Aufmerksamkeit. Habt ihr Fragen? Das ist sehr gut, dass ich anfangen kann. Dafür müsste ich jetzt den Fragentepp aufhaben. So, das kann sich nur um. Ich habe so viele Fenster auf. Ja, so ist das halt manchmal. Ähm, ja. Ich höre ihn gerade nicht. So, ich rede. So, jetzt bin ich im Mambel an. Sehr schön. Dann kommen wir jetzt zur Frage-Session. Ich war ja gerade dabei, wenn ihr wisstet, wie viele Fenster ich aufhabe. Darf. So, sehr gut, ich gehe nach hier oben. Ja, sehr schön. Also, Wasser marsch. Und irgendjemand schreibt oben drüber, schließt du deine Fenster. Okay, hast du recht. Weißt du eventuell, warum die Index-Datei binary ist und nicht irgendwas Lesbares? Weiß ich nicht, vermutlich, weil es dann schneller geht. Keine Ahnung. Hast du ein paar Beispiele aus der Praxis, wo dir dieses Wissen was bringt? Ähm, es bringt einem manchmal mal was, wenn bei irgendeine Merch-Config-Dinge verloren gegangen sind und man dann später mal genau wissen will, wann war das, eventuell, wenn, oder wenn Merchant Rebase war, einfach, dass man gucken kann, nochmal, ob der Commit, den es schon nicht mehr in der offiziellen History gibt, ob man den nochmal finden kann. Es ist genau, in der täglichen Arbeit, wie gesagt, hat man seine sechs, sieben Kommandos, die das meiste tun, aber es ist manchmal hilfreich, wenn halt irgendwas schiefgesang ist. Wo ist das Reflog oder dessen Information? Im Dot-Git-Orter? Das ist auch in Dot-Git-Orter, das ist eines von den Verzeichnissen, die ich ausgeblendet habe. Wenn ich hier nochmal, sehen wir hier noch ein neues Verzeichnis, dass ich die rechts nicht angezeigt habe, weil das ohnehin schon voll war, das ist dieses Logs, Reset, Master und so daraus, da liegen diese Informationen drinne. Okay. Wie teilen sich die Indexinformationen der Commits in den Pack-Files auf? Wie funktioniert die Datei PACKT? Bundesstrich Refs. Da habe ich nicht reingeguckt. Also muss auch irgendeine Datei-System-ähnliche Struktur haben, auf die Git einfacher zugreifen kann, weil sie halt auf den einen Anwendungsfall spezialisiert ist und nicht ein allgemeines Datei-System ist. Wie funktioniert das mit Git LFS? Werden da nur die Blobs extern gespeichert? Weiß ich nicht. LFS habe ich bisher nicht gearbeitet. Wir hatten ein Projekt, wo wir das benutzen sollten, aber irgendjemand hat das nie zeitlich aufgesetzt gekriegt. Wie funktionieren Sub-Modules und warum ist die Nutzung davon so komisch in der Commando-Zeilentools integriert? Beispielsweise Folge im Sub-Module, bitte dem upstream Branch XY. Sub-Modules sind im Prinzip ein Hack, wo ich einfach in Git, eine Datei-Anlege, wo drin steht, belände hier dieses andere Repository an und mache irgendwelche komischen Dinge, wenn du was auscheckst. Es ist ein Versuch mit einem System, das Mono-Repost zu emulieren, und das beist ein. Es ist schwierig. Wie kann ein Projekt, das in zwei verschiedenen Repos angefangen wurde, für zwei verschiedene Module in ein einziges Repo überführt werden? Man kann einfach das in dem einen Repository gehen und das andere Repository als ein Remote hinzufügen und pull fetchen. Und dann kann man einfach einen, zum Beispiel den, wenn die Datei, die Verzeichnisse sich nicht überlappen, kann man dann zum Beispiel einfach einen Branch aus dem zweiten Repository in das erste Repository merken. Dann hat man halt eine Versions-History, die nicht so aussieht wie ein normales, normalerweise sieht das ja aus wie ein Baum, aber man hat vielleicht verschiedene Versionen davon ab. Und bei dem herangehen hatte man halt zwei Anfangskommits, die beide ihre History haben, bauen der von Artfight und irgendwo oben merkt man die zusammen. Dann hat man halt einen Commit, der hat zwei Parents und der eine Parent hat ursprünglich in dem einen Repository gelebt und der andere Parent hat ursprünglich in dem anderen Repository gelebt, aber das geht relativ egal. Man hat halt die normale Repository-History, mit dem Master Branch und einem Branches, die davon abzweigen und in dem gleichen Repository liegt eine zweite History, die mit der anderen überhaupt nichts zu tun hat, die einen eigenen Initialen kommen mit hat, wo dann die Projekt-Webseite drin ist. Du sagst es, GitFlow macht keinen Sinn, aber wenn zum Beispiel ein Feature über eine längere Zeit von mehreren Personen entwickelt wird, wäre es doch schon hilfreich, einen Namen für den aktuellen Stand des Features zu haben, oder? Ja, natürlich. Die Benutzung von Feature-Branches und auch die Idee, dass Feature-Branches eigentlich möglichst kurzlebig sein sollten, ist gut. Das ist das eine Ding, weshalb GitFlow funktioniert. Was nicht funktioniert, ist dieses komische, e-Siegel-Zurück-Mergin in den Master Branch. Was ich auch komisch finde, ist, dass der Haupt-Develop-Branch anders als bei Git default einfach nicht Master heißt, sondern Develop. Das macht einfach, wenn man Standard-Git-Tooling oder benutzt, macht das irgendwie komisch, weil man immer auf einem anderen Branches ist, als man glaubt. Also, ja, also die Idee, Feature-Branches zu haben, ist definitiv richtig. Die Idee, kurzlebige Feature-Branches zu haben, ist noch besser. Aber der bürokratische Overhead mit diesen komischen Master-Branches in verschiedene Richtungen gemirkt werden, ist meiner Ansicht nach im Wesentlichen nur Overhead. Was sind denn gute Workflows mit Git und Code-Review im Gegensatz zu GitFlow? Ich vermute e-Mail-basierte Workflows, aber was gibt es noch? Man muss es für das Projekt ausprobieren, was es gibt. Es gibt halt was, viel propagiert wird. Es ist halt dieses trunk-basierte Development, dass man halt den Develop hat. Man versucht den Develop immer laufig und deploybar zu halten mit kurzlebigen Feature-Branches. Das ist was, was ich auch gerne empfehle, wenn man eine Situation hat, dass man eventuell mehrere Versionen von einem Produkt unterstützen muss, weil man eine Version ausgeliefert, entwickelt eine neue. Und wenn man die neue entwickelt, muss man an der alten noch was ändern, was FreeBSD bei ihrem CVS-Branching-Modell machen. Das kann man meiner Ansicht nach auch auf Git übertragen. Man muss sich überlegen, was haben wir? Haben wir halt zum Beispiel eine Single-Page-Web-Application, wo es immer genau den einen Stand gibt. Da macht man trunk-based ohne irgendwelche Versionsbranches oder haben wir was, wo wir halt ein Produkt haben mit mehreren Versionen, die gleichzeitig benutzt werden, gleichzeitig im Markt sind oder wo man Rückwärtskompagnen oder alte Versionen noch unterstützen muss, dann muss man halt gucken, dass man sich die entsprechende Branche-Modell überlegt. Was ist dein schlimmstes Git-Setup, mit dem du bis jetzt tun hattest? Was immer schwierig ist, ist, wenn man mehrere Positories haben, die sich relativ eng parallel entwickeln, dann hat man drei, vier Positories, wo man immer die richtige Version von dem richtigen Branche ausgecheckt haben will, haben muss. Und wenn man dann irgendwie was machen will, wie ein Git-Bisect um einen Back zu finden, wird man wahnsinnig, weil das Bisect natürlich auf die einen dieser Positories ist, aber nicht auf den anderen, die auch immer mit parallel ausgecheckt worden sind. Und aber man weiß nie so genau, welche Version jetzt von dem einen Repository zu der gerade ausgecheckten Version zu dem anderen Repository gehört. Das ist so eine Situation, wo man denken, vielleicht wären Submodules auch gar nicht so falsch, aber ja, Submodules haben auch ihre Schmerzen. Idealerweise hat man ein Projekt größer, dass alles in einen Repository passt. Dann funktioniert Git am besten. Ich glaube, die Frage bezieht sich auf die Frage davor. Sollen also Feature Branches auch sofort gelöscht werden oder sollen sie für Backfixes und Erweiterungen bestehen bleiben? Wenn Feature Branches ein Feature Branches ist, wird er nicht mehr benötigt, sobald er gemirkt ist. Wenn man das anderes hat, ich habe das andere ist, wenn ich mehrere Versionen habe, ich habe eine Version 4, oder ich fange an, eine Version 5 zu entwickeln, dann muss ich mein Version 4 Branches am Leben halten und Backfixes Version 4 zu machen. Es kann ja sein, dass ich ein Back-Inversion 4 in einem Codetail fixen muss. Den ist Version 5 gar nicht mehr gibt, weil ich ihn refactored habe. Gibt es Anwendungsfälle, bei denen es Sinn macht, manuell im .git-Verzeichnis manuell etwas zu bearbeiten, zum Beispiel mit Dateikommandos wie MV, RM und so weiter? Wenn man die Konfiguration ändern will, natürlich. Ich würde, glaube ich, die Finger von den Objects und so was lassen. Aber im Prinzip, ja, wenn man weiß, was man tut, könnte man das vermutlich tun, aber ich würde es nicht machen, außer um zu gucken, ob es geht. Virtual File System vergeht. Wie funktioniert das und ab wann bringt es was? Habe ich noch nicht rausgeguckt. Ich denke, das ist ein User-Space-File-System für Linux, wo man dann auf ein Git-Repository zugascht. Es läuft dann ganz normal wie so ein User-Space-Dateisystem. Ich weiß nicht genau, was das Virtual File-System jetzt ist. Okay. Gibt es zum Verwalten von Nicht-Text-Dateien, binary-blubs, Bilder, Videos, Doc-X-PDF, kann das abseits vom Code technisch Sinn machen, beispielsweise als verteiltes Dateisystem? Schwierig. Wenn sich die Dateien nicht ändern vielleicht, aber wenn es verschiedene Versionen von der gleichen binär-Datei gibt, unschön. Git wird bei großen Dateien irgendwann auch langsamer. Das ist nicht der Fall für den Git geschrieben. Git ist für den Linux-Colonel geschrieben und da sind typischerweise wenig Blobs drin. So, sieben Leute fragen insgesamt, mich interessiert, mit welchem Tool du die Shell-Aufzeichnung gemacht hast. Und ausgeführt hast. Also T-Mux sei schon im Hintergrund erkannt worden. Ja, es ist gar keine Shell-Aufzeichnung, das ist ein Script. Wie gesagt, das ist ein Fenster. Ganz normales Shell-Fenster habt ihr ja gesehen. Ich habe hier eben diese Dings wie das Getree aufgerufen. Das andere ist ein Script, das irgendwo anders liegt. Das ist ein Objective-Cummel-Script, das die gesamten Logik und meine gesamten Notizen enthält. Das fängt, wo fängt es an? Genau, hier fängt es an. Das habe ich hier, diese Note, die zeigt mir meine Notizen an, was ich sagen möchte. Es gibt Kommandos, die es dann ausführt an dem richtigen Moment. Wenn ich auf Enter gedrückt habe, hier zum Beispiel, das leere Verzeichnis anlegt und da geht inniert und so weiter. Ein paar Dinge irgendwo ist da weiter unten. Macht da komischere Dinge hier. Genau, hier macht er mit diesem Befehl, macht er hier diesen rechte Teilfenster auf. Genau, das Ganze läuft einfach darüber, dass ich halt in dem Script irgendwo hier, das ist diese Funktion, muss man jetzt nicht verstehen. Sieht hässlich aus, ist einfach auch nur, führt diverse Dinge aus, legt eine Timax-Session an, startet dann, genau, macht in dieser Timax-Session die Titelseite, startet einen genommen Terminal, das mit einem Script genau diese Timax-Session ausführt. Genau, was noch wichtig, was noch eine interessante Funktion ist, ist hier diese Kommando-Funktion, die die eigentlichen Kommandos ausführt. Die zeigt mich hier erstmal an in meinem Fenster mit den Notizen und so was, wird im Set hervorgehoben. Das nächste Befehl, den er ausführt und führt den dann aus. Und hier sehe ich die auch diese Write-Funktion, die zerlegt die Ausgabe, das Kommando, das in einzelne Zeichen und schickt dann jeden einzelnen Buchstaben mit einem zuverliegenden Zeit, Wartezeit dazwischen, damit es aussieht, wie ganz schnell und exakt von Hand getippt, an Timax. Und was auch noch wichtig ist, diese Funktion Retital, die rufe ich hier mal ab und zu mal auf, die ändert den Titel des gerade aktiven, also meines Notizenfensters und das benutze ich dann in OBS, um da automatisch Szenenübergänge zu triggern. Also ich bin jetzt hier in dem Fenster, wo ich die Sachen einfach anzeige. Wenn ich jetzt wieder auf meine Notizenfenster klicke mit einem Klick bin ich wieder in der Gesamtansicht ein Klick, ein Klick. Und das ganze Skript ist halt so geschrieben, dass ich einfach mit Enter, Enter, Enter, Enter durch den ganzen Vortrag durchgehe. Sehr gut, dazu passen die beiden nächsten Fragen, Flash-Kommentare. Findet man die Slides dann auch in einem Git oder kannst du so das Skript publizieren? Es gibt es in einem Git, aber das ist im Moment in meinem Git. Ich werde das nachher vermutlich einfach mal auf meinem GitHub zu tun. GitHub, kommen. Vielleicht noch ein HTTPS dazu, für Leute wie das. Das sollte die URL sein, wounter der das dann nachher zu finden sein sollte. So, just in time release. Nächste Frage. Kann ich einen defekten Git-Baum? Kommits zeigen auf 0000? Einfach abschneiden? Die Situation hatte ich noch nie, ich weiß noch nicht, wie ich in die Situation komme. Dann die nächste. Mit welchen Konzepten können mehrere gleichzeitig lebende Versionen einer Software maintain werden, wenn nicht mit langlebigen Branches wie in GitFlow? Es gibt zwei Arten von Branches. Es gibt langlebige Branches wie ein Release-Branch für Version 4 und ein Branch für Version 5 und die leben so lange, wie Version 4 und Version 5 released werden. Was die langlebigen Branches in GitFlow? Es gibt einen Developer-Branche und ein Master-Branche. Und wenn ich Version 5 release, dann merke ich den Developer-Branche und den Master-Branche und was ich dann mit Version 4 mache, weiß ich nicht, weil Version 4 habe ich auf dem Master-Branche überschrieben. Und ich weiß noch nicht, wenn ich in Version 4 fixen will, der in Version 5 nicht mehr gebraucht wird, der Fix. Dann kann ich den eigentlich auch nicht auf den Master-Branche fixen, weil dann habe ich das nächste Mal, wenn ich Version 5 auf Version auf den Master-Merger habe, dann habe ich einen Merchkonflikt. Weil ich habe den Buck in Version 4 auf den Master-Branche fixet, aber nicht in den Developer-Branche in Version 5 gemirkt, weil da gar nicht reingehört. Das ist das Problem. GitFlow ist nicht, dass es Branches gibt, die lange leben, sondern dass es diese langlebigen Branchen nicht wirklich eine Funktion haben, um die History und die Projektverwaltung einfacher zu machen, sondern nur irgendwie ein bürokratisches Feature ist, damit der aktuelle Release, also die aktuelle offiziell freigebene Version immer der aktuelle Stand vom Master ist. Okay. Wie unterscheiden sich Subtrees von Submodules? Im.git. Und sollte man Subtrees gegenüber Submodules vorziehen? Da musst du jemand fragen, der mit beiden Erfahrungen gemacht hat. Ja, dann an der Stelle, das war die letzte Frage. Normalerweise gehen ja manchmal sogar auch Leute ans Mikrofon und sagen ein Feedback wie Danke. Wenn du hier reinguckst gleich ins Ding, da werden ganz viele positives Feedbackes schon angekommen. An der Stelle einen riesigen Applaus oder was auch immer man sagt für Florian Haas mit ein kurzer Blick ins Git. Und ja, ich habe auch wieder viel gelernt. Tausend Dank und ja, weiter Gitten für den Weltfrieden. Tschüss.