Versionskontrolle

Einführung

Exkurs: Warum Versionskontrolle?

Wenn Sie („Max“) jemals im Team an irgendetwas Digitalem zusammengearbeitet haben, dann wissen Sie, wie es geht:

Es beginnt ganz einfach: Sie haben Ihre Version (Dokument-Entwurf.doc) eines Dokuments und senden sie an einen Partner („Moritz“). Dieser nimmt einige Änderungen vor (Dokument-Entwurf-2.doc), sodass es jetzt zwei Versionen gibt, und sendet die Vorschläge an Sie zurück. Sie integrieren ihre Änderungen in Ihre Version, und jetzt gibt es eine neue, konsolidierte Version (→ Dokument-Entwurf-eingearbeitet).

Dann wird es schlimmer: Während Sie Ihre Version weiter ändern (→ Dokument-Entwurf-3.doc), nimmt Ihr Partner weitere Änderungen an seiner Version vor – und nennt diese auch Dokument-Entwurf-3.doc. Jetzt haben Sie drei Versionen:

  • Dokument-Entwurf-eingearbeitet: Die zusammengeführte Kopie, an der Sie beide gearbeitet haben,

  • Dokument-Entwurf-3.doc: Die Version, die Sie weiter geändert haben

  • Dokument-Entwurf-3.doc, die Ihr Partner geändert hat (gleicher Name, er weiss ja nicht dass Sie zwischenzeitlich weitergebarbeitet haben …).

Gut, man kann ja die Dateien besser benennen, also z. B. mit Autorennamen und Datum:

  • Dokument-Max-2020-04-01.doc

  • Dokument-Moritz-2020-04-01.doc

Sprung in die Zukunft:

Max war fleißig und hat einige Revision vorgenommen und hat nun folgende Dateien:

  • Dokument-Max-2020-04-01.doc

  • Dokument-Max-2020-04-09.doc

  • Dokument-Max-2020-04-15.doc

  • Dokument-Max-2020-04-15-2.doc

  • Dokument-Max-2020-04-21.doc

Jede dieser Änderungen hat er Moritz zur Kenntnisnahme geschickt.

Am 22. April bekommt er dann von Moritz eine überarbeitete Version Dokument-Moritz-2020-04-22.doc. Aber welche Version hat Moritz überarbeitet? Die vom 1., 9., 15. (1 oder 2?) oder vom 21.? Dazu kommt dann von Markus die Version Dokument-Markus-2020-04-17.doc, in welcher er im gesamten Dokument Rechtschreibfehler korrigiert hat.

Möchten Sie nun die Änderungen zusammenführen?

— (Nein!)

Was ist Versionskontrolle?

Ein Versionskontrollsystem (VCS) verfolgt den Verlauf von Änderungen, wenn mehrere Personen gemeinsam an einem Projekt arbeiten. Moderne Versionskontrollsysteme erlauben parallele Änderungen und bringen Mechanismen mit, die ein geordnetes und möglichst einfaches Zusammenführen der Änderungen/Beiträge ermöglichen. Während der Entwicklung können Änderungen mit der Gewissheit vorgenommen werden, dass jede Änderung nachvollziehbar und jede Version jederzeit wiederherstellbar ist. Git ist ein Beispiel für ein solches Versionskontrollsystem.

Für technisch Interessierte: Git ist ein Versionsverwaltungssystem

Das Versionsverwaltungssystem namens Git ermöglicht die gemeinschaftliche Arbeit an dem Quelltext des Werkes sowie den Austausch der Beiträge zwischen den Autoren untereinander und der Nachvollziehbarkeit der Änderungen. Somit ist es auch ein wichtiges Werkzeug um Änderungen zu begutachten und zu diskutieren und damit eine Qualitätssicherung im Team zu bewerkstelligen.

Auch hier gibt es im Wesentlichen 3 wichtige Dinge zum kennenlernen:

  • Die Datenbank (Repository)

  • Beiträge (Commits)

  • Zweige

Git basiert im Grunde auf aufeinander aufbauenden Einträgen, d. h. die jeweiligen Änderungen werden in Git eingetragen und Git speichert dabei immer die Änderungen im Bezug auf die *vorige Version. Somit bilden sich Ketten von immer auf den Vorgänger verweisenden Einträgen (Beiträgen, Commits) mit Änderungen.

Diese Ketten von Beiträgen können sich aufzweigen, wenn z. B. zwei Autoren unterschiedliche Änderungen ausgehend von einer gemeinsamen Basis vornehmen. Um diese klassiche Situation abzubilden gibt es Zweige. Sie ermöglichen das parallele und gleichzeitige Bearbeiten des Werkes durch unterschiedliche Personen unabhängig voneinander. Diese Zweige können selbstverständlich auch wieder zusammengeführt werden (merge). Im Idealfall werden dann die unterschiedlichen Änderungen der jeweiligen Autoren miteinander kombiniert und es entsteht wieder eine einheitliche Fassungmit den Beiträgen der beteiligten Autoren. Natürlich kanne s beim Zusammenführen aber auch zu Konflikten kommen, wenn z. B. zwei Autoren die gleiche Stelle im Werk bearbeitet haben. Dann obliegt es einem Beauftragtem die Konflikte sinnvoll zu lösen und eine bereinigte Fassung zu erstellen.

Ein Repository (Verzeichnis) ist im Prinzip eine Datenbank in welcher die jeweiligen Einträge verzeichnet sind.

Das Repository ist die Datenbank

Die Versionierungsdatenbank eines mit Git versionierten Projektes wird als Git-Verzeichnis, Git-Repository oder kurz einfach Repository bzw. Repo bezeichnet.

Für den Endanwender besteht ein Repo aus zwei Dingen:

  1. Arbeitsordner: Hier befinden sich die Projektdateien zu einem von Benutzer bestimmten Vewrsionstand. Änderungen an Dateien werden in diesem Projektverzeichnis auf die übliche Weise vorgenommen.

  2. .git-Ordner bzw. die eigentliche Git-Datenbank: Die Datenbank, in welcher die Versionsinformationen gespeichtert werden, befinden sich immer im .git-Unterordner des Arbeitsordners. Mit diesem Order hat der Benutzer eigentlich nichts zu tun, er darf jedoch natürlich nciht gelöscht werden.

Es kann mehrere dieser Datenbanken für das gleiche Projekt geben, welche untereinander ihre Daten austauschen und sich somit gegenseitig auf dem aktuellen Stand halten. Im Prinzip kann jeder Autor auf seinem Computer eine solche Datenbank haben (auch mehrere) und mit anderen, entfernten Datenbanken, Beiträge austauschen.

Unser Projekt hat eine zentrale Datenbank namens origin eingerichtet, dorthin schicken die Autoren ihre Beiträge, bzw. laden die Beiträge von anderen Autoren herunter. Ein Repository besteht (normalerweise) nicht nur aus der Datenbank, sondern auch aus einem Arbeitsverzeichnis. Dieses stellt den Stand einer Fassung zu einem defnierten Zeitpunkt dar (bzw. zum Zeitpunkt eines definierten Beitrags). Git kann angewiesen werden, das Arbeitsverzeichnis gemäß eines beliebigen Punkts in der Versionsgeschichte der Datenbank einzustellen (auschecken, Checkout). Anschließend können die Dateien und Dokumente im Arbeitsverzeichnis bearbeitet werden. Git erkennt sodann alle Änderungen an den Dateien im vergleich zur urprünglich eingestellten Version. Diese Änderungen können dann als Beiträge in die Datenbank eingetragen werden (committed). Das Arbeitsverzeichnis dient somit dem Bearbeiten von Einträgen und damit dem Erstellen neuer Einträge in die Datenbank.

Commits sind Ein- bzw. Beiträge)

Doch wie werden nun die Versionsinformationen gespeichert bzw. aufgezeichnet? Hierfür vergleicht Git den Stand der Dateien im Projektordner mit dem zuletzt gespeichterten Stand in der Datenbank und zeigt geänderte Inhalte an. Der Benutzer kann nun Änderungen in Einträge (Commits) zusammenfassen, mit einer Beschreibung versehen und in die Datenbank eintragen lassen (committen).

Jeder Commit besteht aus einem Beschreibungstext, einer Prüfzahl und den Änderungen gegenüber dem vorigen Commit. Das bedeutet, jeder Commit speichert nur die Änderungen und nicht den kompletten Projektordner, und baut daher immer auf dem vorhergehendem Commit auf. es ergibt sich somit ein Baum von Einträgen, vom allerersten Eintrag bis zum letzten Commit.

Zweige (Branches) ermöglichen paralleles Arbeiten

Der eigentlich Clou sind die Zweige. Stellen wir uns ein kleines Repo mit 3 Commits (A, B und C) vor:

A → B → C

Weiters haben wir 2 Autoren (X, Y), welche im Versionstand C unabhängig voneinander Änderungen vornehmen (X1, X2 bzw. Y1, Y2, Y3), dies würde in etwa so aussehen:

A ─ B ─ C ─ X1 ─ X2
        │
        └── Y1 ─ Y2 ─ Y3

Somit haben wir nun 2 konkurrierende Versionlinien: X2 und Y3. Wir sehen dass beide Versionslinien auf C aufbauen und sich dann – verzweigen. Somit werden diese Versionslinien Zweige genannt. Natürlich möchten wir diese Zweige miteinander vereinigen, dies wir ein Redakteur erledigen, nachdem er die Änderungen geprüft hat – Doch davor haben wir noch eine andere Herausforderung, wir müssen diese Zweige bennenen. Somit bekommen die Commits der Zweige ein Namensschild mit einem Namen, in unserem Fall benennen wir die Zweige nach den Autoren (Autor-X und Autor-Y). Ein Commit eines Zweiges kann dabei auch mehrere Namensschilder haben. Dann gibt es noch einen besonderen Zweig namens master. In diesem Zweig verwaltet des Redakteur die von ihm aufgenommenen Beiträge der anderen Autoren:

Am Beginn gibt es nur den master-Zweig:

        ┌────────┐
        │ master │
        ├────────┘
        │
A ─ B ─ C

Dann werden für jeden Autor je ein Zweig erstellt, Commit C hat somit 3 Namensschilder:

        ┌────────┐
        │ master │
        ├────────┘
        ├─────────┐
        │ Autor-X │
        ├─────────┘
        ├─────────┐
        │ Autor-Y │
        ├─────────┘
        │
A ─ B ─ C

Schlußendlich bearbeiten die Autoren Ihre Zweige:

        ┌────────┐
        │ master │
        ├────────┘
        │        ┌─────────┐
        │        │ Autor-X │
        │        ├─────────┘
        │        │
A ─ B ─ C ─ X1 ─ X2
        │
        └── Y1 ─ Y2 ─ Y3
                      │
                      ├─────────┐
                      │ Autor-Y │
                      └─────────┘

Es gilt:

  • Jedes Commit baut auf dem Vorangegengenem auf und bildet somit einen Zweig.

  • Jeder Zweig hat mindestens ein Namenschild.

Zweige zusammenführen („Mergen“)

Um Zweige wieder zu einer gemeinsamen Basis zusammenzuführen wird ein sogenannter Merge durchgeführt. Dabei werden, im Idealfall, alle Änderungen zusammengeführt und es entsteht eine neue Version, welche alle Änderungen der Zweige beinhaltet.

Schließlich vereinigt der Redakteur die beiden Zweige, daraus entsteht dann das Commit D, welches die 5 Autorenbeiträge und eventuell noch vom Redaktuer vorgenommene Änderungen enthält:

                 ┌─────────┐    ┌────────┐
                 │ Autor-X │    │ master │
                 ├─────────┘    ├────────┘
                 │              │
A ─ B ─ C ─ X1 ─ X2 ─────────── D
        │                       │
        └── Y1 ─ Y2 ─ Y3 ───────┘
                      │
                      ├─────────┐
                      │ Autor-Y │
                      └─────────┘

Werden jedoch an der gleichen Stelle unterschiedliche Änderungen durchgeführt kommt es zu einem Konflikt, welcher händisch gelöst werden muss. D. h. ein Redakteur entscheidet, welche Änderungen übernommen, welche kombiniert oder gar verworfen werden müssen.

Genaueres findet sich im Abschnitt Beiräge zusammenführen: „Mergen“ und Diskutieren.