Posted on Leave a comment

Versionsverwaltung Praxisprojekt

resize_to_80

Versionsverwaltung Praxisprojekt

blank

Im letzten Artikel haben wir uns mit Versionsverwaltung und insbesondere mit dem Tool Git beschäftigt. Um besser zu verstehen, wie man mit Git arbeitet, wollen wir den Git-Workflow nun an einem Beispiel demonstrieren. In diesem Tutorial werden dazu ein Repository für ein Projekt (beispielsweise das TicTacToe-Spiel aus unserem C# Tutorial) online bei GitHub eingerichtet und einige Basisoperationen, wie das Erstellen eines Branches und das Pushen bzw. Mergen von Änderungen, durchgeführt.

Setup

Für das Setup benötigen Sie den Projektcode lokal in einem Ordner, sowie ein GitHub-Account und Git selbst.

Git installieren und konfigurieren

Git kann beispielsweise auf https://git-scm.com/downloads für alle Betriebssysteme heruntergeladen werden. Laden Sie den entsprechenden Installer für Ihren Computer herunter und führen Sie ihn aus. Während der Installation können Sie verschiedene Einstellungen vornehmen. So können Sie beispielsweise den Editor, mit dem Git Merge-Konflikte anzeigt, auswählen.  

Wenn Sie einen favorisierten Editor haben, ist es empfehlenswert, diesen zu verwenden. Sowohl Notepad++ als auch Visual Studio Code und Sublime Text sind sehr gut als Editoren geeignet. Wir werden in diesem Tutorial allerdings keinen Editor verwenden, sondern mit der Kommandozeile bzw. direkt im Code arbeiten.

Nach der Auswahl des Editors können Sie entscheiden, ob die Umgebungsvariablen für Git angepasst werden sollen, damit Git beispielsweise über die Kommandozeile aufgerufen werden kann. Das ist für dieses Tutorial zwingend notwendig und generell für die Arbeit mit Git zu empfehlen. Wählen Sie daher die zweite Option.

Nach diesem Wizard kommen noch einige weitere Menüs. Sie können hier jeweils einfach die Default-Einstellungen verwenden. Danach ist die Installation abgeschlossen.

Ob die Installation wie gewünscht geklappt hat, können Sie testen, indem Sie auf einer neuen Kommandozeile beispielsweise

git --version

aufrufen. Hier sollte nun die von Ihnen installierte Version ausgegeben werden.

Als nächstes sollte Git so eingerichtet werden, dass es Ihren Nutzernamen und Ihre E-Mail-Adresse kennt. Einer der größten Vorteile von Versionsverwaltung ist eine Historie, die Änderungen klar den betreffenden Personen zuordnen lässt. Damit das funktioniert, muss das VCS natürlich wissen, wer Sie sind. Git wird wie folgt konfiguriert.

git config --global user.email "you@example.com"
git config --global user.name "Your Name" 

Nun sind wir dem ersten Schritt fertig. Als nächstes benötigen wir einen GitHub-Account und ein remote verfügbares Repository.

GitHub-Account und Repository anlegen

Besuchen Sie für diesen Schritt github.com und klicken Sie auf „Sign Up“ in der rechten oberen Ecke. Wählen Sie einen Nutzernamen, ein Passwort und das kostenlose Abonnement. Nachdem Sie Ihre E-Mail-Adresse bestätigt haben, können Sie direkt damit beginnen, ein Repository für den Code anzulegen. Klicken Sie dazu auf das +-Icon und wählen „New Repository“.

Anschließend werden Sie auf einen Wizard weitergeleitet, auf dem Sie das Repository konfigurieren können. Vergeben Sie dazu einen sinnvollen Namen und gegebenenfalls eine kurze Beschreibung. Sie können außerdem ein Readme hinzufügen und das Repository entweder öffentlich zugänglich machen oder nur privaten Zugriff erlauben.

Damit ist das grundlegende Setup für diese Tutorial abgeschlossen. Im Folgenden werden wir das Repository befüllen und einige Änderung committen. Außerdem werden wir Branches anlegen, diese mergen und einen Konflikt zwischen den Änderungen der einzelnen Branches provozieren und lösen.

Arbeiten mit Git

Schritt 1: Das Repository befüllen

In diesem Beispiel ist der Code, der in einem Repository gehostet werden soll, bereits lokal verfügbar. Das Remote-Repository wurde bereits angelegt, muss nun aber noch befüllt werden. Dazu öffnen Sie eine Kommandozeile und navigieren mit dem Befehl

cd <folder path>

in den Ordner, in dem das Projekt liegt. Mit dem Befehl

git init

initialisieren Sie diesen Ordner als lokales Repository. Dadurch wird ein .git-Ordner erstellt. Wenn Sie diesen Ordner nicht sehen, dann müssen Sie im Dateiexplorer ausgeblendete Elemente einblenden. Dazu klicken Sie im Explorer auf den Reiter „Ansicht“ und haken „Ausgeblendete Elemente“ unter der Option „Ein-/ Ausblenden“ an.

Anschließend sollte der Ordner angezeigt werden. Im .git-Ordner befinden sich diverse Dateien, die für das Nachvollziehen der Versionshistorie, der Änderungen und der Commits notwendig sind. Auf den genauen Inhalt des Ordners werden wir an dieser Stelle allerdings nicht näher eingehen.

Nun können wir das Remote-Repository durch den Befehl

git remote add origin https://github.com/user-example/tac-tac-toe.git

als Origin unseres lokalen Ordners festlegen. Den Link Ihres Repository finden Sie auf GitHub – er setzt sich aus Ihrem Nutzernamen und dem Namen des Repositories zusammen. Über

git status

können Sie den aktuellen Zustand des lokalen Repositories abfragen. Insgesamt sollte die Kommandozeile in etwa so aussehen:

Git sagt Ihnen, dass Sie sich aktuell auf dem Master befinden. Zudem sind bisher keine Dateien und Änderungen committed. Die Dateien im Ordner werden zum aktuellen Zeitpunkt nicht nachverfolgt, können aber durch den Befehl

git add <file name> 

hinzufügt werden.

Durch

git add .

werden alle im Ordner und in Unterordnern befindlichen Dateien hinzugefügt. Allerdings beinhaltet das auch die Binaries, also die kompilierten Dateien, sowie Konfigurations- und Userdateien. Das hat verschiedene Nachteile: Binaries sind relativ groß und im Prinzip unnötig, da sie lokal durch das Kompilieren des Projektes erzeugt werden können. Userspezifische Dateien sollten außerdem nie in einem öffentlich zugänglich Repository landen, da jeder seine Entwicklungsumgebung anders konfiguriert.

Um also zu verhindern, dass diese Dateien committed werden, kann man eine sogenannte .gitignore-Datei anlegen. In einer solchen Datei werden Dateinamen oder Muster festgelegt, die Git nicht nachverfolgen soll. Für .NET-Projekte findet man einige Dateien im Internet – beispielsweise hier. Diese Datei schließt unter anderem Caches, automatisch generierte Dateien oder die Ergebnisse des Builds aus. Eine solche Datei muss sich im Repository befinden und kann auch mit committed werden.

Unter Windows können Sie eine Datei, deren Name mit einem vorgestellten „.“ Beginnt, nicht direkt erzeugen. Legen Sie daher zuerst eine Textdatei gitignore.txt an, in die Sie den Inhalt des Links kopieren. Auf der Kommandozeile führen Sie anschließend den Befehl

ren gitignore.txt .gitignore

aus, der die Datei so umbenennt (renamed), wie Git sie erwartet.

Wenn Sie anschließend

git add . 

ausführen, werden nur die Dateien lokal hinzugefügt, die tatsächlich für das Projekt notwendig sind. Wenn Sie nun den Status abfragen, sollten sie etwas in dieser Richtung sehen:

Committen und pushen Sie die Änderungen mit

git commit -m "Initial commit"
git push -u origin master

Die Zeichenkette, die Sie dem Commit nach dem -m-Parameter übergeben, ist die Message. Hier sollte möglichst gut erklärt werden, was die Änderung oder der Commit beinhaltet. Für den ersten Commit eines Repositories ist „Initial Commit“ meist ausreichend. Anschließend müssen Sie die lokalen Änderungen remote verfügbar machen, also pushen. Damit ist der Code nun auch online vorhanden – das können Sie einfach nachprüfen, in dem Sie das Repository auf GitHub besuchen.

Schritt 2: Eine einfache Änderung committen

Führen Sie nun eine einfache Änderung durch, beispielsweise indem Sie dem Label auf der Oberfläche eine neue Farbe geben. Eine weitere Statusabfrage zeigt jetzt an, dass die entsprechende Datei geändert wurde.

Sie können die Änderung über git add . oder git add TicTacToe/MainWindow.xaml hinzufügen und pushen:

git add TicTacToe/MainWindow.xaml 
git commit -m „Changed button color to blue”
git push -u origin master 


Schritt 3: Einen Branch erstellen und ändern

Insbesondere für große Änderungen, die sich über mehrere Commits erstrecken, ist es sinnvoll mit Branches zu arbeiten. Ein Branch ist eine lokale Kopie, die unabhängig vom Master oder anderen Branches entwickelt wird. Nachdem die komplette Änderung durchgeführt wurde, kann der Branch in den Master oder einen anderen Branch gemerged werden. Stellen wir uns der Einfachheit halber vor, dass die Änderung, die wir durchführen wollen, wieder lediglich eine farbliche Änderung des Labels ist – diesmal allerdings auf einem eigenen Branch. Das benötigen wir zuerst den Befehl:

git checkout -b feature/color-change

Der Checkout-Befehl wechselt zu einem Branch. Durch den Parameter -b wird angegeben, dass ein neuer Branch erstellt werden soll. Das ist nicht möglich, wenn ein gleichnamiger Branch bereits existiert.

Es gibt keine Vorschrift, wie genau der Name eines Branches lauten muss, aber es ist gute Praxis, zuerst zu qualifizieren, welchem Zweck die geplante Änderung dient (z.B. feature, bugfix), und anschließend die Änderung genauer zu beschreiben.

Ändern Sie nun wieder die Farbe des Labels im Code.  Sie können wie gewohnt hinzufügen und pushen, diesmal allerdings nicht auf den Master, sondern auf Ihren Feature-Branch:

git add .
git commit -m “Changed label color to red” 
git push -u origin feature/color-change 

Sie sehen auf GitHub, dass es zwei Branches gibt, und können eine Übersicht über diese einsehen:

Schritt 4: Mergen mit einem Pull-Request

Wie Sie sehen, bietet GitHub Ihnen außerdem an, die Branches miteinander zu vergleichen und einen Pull-Request zu erstellen. Durch einen Pull-Request kann eine Änderung aus einem Feature- oder Bugfix-Branch in den Master übernommen werden. Oft gibt es nur eine begrenzte Anzahl an Personen, die dazu berechtigt sind, einen Pull-Request anzunehmen. Das stellt sicher, dass keine ungewollte Änderung in den Master gerät und der Code von mindestens einer anderen Person in einem sogenannten Review geprüft wurde.

Sie können nun einen Pull-Request öffnen.

Git prüft automatisch, ob die Änderung ohne Probleme übernommen werden kann – sich also die betreffenden Zeilen nicht bereits geändert haben und es daher zum Konflikt kommt. Das ist hier der Fall. Sie können den Pull-Request also anschließend direkt Mergen.

GitHub zeigt Ihnen den Merge in der Übersicht über alle Zweige an:

Schritt 5: Mergen mit der Kommandozeile

Wir haben den Merge nun hauptsächlich mit der Oberfläche von GitHub durchgeführt. Es gibt viele verschiedene Tools, die den Git-Prozess visualisieren und damit vor allem bei großen Projekten vereinfachen. Natürlich kann man den eben beschriebenen Prozess aber auch komplett über die Kommandozeile nur mit Git selbst durchführen. Das funktioniert wie folgt:

Zuerst müssen Sie wieder eine Änderung, an der wir den Vorgang demonstrieren können, durchführen und pushen.

git add .
git commit -m <Commit message>
git push -u origin feature/color-change

Checken Sie nun den Master aus. Danach ist es empfehlenswert, den lokalen Master zuerst mit dem Remote-Master über den Pull-Befehl zu synchronisieren. Die letzte Änderung, die wir eben beispielsweise durch den Pull-Request gemerged haben, liegt auf Ihrem lokalen Master noch nicht vor.

git checkout master
git pull

Hierbei sollten keine Merge-Konflikte auftreten. Anschließend führen Sie den Befehl

git merge feature/color-change 

aus. Dadurch werden die Commits dieses Branches auf den Master angewendet, das heißt ihr lokaler Master verfügt jetzt über die entsprechenden Änderungen. Durch einen weiteren Push mit

git push -u origin master

werden die Änderungen auch auf dem Remote-Repository verfügbar.

Schritt 6: Merge-Konflikt erzeugen und lösen

Im letzten Schritt dieses Tutorials wollen wir einen Merge-Konflikt erzeugen und lösen. Dazu erstellen wir zwei Branches, nachdem wir sichergestellt haben, dass wir uns auf dem aktuellen Master befinden.

git checkout master
git checkout -b bug/provoke-conflict-1
git checkout -b bug/provoke-conflict-2

Wird ein neuer Branch erstellt, ist dieser immer eine exakte Kopie des aktuellen Branches, das heißt wir haben jetzt zwei Kopien des Masters.

Ändern Sie eine Zeile und pushen Sie die Änderung in das entsprechende Repository. Aktuell sollten Sie sich auf dem Branch bug/provoke-conflict-2 befinden:

git add .
git commit -m "Changed color to green"
git push -u origin bug/provoke-conflict-2

Anschließend wechseln Sie den Branch.

git checkout bug/provoke-conflict-1

Nach diesem Schritt sollten Sie sehen, dass die Änderung, die Sie eben vorgenommen haben, nicht mehr vorhanden ist – stattdessen liegt wieder der Zustand vom Master vor. Gehen Sie in dieselbe Zeile, führen Sie eine andere Änderung durch und pushen diese.

git add .
git commit -m "Changed color to blue"
git push -u origin bug/provoke-conflict-1

Nun wollen wir zuerst bug/provoke-conflict-1 und anschließend bug/provoke-conflict-2 mergen. Folgen Sie dazu dem Prozess von vorhin:

git checkout master
(git pull)
git merge bug/provoke-conflict-1
git push -u origin master

Anschließend mergen Sie den zweiten Branch

git merge bug/provoke-conflict-2

Diese Änderung führt wie erwartet zu einem Konflikt, auf den Git uns aufmerksam macht.

Es gibt verschiedene Tools, mit denen Konflikte dargestellt und gelöst werden können, sehen wir aber zuerst in den Code. An der betreffenden Stelle steht nun folgendes:

(Für den Editor noch einmal nicht als Screenshot:

        <Style TargetType="Label">
<<<<<<< HEAD
            <Setter Property="Background" Value="Blue"/>
=======
            <Setter Property="Background" Value="Green"/>
>>>>>>> bug/provoke-conflict-2
            <Setter Property="FontSize" Value="20" />
            <Setter Property="VerticalContentAlignment" Value="Center" />
)

Zwischen <<< HEAD und === steht der Code, der aktuell im Master vorliegt – Sie erinnern sich, dass Head die Bezeichnung für den aktuelle referenzierten Commit ist. Im Abschnitt zwischen === und  >>> <branch-name> steht der Code des Branches, der gemerged werden soll. Sie können den Konflikt einfach beheben, indem Sie den Code, der nicht gewünscht ist, löschen. Soll das Label grün sein, so löschen Sie die Zeile

<Setter Property="Background" Value="Blue"/>

sowie die Indikatoren, wo der Konflikt vorliegt. Das Ergebnis sollte so aussehen:

(Code:
 <Style TargetType="Label"> 
             <Setter Property="Background" Value="Green"/> 
             <Setter Property="FontSize" Value="20" /> 
             <Setter Property="VerticalContentAlignment" Value="Center" />) 

Nun können Sie diese Änderung hinzufügen, committen und pushen:

 Git add . 
 Git commit -m „Resolved merge conflict on color change” 
 Git push -u origin master 

Alle Änderungen sind nach dem Push im Master vorhanden und der Konflikt wurde behoben.

Schritt 7: Löschen Branches

Ein letzter Schritt, den Sie nach dem erfolgreichen Mergen durchführen sollten, ist das Löschen der Branches. Der Befehl, um den Branch remote zu löschen, ist:

git push --delete origin <branch_name>

Danach wird der Branch auch bei GitHub nicht mehr angezeigt. Um den Branch auch lokal zu löschen, benötigen Sie den Befehl:

git branch -d <branch_name>

Zusammenfassung

Der Git-Workflow kann sehr komplex wirken und zu Beginn durchaus abschrecken. Die Vorteile von Versionsverwaltung liegen allerdings klar auf der Hand: Es gibt eine nachvollziehbare Historie und auch die Kollaboration mehrerer Nutzer bzw. das parallele Arbeiten an unterschiedlichen Features wird ermöglicht. Git ist eines der beliebtesten Version Control Systems und wird durch viele weitere Anwendungen, wie GitHub oder GitLab unterstützt. Grundlegend arbeitet Git mit Branches, auf denen unabhängig voneinander gearbeitet werden kann. Die Branches können miteinander verglichen, kopiert und gemerged werden. Die wichtigsten Befehle dazu sind:

Das Befüllen eines Remote-Repositories:

git init
git remote add origin <url> 

(Anlegen einer .gitignore-Datei)

git add .
git commit -m “Initial commit”
git push -u origin master

Das Synchronisieren des lokalen Repository mit dem Remote-Repository:

git pull

Das Hinzufügen, Committen und Pushen von Änderungen:

git add <file name>
git commit -m „Commit message”
git push -u origin <branch-name>

Das Erstellen eines neues Branches

git checkout -b <new-branch-name>

Das Auschecken eines bestehenden Branches:

git checkout <branch-name>

Das Mergen in den Master:

git checkout master
(git pull) 
git merge <new-branch-name> 
git push 

Ähnliche Produkte

Schreibe einen Kommentar