====== Versionsverwaltung mit Git+GitLab ====== In euren Projekten werdet ihr kollaborativ an eurem Programm-Code arbeiten müssen. Dabei wird es vorkommen das zwei oder mehr, gleichzeitig Änderungen vornehmen, oder zu unterschiedlichen Terminen mit wechselnden Gruppenmitgliedern gearbeitet wird. Um diese Art der Zusammenarbeit zu erleichtern wird Git verwendet. Mit Git könnt ihr euren gemeinsamen Programm-Code aktuell halten und zeitgleich bearbeiten ohne dass ihr Gefahr läuft wichtige Arbeit von anderen zu überschreiben oder vorherige (funktionierende) Versionen eures Codes zu verlieren. Dies macht Git zu einem mächtigen Werkzeug welches weit verbreitet Anwendung erfährt. Damit werden oft Projekte verwaltet, die wesentlich komplexer ist als das, was ihr im Robotiklabor macht. Wenn ihr aber schon am Beispiel eines kleineren Projektes dem Umgang mit Git lernt, erleichtert es euch hoffentlich die Arbeit mit Git in der Zukunft. In diesem Artikel haben wir versucht, euch die Git-Basics vorzustellen. Weitere Infos findet ihr online, z.B.: Eine ausführliche Anleitung zur verwendung von Git gibt es hier: [[https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository]] Eine einfache in deutscher Sprache z.B. hier: [[https://rogerdudler.github.io/git-guide/index.de.html]] Hier findet ihr Youtube-Videos zum Thema: https://www.youtube.com/watch?v=Nkz7TnhFvWU&list=PL58qjcU5nk8s-UQHfzeVajBDwkbWqwSc6 =====GitLab===== GitLab ist eine webbasierte Software zur Versionierung und gemeinsamen Bearbeitung von Programmcode mit Git. Kernkomponente ist ein Webportal an dem sich die Benutzer anmelden und eigene Projekte anlegen können. Für jedes Projekt wird automatisch ein Git-Repository angelegt, in dem dann der Programmcode versioniert abgelegt werden kann. Zusätzlich stellt GitLab zu jedem Projekt ein Wiki und einen Issue Tracker bereit über die dann Dokumentationen angeboten bzw. Fehler oder Änderungswünsche am Programmcode erfasst und verwaltet werden können. Für die gemeinsame Arbeit können andere Benutzer zu einem Projekt hinzugefügt werden, wobei differenzierte Berechtigungsstufen möglich sind. Projekte können intern, nur für Projektmitglieder, extern, für alle angemeldeten Benutzer und öffentlich, also weltweit zugänglich sein. Funktionsweise und -umfang entsprechen im Wesentlichen dem bekannten Webdienst „github.com“, jedoch werden alle Daten auf Servern des tubIT Rechenzentrums gespeichert. Der Dienst ist somit ideal für das Verwalten von Programmcode, egal ob allein oder im Team. ====== Installation ====== ===== Software installieren ===== ==== Kommandozeilenversion ==== Die meisten Leute benutzen für die Verwaltung ihrer Git-Repositories ein Kommandozeilentool, für das es im Gegensatz zu den grafischen Tools auch ordentliche Doku gibt. Die aktuelle Git-Version findet ihr hier: * MacOS: [[https://git-scm.com/download/mac|https://git-scm.com/download/mac]] * Windows: [[https://git-scm.com/download/win|https://git-scm.com/download/win]] * Unix: [[https://git-scm.com/download/linux|https://git-scm.com/download/linux]] Wenn alles geklappt hat, könnt ihr euch in der Kommandozeile z.B. die aktuelle Version von der git-Installation ansehen: git --version {{:techniken:git-version.png|}} Evtl. müsst ihr noch euren Namen und E-Mail festlegen: git config --global user.name "d.golovko" git config --global user.email "d.golovko@tu-berlin.de" ==== Grafische Userinterfaces ==== Liebhaber Grafischer Oberflächen können eines der folgenden Programme benutzen - leider ist bei denen manchmal nicht wirklich klar, was eigentlich "unter der Motorhaube" passiert. * MacOS: SourceTree [[https://www.sourcetreeapp.com]] * Linux: * Win: z.B. [[https://www.sourcetreeapp.com/]] ===== Falls Du der/die erste in eurem Team bist: Gruppe und Projekt auf dem TU-Server erstellen ===== ==== Bei GitLab der TU Berlin anmelden ==== * Mit dem Browser auf [[https://gitlab.tubit.tu-berlin.de|https://gitlab.tubit.tu-berlin.de]] gehen. * Mit den eigenen Tubit-Daten anmelden * Kurzes Tutorial zum Einrichten des ersten Repositorys: {{:techniken:tubit-gitlab_schnelleinrichtung.pdf|}} ==== Projektrepository erstellen ==== * Auf Knopf "New Project" drücken * Bei "Project path" einen aussagekräftigen Namen für das Projekt ohne irgendwelche Sonder- oder Leerzeichen eingeben * Den "Create Project" Knopf drücken. * Um andere Teammitglieder hinzuzufügen, drückt auf Settings-->Members (links unten). Die anderen Mitglieder sollen die Rolle "Master" haben, damit sie volle Schreibrechte bekommen. ====== Arbeiten mit Git ====== ===== 0.: Grundkonzepte ===== Git besteht aus vier verschiedenen Orten an denen eure Dateien aufbewahrt werden. Davon sind der workspace, index und local repository auf eurem Computer gespeichert, während das remote repository entfernt auf dem Git-Server liegt. === workspace === Der workspace ist eure Arbeitskopie. Dieser enthält eure Daten mit denen ihr arbeiten könnt. Es kann jede beliebige Datei angelegt werden, nicht nur Code. Zum bearbeiten verwendet ihr die Editoren und IDE's eurer Wahl. === index === Der index dient zum //stagen// eurer Dateien. Hier gebt ihr an welche Dateien mit dem nächsten commit zum local repository hinzugefügt werden. Zu beginn mag dieser zusätzliche Schritt etwas umständlich wirken, für größere Projekte ist er aber sehr sinnvoll ([[http://gitolite.com/uses-of-index.html|Warum?]]). Das Hinzufügen geschieht mit dem Befehlen "add". === local repository === Im local repository wird jeder commit (Hinzufügen) zu eurem Projekt gespeichert, es ermöglicht auch das zurückkehren zu alten Versionen eures Projektes. === remote repository === Sobald ihr euer lokales Repository auf den neusten Stand gebracht habt, könnt ihr mit "push" die neue Version zum "remote repository" schieben. Das "local repository" und "remote repository" enthalten alle bisher gespeicherten Zwischenstände eures Projektes. Der "workspace" hingegen ist nur die aktuellste auf deinem Rechner vorhandene Version. {{ :gitlab-dienst:git_overview.png?800 |}} ===== 1.: Repository vom TU-Server auf den eigenen Rechner übertragen ("clone") ===== Nachdem ihr ein Projekt in GitLab angelegt habt könnt ihr euch davon eine lokale Kopie anlegen. Öffnet euer Terminal/Konsole/Eingabeaufforderung um per [[https://de.wikipedia.org/wiki/Kommandozeile|Kommandozeile]] Befehle einzugeben. Zunächst der Befehl zum Klonen des Repository: git clone Ihr schreibt anstatt die Adresse eures remote Repository, zu finden auf GitLab auf der Seite eures Projekts. Wechselt zum HTTPS-Link: {{ :techniken:gitlab-new-project.png?800 |}} Und für gebt ihr das Verzeichnis an in dem eure working copy liegen soll. Der gesamte Befehl könnte dann wie folgt aussehen: git clone https://gitlab.tubit.tu-berlin.de/d.golovko/MyProject.git /Documents/Arduino/ Nun habt ihr eine Kopie eures Projekts lokal gespeichert und könnt Änderungen am workspace vornehmen. Mit mit dem ''cd''-Befehl könnt ihr in der Kommandozeile zum entsprechenden Ordner wechseln: cd /Documents/Arduino/MyProject/ ===== 2.: Neue Dateien der Kopie auf dem eigenen Rechner hinzufügen ("add", "commit")===== Der add-Befehl sagt Git das du Änderungen an einer Datei mit dem nächsten commit zum lokalen Repository hinzufügen möchtest. Solange der commit noch nicht ausgeführt wurde, wurden die Änderungen auch nicht übernommen. Eine Datei zum Index hinzufügen: git add Es können nur Ordner zum Git-Repository hinzugefügt werden wenn sie Dateien enthalten, das liegt daran dass Git nur Dateien erfasst und nicht Ordner. Dateien welche indexiert wurden können nun zum lokalen Repository hinzufügt werden: git commit -m "Hierher kommt eine Beschreibung was geändert wurde (die Anführungszeichen gehören dazu!)" ==== Beispiel ==== Wir fügen die Datei test.rtf zu unserem lokalen Repository hinzu. Zunächst bewegt ihr euch mit der Kommandozeile in den Ordner eures Projektes. Die test.rtf wurde vorher mit einem Texteditor im Projektordner erstellt. Zum Index hinzufügen: git add test.rtf Im Anschluss committen wir die Datei zu unserem lokalen Repository: git commit -m "Eine hello world Test-Datei!" Nun befindet sich die Datei in eurem lokalen Repository. ===== 3.: Änderungen vom TU Server auf den eigenen Rechner übertragen ("pull") ===== Um die aktuelle Version von eurem remote Repository zu bekommen verwendet ihr den Befehl: git pull Dieser Befehl ist immer vor der Übertragung der eigenen Änderungen in das Repository empfohlen, um eventuelle Änderungen von Anderen einzuarbeiten, bevor ihr euren Code pusht (s. nächten Punkt). ===== 4.: Änderungen auf dem eigenen Rechner in das Repository auf dem TU Server übertragen ("push") ===== Um die Änderungen auch auf euerem remote Repository verfügbar zu machen verwendet ihr folgenden Befehl: git push origin master Bevor am Code gearbeitet wird immer die aktuellste Version "pullen", nach getaner Arbeit den neuen Stand "pushen"! ===== 5.: Versionskonflikte ===== Falls jedoch gleichzeitig am Code gearbeitet wird kann es zu Versionskonflikten kommen, diese müssen manuell gelöst werden bevor ein push/pull durchgeführt werden kann. ==== Beispiel ==== In unserer "test.rtf"-Datei haben wir "Hello Wörld!" geschrieben und zum remote repository hinzugefügt. Nun hat aber jemand drittes schon vor dir deinen Fehler bemerkt und versucht ihn zu korrigieren indem er es zu "Hello Earth!" verbessert. Da deine Intention aber war "Hello World!" zu schreiben änderst du die Datei entsprechend und versuchst sie zu pushen. Du wirst dann eine Fehlermeldung erhalten die folgendermaßen aussieht: User$ git push origin master To git@gitlab.tubit.tu-berlin.de:c.jaedicke/myTestProject.git ! [rejected] master -> master (fetch first) error: failed to push some refs to 'git@gitlab.tubit.tu-berlin.de:c.jaedicke/myTestProject.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. Die Lösung des Problems wird bereits genannt. Es müssen zunächst durch einen pull die Änderungen am remote repository in dein local repository integriert werden. Wenn du nun einen pull durchführst wirst du folgende Meldung erhalten: User$ git pull remote: Counting objects: 5, done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. From gitlab.tubit.tu-berlin.de:c.jaedicke/myTestProject 2e6d627..a29e896 master -> origin/master Auto-merging test.rtf CONFLICT (content): Merge conflict in test.rtf Automatic merge failed; fix conflicts and then commit the result. Git hat versucht automatisch die Änderungen am remote repository mit deinem workspace zu mergen (Zusammenführen). Dabei ist es, wie zu erwarten, zu einem Konflikt gekommen, denn es wurde an gleicher Stelle Änderungen vorgenommen. Ihr könnt euch den Konflikt anzeigen lassen mit: git diff Dies gibt euch folgende Antwort von Git: User$ git diff diff --cc test.rtf index 30c8472,642e89a..0000000 --- a/test.rtf +++ b/test.rtf @@@ -4,4 -4,4 +4,8 @@@ \paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\partightenfactor0 - \f0\fs24 \cf0 Hello World!} -\f0\fs24 \cf0 Hello Earth!} ++<<<<<<< HEAD ++\f0\fs24 \cf0 Hello World!} ++======= ++\f0\fs24 \cf0 Hello Earth!} ++>>>>>>> a29e8967e7015e58cd9af8489bec4d8288b84fe4 Um den Konflikt zu lösen muss also "Hello World!" in eurem local repository zu "Hello Earth!" geändert werden. Sobald ihr die Änderungen vorgenommen habt muss wieder ein add+commit durchgeführt werden. Nun kann ohne Konflikt ein pull durchgeführt werden, womit dein local repository auf dem aktuellen Stand ist. Ausgehend vom aktuellen Stand kann nun "Hello Earth!" zu "Hello World!" geändert werden und zum remote repository gepushed werden. ==== Mit SourceTree ==== [[gitlab-dienst::MacOS-SourceTree]] [[gitlab-dienst::Commit/Push]] ===== Branching ===== In Git gibt es die Möglichkeit sogenannte branches zu erstellen. Ein Branch ist so etwas wie eine Kopie des bisherigen Programms in einer Art unter-repository. Bei Erstellung eines neuen repositorys wird automatisch der "master" Branch erstellt. In diesem legt man die Ordnerstruktur des Projekts fest. Danach kann das gesamte Team alle Änderungen direkt in den master branch pushen. Das Problem hierbei ist, dass es vorkommen kann, dass jemand fehlerhaften code hochlädt oder dass eine änderung in einem anderen Programmteil einen Fehler in unserem hervorruft. Um derartige Konflikte zu vermeiden ergibt es bei größeren Projekten Sinn für verschiedene Teile des Programms verschiedene branches zu erstellen. \\ **Bsp:**\\ Wir entwickeln eine Software, welche Bilder einer Webcam aufnimmt und darauf 2 Algoritmen A und B laufen lässt. Unser Team besteht aus 5 Menschen. Wir beschliessen nun 2 Leute an Algorithmus A, 2 Leute an Algorithmus B und eine Person am Einlesen des Bildes arbeiten zu lassen. Wir erstellen ein Git repository in welchem wir die Struktur unseres Projekts festlegen und erstellen uns 3 Branches: "Algo_A", "Algo_B" und "Einlesen" (Abb. 3, Pfeil 1). Jedes Team hat nun seinen eigenen Branch (Kopie der Projektstruktur) in dem es arbeitet. Nun hat zB. Team-B ihren Algorithmus zum laufen gebracht und gut getestet, in diesem Fall wird der Branch "algo_B" in den "master"-Branch gemerged (Abb. 3, Pfeil 2) (dh. alle Änderungen die auf dem Branch algo_B vorgenommen wurden werden in den master Branch übertragen). Die anderen Teams arbeiten vorläufig weiter auf der Kopie des ursprünglichen Master Branches. Wenn nun Team-A ebenfalls ihren algorithmus vorläufig fertig gestellt und gut getestet! hat, wird der master Branch mit den Veränderungen von Team-B erst in den algo_a Branch gemerged (Abb. 3, Pfeil 3) und danach der algo_a Branch in den Master (Abb. 3, Pfeil 4). Dieser Schritt ist wichtig um zu verhindern, dass beim Mergen von algo_a in master konflikte auftreten und am ende des merges die Programmversion im Master nicht mehr funktioniert. Auf diese Weise hat auch jeder jederzeit Zugriff auf die letzte funktionierende Version eures Programms (also den master Branch). {{ :techniken:git_branch_example.png?500 |Abbildung 3: Branching Beispiel in Git.}} **Befehle:**\\ Einene Branch mit dem Namen algo_A erstellen. Achtung, ihr brancht immer von dem Branch in dem ihr euch momentan befindet ab. git branch algo_A In den Branch algo_A wechseln: git checkout algo_A Den Branch algo_A löschen: git branch -d algo_A Zum mergen müsst ihr zuerst in den Branch wechseln in welchen ihr mergen wollt. danach merged ihr mit folgendem Befehl: git merge algo_A \\ **Bsp:**\\ Wenn ihr also zB. erst git checkout master ausführt und danach git merge algo_A so werden die Änderungen, die in algo_A gemacht wurden, in den master übernommen.