\documentclass[german,a4paper]{report} \usepackage[german]{babel} \usepackage{graphicx} % Benoetigt, um Grafiken einzubinden \usepackage{longtable} \usepackage{float} \usepackage{german} \usepackage{ae} \usepackage{alltt} \usepackage{amssymb} \usepackage[utf8]{inputenc} % Umlaute und dt. Zeichen Kodieren % ae.sty verwenden! \usepackage[T1]{fontenc} % ec* Schriftarten verwenden \usepackage{times} % Times-Schriftart (pdf) \usepackage{calc} \usepackage{lmodern} \setcounter{secnumdepth}{4} \setcounter{tocdepth}{4} \begin{document} \title{GIT - Eine Einf"uhrung} \author{Hauke Z"uhl } \maketitle \tableofcontents \chapter{Was ist GIT?} GIT ist ein sogenanntes ``Versionskontrollsystem'' von Dateien in Projekten, das heisst, man kann die Ver"anderungen, die an Dateien im Laufe der Zeit durchgef"uhrt werden, nachvollziehen. Dabei werden nicht nur Zeitstempel gespeichert, sondern auch welcher Benutzer die "Anderungen durchgef"uhrt hat. Dies ist dann ein Versionsstand eines Projektes. GIT speichert also nur Ver"anderungen. Gut, bei sog. ``Bin"ardateien'', also zum Beispiel LibreOffice-Dokumenten, geht das nicht, aber das ist ein anderes Thema. Immerhin kann man aber auch LO-Dokumente speichern, wie man an und f"ur sich alles, was eine Datei ist, in GIT gespeichert werden kann. Was GIT besonders macht, ist die Tatsache, dass es dezentral ist. Das bedeutet, dass jeder, der ein Projekt aus GIT herunterl"adt (man sagt auch ``auschecken'' dazu) den kompletten Versionsverlauf auf seinem Rechner als lokale Kopie verliegen hat. Im ersten Moment mag das ein Nachteil sein, denn man will ja nicht die Dateiversionen haben, die Max Mustermann vor 10 Jahren in GIT hochgeladen hat, aber keine Sorge, GIT arbeitet recht platzsparend. Der Vorteil dieser Methode ist, dass man dadurch mindestens eine Sicherheitskopie auf einem Rechner hat. Arbeiten mehrere Leute an einem Projekt, kommen so diverse Sicherheitskopien zustande. Diese Einf"uhrung soll mit einfachen Worten und Beispielen an GIT heranf"uhren. Ich konzentriere mich dabei auf die Konsole, denn nur auf der Konsole kann man meiner Meinung nach die Arbeitsweise von GIT verinnerlichen. Grafische Clients kann man sp"ater immer noch einsetzen! \chapter{Fachbegriffe} Ohne Fachbegriffe, die "uberwiegend in Englisch sind, kommt man leider bei der Benutzung und der Erkl"arung von GIT nicht aus, deshalb hier die grundlegenden Fachbegriffe: ``Repository'': Man kann es als ``Projekt'' bezeichnen. Im Repository (verk"urzt auch nur ``Repo'' genannt) findet man die Verzeichnnisse und Dateien des Projektes wieder. ``Einchecken'': Neue Dateien, die zum Repo hinzugef"ugt werden, werden ``eingecheckt'', aber wenn auch "Anderungen an Dateien dem Repo hinzugef"ugt werden, spricht man von ``einchecken''. Auch ``commit'' genannt. ``Auschecken'' / ``Klonen'': Unter ``Auschecken'' versteht man umgangssprachlich(!) das Herunterladen eines GIT-Repositories. Korrekterweise bedeutet ``auschecken'', dass sog. ``Zweige'' auscheckt. Der Begriff des Zweiges wird sp"ater genauer erl"autert. An dieser Stelle sei nur sovierl dazu gesagt, dass man mit Zweigen Projekte weiter unterteilen kann. Wenn man ein Repository klont, dann bezieht sich das auf das GIT-Kommando, um ein Repository von einem GIT-Server herunterzuladen. ``Branch'': Ein ``Branch'' ist ein Zweig eines Projektes. Dazu sp"ater mehr. ``Merge'': Das Zusammenf"uhren zweier Zweige wird als ``merge'' bezeichnet. \chapter{Erste Schritte mit GIT} Um mit GIT zu arbeiten, braucht man erst einmal das Programm.\\ Unter Linux kann man sich GIT mit Hilfe des distributionseigenen Installationsprogrammes installieren. Unter Debian oder Ubuntu zum Beispiel per \textit{aptitude install git}, bzw. per \textit{apt-get install git}. RedHat oder CentOS liefert GIT per \textit{yum install git} auf die Platte. Und unter MacOS d"urfte \textit{brew install git} zum Erfolg f"uhren. Mangels MAC kann ich das nicht pr"ufen.\\ Ein Tip: Vergiss erst einmal grafische Clients, das ist Bl"odsinn, denn damit lernt man nicht mit GIT umzugehen und zu verstehen! Denk auch nicht an irgendwelche Server oder gar an GitHub! Wir fangen einfach an und das ist lokal bei dir auf deinem Computer.\\ \\ Los geht's!\\ \\ "Offne eine Konsole deiner Wahl. Bash, zsh, ksh, egal. Irgendwas, wo du mit Hilfe deiner Tastatur deinem Rechner Kommandos senden kannst\footnote{Manche Shells ben"otigen den Befehl \textit{rehash}, wenn neue Software hinzugekommen ist}.\\ Es empfiehlt sich, f"ur Git-Repos ein eigenes Verzeichnis anzulegen. Zum Beispiel \textit{git} oder \textit{projekte}, oder, oder, oder.\\ Ich selbst verwende \textit{git}.\\ \\ Also: \textit{mkdir git}, dann \textit{cd git}.\\ \\ Jetzt legen wir ein Verzeichnis f"ur unser erstes Projekt an. Lass uns das Projekt ``Welt'' nennen: \textit{mkdir Welt}. Per \textit{cd Welt} wechseln wir in das neue Verzeichnis.\\ Jetzt wird es ernst, wir erzeugen unser erstes GIT-Repository: \textit{git init}. Yes!\\ Wenn man nun per \textit{ls -oha} nachguckt, sollte das Verzeichnis so aussehen: \begin{verbatim} insgesamt 12K drwxrwxr-x 3 hauke 4,0K Mar 22 13:03 . drwxrwxr-x 18 hauke 4,0K Mar 22 13:03 .. drwxrwxr-x 7 hauke 4,0K Mar 22 13:03 .git \end{verbatim} Das Verzeichnis .git ist ein verstecktes Verzeichnis, dort stehen Informationen f"ur GIT in diversen Dateien.\\ \\ Wir k"onnen nun loslegen, Dateien anzulegen. Fangen wir erst einmal einfach an und legen eine Datei LIESMICH an. Ich verwende an dieser Stelle den Editor vi, wenn du aber einen anderen Editor verwenden magst, nutze diesen; es geht nur darum, Text in eine einfache Datei zu schreiben (Officeprogramme scheiden also aus!).\\ Der Inhalt der Datei soll ganz einfach sein: \begin{verbatim} Projekt Welt \end{verbatim} Abspeichern nicht vergessen!\\ Jetzt sieht unser Verzeichnis (\textit{ls -oha}) so aus: \begin{verbatim} insgesamt 16K drwxrwxr-x 3 hauke 4,0K Mar 22 13:20 . drwxrwxr-x 18 hauke 4,0K Mar 22 13:03 .. drwxrwxr-x 7 hauke 4,0K Mar 22 13:06 .git -rw-rw-r-- 1 hauke 14 Mar 22 13:20 LIESMICH \end{verbatim} Jetzt fragen wir mal GIT, was es davon h"alt, dass in dem Repository eine Datei neu angelegt wurde. Dazu geben wir \textit{git status} ein. Das Ergebnis sollte in etwa so aussehen: \begin{verbatim} Auf Branch master Initialer Commit Unversionierte Dateien: (benutzen Sie "git add ...", um die Aenderungen zum Commit vorzumerken) LIESMICH nichts zum Commit vorgemerkt, aber es gibt unversionierte Dateien (benutzen Sie "git add" zum Versionieren) \end{verbatim} GIT gibt uns einige Informationen:\\ Wir sind auf dem Branch (Zweig) ``master''. Dazu - wie gesagt - sp"ater mehr.\\ Unser erstes Einchecken (commit) steht bevor; es ist der initiale Commit.\\ Git hat festgestellt, dass es Dateien gibt, "uber die es nichts weiss. Unversionierte Dateien also. Die Datei(en) wird/werden aufgez"ahlt und es gibt - zumindest bei mir - einen hilfreichen Tip, was man machen sollte (\textit{git add ...}).\\ Also, ran an den Speck und die Datei per \textit{git add LIESMICH} zum Einchecken vormerken. Ein \textit{git status} sollte nun folgendes ergeben: \begin{verbatim} Auf Branch master Initialer Commit zum Commit vorgemerkte Aenderungen: (benutzen Sie "git rm --cached ..." zum Entfernen aus der Staging-Area) new file: LIESMICH \end{verbatim} Prima, das sieht schon anders, besser aus!\\ Jetzt kann ich nat"urlich weitere Dateien anlegen und per \textit{git add ...} vormerken, oder ich kann diese eine Datei in das Repository "ubernehmen, den ``commit'' also durchf"uhren. \textit{git commit LIESMICH} f"uhrt den Commit auf die Datei LIESMICH aus. Es sollte sich ein Editorfenster "offnen, denn GIT bietet dir jetzt an, in einem Kommentar kurz zu erl"autern, was du gemacht hast. Dieser Text taucht dann in der Historie des Projektes sp"ater auf. Beispiel: ``LIESMICH angelegt''. Kurz und knackig sollte der Kommentar sein, aber auch so geschrieben, dass du sp"ater noch weisst, was du seinerzeit gemacht hast.\\ GIT gibt dir auch hier wieder eine R"uckmeldung: \begin{verbatim} [master (Basis-Commit) 19a30b3] LIESMICH angelegt 1 file changed, 2 insertions(+) create mode 100644 LIESMICH \end{verbatim} In der ersten Zeile wird der Branch angezigt, der Commit-Hash (ist auch an dieser Stelle nicht weiter wichtig, ich erw"ahne es aber dennoch, der "Ubersicht halber) und dein Kommentar. In der zweite Zeile wird die Anzahl der ver"anderten Dateien, sowie hinzugekommene Zeilen (insertions) und (hier noch nicht sichtbar) die Anzahl der entfernten Zeilen. In der dritten Zeile stehen dann noch Information bzgl. des Modus der Datei (create), die Dateirechte und der Dateiname.\\ Super, damit ist die erste Version des Projektes ``Welt'' im GIT-Repository angekommen. Am Beispiel einer weiteren Datei zeige ich dir nun auch erste ``Vereinfachungen'', denn mal angenommen, du hast auf einem Satz mehrere Dutzend Dateien neu in deinem Projekt, dann wirst du nicht per \textit{git add datei1}, \textit{git add datei2}, usw. jede einzelne Datei vormerken. Die Sache ginge ja dann so sp"ater beim commit weiter. Also, eher wird der BER fertig, als dass du mit deinem Projekt weiterkommst!\\ Als Beispiel gibt es jetzt das Shellskript ``welt.sh'': \begin{verbatim} #!/bin/sh echo "Hallo Welt" \end{verbatim} Jetzt kommt das ``add'' mal etwas anders: \textit{git add .} Du hast den Punkt hinter ``add'' bemerkt? Gut! Damit hast du jetzt alle neuen Dateien in diesem Verzeichnis (Unterverzeichnisse, sofern vorhanden mit eingeschlossen) zum einchecken vorgemerkt. \textit{git status} wird dir das anzeigen.\\ Jetzt das tats"achliche Einchecken in das Repository und da verrate ich dir den n"achsten Trick: Den Kommentar direkt angeben, ohne dass ein Editor erst "offnet: \textit{git commit -a -m 'Projekt erweitert, neue Dateien hinzugefuegt'}.\\ Das erkl"are ich mal genauer:\\ -a bedeutet, dass alle (-a = all) Dateien, die vorher per \textit{git add .}, bzw. per \textit{git add dateiname} vorgemerkt wurden nun in das Repo "ubernommen werden sollen. Du siehst: Man kann auch erst einmal ``sammeln''.\\ -m bedeutet, dass nun ein Kommentar kommt (-m = message). Der Text sollte in Anf"uhrungszeichen stehen, sonst macht die Shell "Arger.\\ Und damit hast du bereits die ersten Schritte gemacht.\\ Hier noch mal zusammengefasst die Schritte, die im Wesentlichen immer wieder wiederholt werden, nachdem man das Projektverzeichnis angelegt und GIT initialisiert hat: \begin{itemize} \item Datei anlegen \item git add \item git commit \item Datei anlegen \item git add \item git commit \item ... \end{itemize} Oder aber man macht: \begin{itemize} \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item git add . \item git commit -a \item Datei anlegen \item ... \end{itemize} \chapter{GIT konfigurieren} Oftmals sehen die Logs von GIT ziemlich d"amllich aus, was meistens daran liegt, dass die Benutzer ihr GIT nicht ordentlich konfiguriert haben. F"ur eine vern"unftige Konfiguration bedarf es des korrekten Namens und der Mailadresse.\\ Dies geschieht per \textit{git config ...}. Beispiel: \textit{git config user.name 'Max Mustermann'}, um den Namen festzulegen und \textit{git config user.email 'mmuster@exampel.kom} f"ur die Mailadresse.\\ Damit sind Name und Mailadresse f"ur dieses eine Projekt festgelegt. Damit das f"ur alle GIT-Repositories gilt, f"ugt man die Option \textit{--global} hinzu, also \textit{git config --global user.name 'Max Mustermann'} und \textit{git config --global user.email 'mmuster@exampel.kom}.\\ Man kann nat"urlich noch eine Menge mehr konfigurieren, aber hier geht es um die Grundlagen. \chapter{Zweige} Bisher haben wir uns geradlinig auf dem Zeitstrahl bewegt, aber wenn man im Team an einem gro"sen Projekt arbeitet, dann erledigt jeder, bzw. jede entsprechende Unteraufgaben. Um solche Unteraufgaben zu organisieren, nutzt man in Versionskontrollsystemen sog. ``Zweige''. Leider kann man das nicht direkt mit einem Baum vergleichen, denn zwar gibt es sowohl beim Baum als auch in GIT einen Hauptzweig/Stamm und (mehr oder weniger) viele Zweige, bei einem Baum werden die Zweige aber nicht wieder zum Stamm zur"uckgef"uhrt. Bei Versionskontrollsystemen jedoch werden Zweige fr"uher oder sp"ater wieder in den Hauptzweig "uberf"uhrt.\\ \\ Am Anfang befindet man sich immer auf dem Hauptzweig, dem sog. ``Masterbranch''. Du hast das bereits in diversen Meldungen von GIT gesehen.\\ Das sieht dann so aus: \begin{verbatim} master A--B--C--D--E--F \end{verbatim} Um nun einen neuen Zweig zu erzeugen, gibt man \textit{git checkout -b }\footnote{-b bedeutet, dass der Zweig erzeugt und sofort ausgecheckt wird, d.h. man befindet sich sofort auf diesem Zweig} ein. Angenommen, ich will als Unteraufgabe zum Projekt ``Welt'' ein ``Hallo'' programmieren, dann erzeuge ich den Zweig ``Hallo'' per \textit{git checkout -b hallo}. Wir sind nun im Zweig ``hallo''. Um das zu "uberpr"ufen gibt es \textit{git branch}: \begin{verbatim} * hallo master \end{verbatim} Der kleine Stern in der ersten Spalte zeigt den Zweig an, in dem wir uns aktuell befinden.\\ Will ich auf den Zwei ``master'' zur"uckwechslen, gebe ich \textit{git checkout master} ein. Wichtig: Hier wird kein ``-b'' verwendet, da es den Zweig ``master'' bereits gibt!\\ \\ Bist du also im Zweig ``hallo'', gehst du wieder wie immer vor: Datei(en) anlegen, vormerken, einchecken.\\ Das sieht dann so aus: \begin{verbatim} master A--B--C--D--E--F \ hallo G--H--I--J--K \end{verbatim} Das sollte soweit klar sein, aber irgendwann kommt der Punkt, an dem du den Zweig ``hallo'' wieder in den Zweig ``master'' zur"uckf"uhren willst/musst.\\ Dazu wechselst du erst einmal in den Zweig ``master'' zur"uck. Nun sagst du GIT, dass du den Zweig ``hallo'' in den Masterbranch ``mergen'' willst: \textit{git merge hallo}. Es "offnet sich wieder ein Editor, indem (meistens) bereits eine Information vorgegeben ist: \begin{verbatim} Merge branch 'hallo' \end{verbatim} Hinweis: Es muss(!) ein Kommentar angegeben werden, und sei es nur der vorgegebene Standardkommentar!\\ Wenn alles gutgegangen ist, sind nun alle Dateien des ``hallo''-Zweiges im Masterbranch.\\ Das sieht dann so aus: \begin{verbatim} master A--B--C--D--E--F---L \ / hallo G--H--I--J--K \end{verbatim} In der Softwareentwicklung wird generell mit mehreren Zweigen gearbeitet, um zu verhindern, dass ungetestete und in der Entwicklung befindliche Dateien Einzug in das fertige Projekt nehmen. Es gibt daher einmal nat"urlich den Zweig ``master'', in dem das fertige Produkt liegt, dann den Zweig ``develop'', in dem entwickelt wird und von dem weitere Zweige mit weiteren Unteraufgaben abgeleitet werden. Wenn in ``develop'' alles ordentllich l"auft, dann wird dieser in den Masterbranch gemergt und das Produkt wird ver"offentlicht. Dadurch ergibt sich mit der Zeit eine durchaus recht breite Struktur, die aber dem Team hilft, dass man sich nicht in die Quere kommt und letztendlich auch den "Uberblick beh"alt. \chapter{Ein erstes Fazit} Du solltest nun in der Lage sein, lokal auf deinem Rechner GIT-Repositories anzulegen, Dateien hinzuzuf"ugen und diese auch in das Repo zu laden. Ausserdem solltest du dir auch "uber Zweige klar sein und diese verwenden k"onnen, denn mit Hilfe von Zweigen wird eine koordinierte Teamarbeit in einem Projekt erst m"oglich, aber auch wenn du alleine an einem Projekt arbeitest, solltest du dir angew"ohnen, f"ur jede Teilaufgabe einen eigenen Zweig anzulegen. \chapter{Dateien l"oschen und umbenennen} Dateien anlegen kannst du jetzt schon fl"ussig, was aber ist, wenn du eine versionierte Datei nicht mehr brauchst, oder wenn du dich beim Namen vertippt hast?\\ Keine Panik, auch das geht mit GIT.\\ Um eine Datei zu l"oschen, die im GIT-Repository ist, verwendest du den Removebefehl: \textit{git rm }. Danach f"uhrst du ein \textit{git commit -m 'Kommentar'} aus und die Datei ist von jetzt an nicht mehr vorhanden.\\ Umbenennen geht ebenfalls sehr einfach: \textit{git mv }. Auch danach wieder ein \textit{git commit -m 'Kommentar'} und die Datei hat von nun an einen neuen Namen.\\ Moment mal, was soll das heissen ``von nun an''?\\ Ganz einfach: Da man mit GIT auch "altere Versionen des Repositories auschecken kann, hat in fr"uheren Versionen die Datei nat"urlich noch ihren alten Namen, bzw. ist im Repo noch vorhanden! Wie man fr"uhere Versionen auscheckt, erkl"are ich aber sehr viel sp"ater. \chapter{GIT-Server} \section{Einstieg} So, jetzt kommt der sog. ``heisse Scheiss''! GIT in Verwendung mit einem GIT-Server!\\ Bisher hast du deine Repositories lokal auf deinem Rechner gehabt und das ist am Anfang auch gut so, aber stelle dir vor, deine Festplatte zerlegt sich und dein echt tolles Projekt wird damit geschreddert. Dann n"utzt dir auch GIT nichts mehr. Gut, du h"attest regelm"a"sig eine Sicherung deines Repos auf DVD, CD, USB-Stick oder wo auch immer anlegen k"onnenen, aber mal ehrlich, das ist nicht Sinn und Zweck von GIT. Ausserdem funktioniert so die Teamarbeit an einem Projekt nicht. Also ben"otigt man externen Speicherplatz. Auf einem GIT-Server.\\ Als Plattform kannst du "offentliche Server nehmen. GitHub sei hier erw"ahnt.\\ Du kannst dir einen GIT-Server auch auf einem kleinen Raspberry Pi in deinem Heimnetzwerk einrichten. Oder du mietest dir einen eigenen Rootserver und packst dort deinen GIT-Server drauf. Alles kein Problem! \section{GitHub} GitHub ist eine - f"ur nichtkommerzielle Projekte - kostenlose Plattform, die GIT anbietet. Man kann nat"urlich Geld zahlen, dann bekommt man etwas mehr an ``Features'' auf der Plattform, aber f"ur den Hausgebrauch reicht die kostenlose Variante.\\ Du meldest dich bei GitHub an und hinterlegst dort deinen "offentlichen SSH-Schl"ussel\footnote{Wie man SSH-Schl"ussel erstellt, m"ogest du bitte im WWW selbst"andig suchen}.\\ Du kannst dort deine Projekte komplett verwalten, die Seite ist sehr "ubersichtlich aufgebaut und es gibt auch eine Hilfefunktion. \section{GIT-Server im Heimnetzwerk} F"ur einen GIT-Server im eigenen Heimnetzwerk eignet sich ein Raspberry Pi wunderbar. Der sollte nat"urlich "uber LAN (und nicht via WLAN) mit dem Netz verbunden sein, damit die Daten"ubertragung m"oglichst hastig erfolgen kann. Eine FritzBox zum Beispiel hat Gigabitinterfaces, da kann man schon mal gut was "uber die Leitung jagen (wobei des Raspberries Interface langsamer ist).\\ Als GIT-Serversoftware empfehle ich an dieser Stelle gitea\footnote{https://gitea.io/}.\\ Wenn du dich damit besch"aftigen willst, solltest du aber "uber gute Linuxkenntnisse verf"ugen.\\ Mit gitea hast du eine Weboberfl"ache, "ahnlich wie bei GitHub, unter der du deine Projekte recht einfach verwalten kannst. Du hast auch die M"oglichkeit, private Projekte dort anzulegen und mit Hilfe der Benutzerverwaltung kannst du auch Einfluss darauf nehmen, was deine Teammitgleider alles so d"urfen. \subsection{gitea} Gitea ist ein kleines, aber feines Projekt, das ein Webfrontend f"ur einen git-Server bereitstellt. Es ist in der Programmiersprache go geschrieben und ben"otigt nur minimale Resourcen. \subsubsection{Vorbereiten der Datenbank} Bevor du dir gitea herunterl"adst und installierst, solltest du das Datenbanksystem ausw"ahlen, das gitea sp"ater benutzen soll. Du kannst zwischen MariaDB/MySQL und PostgreSQL w"ahlen. Gut, es gibt noch SQLite, MSSQL oder TiDB nutzen, aber die ersten beiden will man nicht wirklich und TiDB ist wohl noch zu speziell. Achte darauf, dass MySQL/MariaDB auch tats"achlich auf dem Netzwerkinterface horcht, das du bei der Installation angibst!\\ \paragraph{PostgreSQL} Am einfachsten loggst du dich per ``sudo su - postgres'' als Benutzer postgres in deiner Shell auf deinem GIT-Server ein, dann erzeugst du per ``createuser -P -d gitea'' einen Benutzer f"ur die Datenbank ``gitea''.\\ Im n"achsten Schritt loggst du dich auf der Shell per ``psql -h localhost template1 gitea'' in das Datenbanksystem ein. Hier reicht nun ein ``CREATE DATABASE gitea;'', um die Datenbank f"ur gitea anzulegen. \paragraph{MariaDB/MySQL} Du loggst dich mit dem administrativen Benutzer in MariaDB/MySQL, den du bei der Installation eingerichtet hast, in das Datenbanksystem ein. Das ist oft der Datenbankbenutzer ``root'' (nicht zu verwechseln mit dem Systembenutzer ``root''). Also ``mysql -p -u root''. Nun erfolgt ein ``GRANT ALL PRIVILEGES ON gitea.* to 'gitea'@'localhost' IDENTIFIED BY 'geheimes passwort';''. Dann loggst du dich aus, loggst dich per ``mysql -p -u gitea'' wieder ein und f"uhrst ein ``CREATE DATABASE gitea CHARACTER SET utf8mb4;'' aus, um die Datenbank f"ur gitea anzulegen. \\ \textbf{Hinweis:} Sollte bei Benutzung von MariaDB w"ahrend der Installation im Webbrowser die Fehlermeldung ``Datenbankeinstellungen sind nicht korrekt: Error 1071: Specified key was too long; max key length is 767 bytes'', dann folgende Befehle in der MariaDB-Kommandozeile ausf"uhren: \begin{verbatim} set global innodb_large_prefix=on; set global innodb_file_format=Barracuda; \end{verbatim} \subsubsection{Installation} Bevor du dir gleich die Software runterl"adst, lege bitte einen Benutzer ``git'' auf deinem Server an, sofern der Benutzer noch nicht existiert.\\ Von https://gitea.io/ l"adt man sich die passende Version f"ur seinen Server runter und entpackt diese. Das entstandene Verzeichnis wird dann in das Benutzerverzeichnis des Benutzers ``git'' verschoben und diesem zu eigen gemacht (chown).\\ Um gitea beim Systemstart zu starten, benötigst du die passenden Skripte.\\ Nat"urlich solltest du die Dateien entsprechend f"ur dein System anpassen, sonst stimmen die Pfade unter Umst"anden nicht. \paragraph{systemd} In ``/etc/systemd/system/'' legst du (z.B. mit vim) die Datei ``gitea.service'' mit folgendem Inhalt an: \begin{verbatim} [Unit] Description=Gitea After=syslog.target After=network.target After=mariadb.service mysqld.service postgresql.service After=memcached.service redis.service [Service] # Modify these two values and uncomment them if you have # repos with lots of files and get an HTTP error 500 because # of that ### #LimitMEMLOCK=infinity #LimitNOFILE=65535 Type=simple User=git Group=git WorkingDirectory=/home/git/gitea ExecStart=/home/git/gitea/gitea web Restart=always Environment=USER=git HOME=/home/git [Install] WantedBy=multi-user.target \end{verbatim} Dann folgen ein ``systemctl enable gitea'', danach ein ``systemctl start gitea''. \paragraph{SystemV init} Es gibt ja immer noch Puristen, die das alte init-System von SystemV verwenden. Dafür benötigt man die Datei ``/etc/init.d/gitea'', die Executrechte benötigt. \begin{verbatim} #! /bin/sh ### BEGIN INIT INFO # Provides: gitea # Required-Start: $syslog $network # Required-Stop: $syslog # Should-Start: mysql postgresql # Should-Stop: mysql postgresql # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: A self-hosted Git service written in Go. # Description: A self-hosted Git service written in Go. ### END INIT INFO # Author: Danny Boisvert # Do NOT "set -e" # PATH should only include /usr/* if it runs after the mountnfs.sh script PATH=/sbin:/usr/sbin:/bin:/usr/bin DESC="Gitea" NAME=gitea SERVICEVERBOSE=yes PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME WORKINGDIR=/home/git/gitea DAEMON=$WORKINGDIR/$NAME DAEMON_ARGS="web" USER=git # Read configuration variable file if it is present [ -r /etc/default/$NAME ] && . /etc/default/$NAME # Exit if the package is not installed [ -x "$DAEMON" ] || exit 0 # Load the VERBOSE setting and other rcS variables . /lib/init/vars.sh # Define LSB log_* functions. # Depend on lsb-base (>= 3.2-14) to ensure that this file is present # and status_of_proc is working. . /lib/lsb/init-functions # # Function that starts the daemon/service # do_start() { # Return # 0 if daemon has been started # 1 if daemon was already running # 2 if daemon could not be started sh -c "USER=$USER start-stop-daemon --start --quiet \\ --pidfile $PIDFILE --make-pidfile \\ --test --chdir $WORKINGDIR --chuid $USER \\ --exec $DAEMON -- $DAEMON_ARGS > /dev/null \\ || return 1" sh -c "USER=$USER start-stop-daemon --start --quiet \\ --pidfile $PIDFILE --make-pidfile \\ --background --chdir $WORKINGDIR --chuid $USER \\ --exec $DAEMON -- $DAEMON_ARGS \\ || return 2" } # # Function that stops the daemon/service # do_stop() { # Return # 0 if daemon has been stopped # 1 if daemon was already stopped # 2 if daemon could not be stopped # other if a failure occurred start-stop-daemon --stop --quiet --retry=TERM/1/KILL/5 \\ --pidfile $PIDFILE --name $NAME RETVAL="$?" [ "$RETVAL" = 2 ] && return 2 start-stop-daemon --stop --quiet --oknodo \\ --retry=0/1/KILL/5 --exec $DAEMON [ "$?" = 2 ] && return 2 # Many daemons don't delete their pidfiles when they exit. rm -f $PIDFILE return "$RETVAL" } case "$1" in start) [ "$SERVICEVERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$SERVICEVERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$SERVICEVERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$SERVICEVERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$SERVICEVERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$SERVICEVERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $? ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) # Failed to stop log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac \end{verbatim} Um das Skript zu aktivieren, führt man ``update-rc.d gitea defaults'' aus und startet gitea per ``/etc/init.d/gitea start''. \subsubsection{Konfigurationsdatei} Um sp"ater noch ein wenig Feintuning vorzunehmen, kann man im Verzeichnis ``custom/conf'' die Datei ``app.ini'' "andern, die bei der Installation automatisch angelegt wird.\\ Ein Beispiel f"ur eine app.ini: \begin{verbatim} APP_NAME = Gitea RUN_USER = git RUN_MODE = prod [repository] ROOT = /home/git/repositories [database] DB_TYPE = postgres HOST = 127.0.0.1:5432 NAME = gitea USER = gitea PASSWD = GEHEIM SSL_MODE = disable PATH = data/gitea.db [server] DOMAIN = git.hauke-zuehl.de HTTP_PORT = 3000 ROOT_URL = https://git.hauke-zuehl.de/ DISABLE_SSH = false SSH_PORT = 22 START_SSH_SERVER = false OFFLINE_MODE = false [mailer] ENABLED = false [service] REGISTER_EMAIL_CONFIRM = true ENABLE_NOTIFY_MAIL = true DISABLE_REGISTRATION = true ENABLE_CAPTCHA = true REQUIRE_SIGNIN_VIEW = true [picture] DISABLE_GRAVATAR = false ENABLE_FEDERATED_AVATAR = true [session] PROVIDER = file [log] MODE = file LEVEL = Info ROOT_PATH = /home/git/gitea/log [security] INSTALL_LOCK = true \end{verbatim} Bitte daran denken, dass diese Datei als Eigent"umer den Benutzer ``git'' haben muss! Wenn du aber bei der Installation oben alles korrekt eingetragen hast, sollte es keine Probleme geben.\\ In diesem Beispiel habe ich "ubrigens PostgreSQL als Datenbanksystem verwendet, du kannst aber gerne MariaDB oder MySQL verwenden. \subsubsection{Der erste Start} Du startest gitea zun"achst "uber die Kommandozeil per ``./gitea web'' und gibst dann in deinem Webbrowser die URL ``http://localhost:3000'' ein.\\ Du wirst nun durch die Konfiguration der Datenbank und von gitea gef"uhrt. Bei der Domain solltest du den Server- oder einen ordentlichen Domainnamen eingeben. Hast du also zum Beispiel einen kleinen RaspberryPi zu Hause, auf dem gitea laufen soll, und dieser heisst ``pi.deinzuhause.net'' dann gibst du eben diesen Namen bei der Domain und der Application URL ein.\\ Den Datenbankbenutzer f"ur gitea und die entsprechende Datenbank solltest du nun auch anlegen, sonst kracht es bei der Einrichtung der Tabellen.\\ Hast du soweit alles eingetragen, kannst du dich anmelden und deine Projekte mit gitea verwalten.\\ Der erste Benutzer, der sich registriert bei gitea, wird "ubrigens als Administrator angelegt, also Obacht! Von nun kannst du gitea in aller Ruhe erforschen und eigene Repositores anlegen, Organisationen und Teams erzeugen, usw.! \subsection{Gogs} Gitea ist ein sog. ``fork'' von gogs, d.h, jemand fand die Entwicklung von gogs nicht so toll, hat das Projekt geklont und fortgeführt.\\ \\ Gogs dagegen ist zur Zeit ein wenig eingeschlafen, sodass hier nicht weiter darauf eingegangen wird. Wer aber gogs verwenden möge, kann dies nach der Installationsanleitung von gitea durchführen. \section{GIT from scratch} Ich habe keine bessere "Uberschrift gefunden, aber wenn du keine Lust auf GitHub oder gogs oder wie auch immer das coole (Web-)Frontend heisst, dann reicht auch...git.\\ Dann legst du als Benutzer ``root'' einen Benutzer ``git'' an. Hast du das erledigt, wirst du zum Benutzer ``git'' und legst ein Verzeichnis ``.ssh'' im Benutzerverzeichnis von ``git'' an. In das Verzeichnis ``.ssh'' kommen in die Datei ``authorized\_keys'' die "offentlichen SSH-Schl"ussel der Benutzer, die git benutzen d"urfen.\\ Warum wird das mit den Schl"usseln gemacht?\\ Ganz einfach: Ansonsten m"usstest du jedem Teammitglied das Passwort des Benutzers ``git'' verraten und das willst du wirklich nicht!\\ Also: \begin{verbatim} sudo adduser git su git mkdir .ssh chmod 700 .ssh \end{verbatim} Jetzt kannst du - als Benutzer ``git'' anfangen, Repositories anzulegen: \begin{verbatim} mkdir Welt.git cd Welt.git git --bare init \end{verbatim} Du siehst hier wieder den ``init''-Befehl, diesmal jedoch mit der Option ``--bare''. Diese Option sorgt daf"ur, dass kein sog. ``Arbeitsverzeichnis'' angelegt wird, d.h. es fehlt das .git-Verzeichnis, daf"ur sind dort andere Dateien und Verzeichnisse erzeugt werden, die zur Verwaltung eines GIT-Repositories n"otig sind (guck einfach mal per \textit{ls -oha} nach). Okay, du hast keine Lust? So sieht das Verzeichnis dann aus: \begin{verbatim} drwxrwxr-x 7 git 4,0K Mar 22 18:11 . drwxrwxr-x 19 git 4,0K Mar 22 18:11 .. drwxrwxr-x 2 git 4,0K Mar 22 18:11 branches -rw-rw-r-- 1 git 66 Mar 22 18:11 config -rw-rw-r-- 1 git 73 Mar 22 18:11 description -rw-rw-r-- 1 git 23 Mar 22 18:11 HEAD drwxrwxr-x 2 git 4,0K Mar 22 18:11 hooks drwxrwxr-x 2 git 4,0K Mar 22 18:11 info drwxrwxr-x 4 git 4,0K Mar 22 18:11 objects drwxrwxr-x 4 git 4,0K Mar 22 18:11 refs \end{verbatim} Falls du es dir noch nicht gedacht hast: Du kannst das lokal auf deinem Rechner machen! Damit wird dein Rechner zum GIT-Server! Und was auf deinem Rechner funktioniert, klappt auch auf einem Raspberry Pi, der in deinem Keller oder auf dem Dachboden rumliegt oder auf dem dicken Server, der irgendwo in einem Rechenzentrum in Deutschland steht. \chapter{Projekt ``Welt'' auf den Server bringen} Nachdem du also einen GIT-Server irgendwie ans Laufen gebracht hast, oder du dich bei GitHub angemeldet hast, deinen "offentlichen SSH-Schl"ussel auf den Server geladen hast, soll das ``Welt''-Projekt nun auf den entfernten Server gebracht werden. Ob dein GIT-Server nun auf deinem Raspberry oder auf deinem lokalen Server l"auft, der Unterschied liegt in der Benennung des Rechners. Ich erkl"are dir die folgenden Schritte unter der Annahme, dass du den GIT-Server auf deinem Rechner installiert hast. Die Transferleistung hin zum Raspberry Pi oder einem Rootserver "uberlasse ich dir.\\ Um dein Projekt auf den Server hochzuladen, musst du dich im Repoverzeichnis befinden, wo wir uns am Anfang dieses Papiers aufgehalten haben. Also \textit{cd ~/git/Welt}. Zu Beginn wollen wir den Masterbranch hochladen, also zur Sicherheit ein \textit{git checkout master} machen.\\ Achtung, jetzt geht es los:\\ \begin{verbatim} git remote add origin git@localhost:Welt.git git push origin master \end{verbatim} Damit hast du deinen Masterbranch auf den Masterbranch des GIT-Servers geladen, wobei der Server daf"ur sorgt, dass deine "Anderungen mit dem bereits bestehenden Branch ``gemergt'' werden. Bei einem krachneuen Branch ist das nat"urlich nicht n"otig, aber sp"ater einmal, wenn du ein ganzes Team an deinem Projekt mitwerkeln l"asst, dann ist das wichtig.\\ \\ Also, mal die Erkl"arung:\\ Mit der ersten Zeile hast du deinem Repository gesagt, dass unter dem Namen ``origin'' ein entferntes (remote) Repo existiert. Und zwar beim Benutzer ``git'' auf dem Rechner ``localhost'' im Repository ``Welt.git''.\\ Mit der zweite Zeile hast du dann den aktuellen Branch hochgeladen (push) und zwar zu dem entfernten Repository ``origin'' in dessen Branch ``master''.\\ Die Bezeichnung ``origin'' f"ur ein entferntes Repository ist Standard. Du h"attest es auch ``Pizza'' oder ``Koeln'' nennen k"onnen, Namen sind Schall und Rauch. Dein ``push'' w"are dann \textit{git push Pizza master}, bzw. \textit{git push Koeln master}. Es ist nur ein Name f"ur die Verbindungsdaten zum Server (git@localhost:Welt.git).\\ \\ Jetzt hat sich deine Arbeitsweise etwas erweitert: \begin{itemize} \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item git add . \item git commit -a \item Datei anlegen \item Datei anlegen \item Datei anlegen \item Datei anlegen \item git add . \item git commit -a \item git push origin master \item ... \end{itemize} (Gesetzt den Fall, du bist im Masterbranch) \chapter{Arbeiten im Team} Du hast bisher alleine mit GIT gearbeitet, hast aber das Projekt, bzw. die Projekte mit einem GIT-Server verwaltet.\\ Dann ist der Schritt hin zur Teamarbeit f"ur dich recht leicht, denn du weisst ja, dass du mit \textit{git push ...} Ver"anderungen hochl"adst.\\ Da aber deine Kolleginnen und Kollegen auch fleissig waren, solltest du deren "Anderungen mindestestens einmal am Tag herunterladen und deine Arbeitskopie damit aktuell halten.\\ Das gilt besonders f"ur die Zweige, die regelm"a"sigen "Anderungen unterworfen sind. Dies sind meistens \begin{itemize} \item master \item develop \item testing \end{itemize} Um deine Arbeitskopie zu aktualisieren, wechselst du in den entsprechenden Zweig (zum Beispiel ``develop'') und f"uhrst dort \textit{git pull} aus.\\ Damit werden die "Anderungen vom Server heruntergeladen und in deinen Zweig eingepflegt.\\ \\ Ein Beispiel aus dem realen Leben:\\ Wenn man in einer Software einen Fehler findet, wird erst einmal ein Bericht geschrieben und dieser Bericht bekommt eine sog. ``Ticketnummer''. Zum Beispiel 4711.\\ Du sollst nun Ticket 4711 bearbeiten. Es wird immer (meistens) aus dem Zweig ``develop'' ein neuer Zweig erstellt. Das heisst, du wechselst per \textit{git checkout develop} in den Entwicklungszweig und f"uhrst hier \textit{git pull} aus. Damit ist dein Zweig aktuell und du kannst mit \textit{git checkout -b bug-4711} den Zweig erzeugen, um den Fehler zu beheben.\\ Bist du irgendwann fertig damit (und hast immer wieder \textit{git pull origin bug-4711} gemacht, kannst du deinen Zweig wieder in den Developbranch ``zur"uckmergen'', bzw ``zur"uckmergen'' lassen. ``Lassen'' deshalb, weil in der Regel ein anderer Programmierer erst deinen Code testet und f"ur den Merge freigibt, aber das ist abh"angig von den Regeln der jeweiligen IT-Abteilung. \chapter{"Altere Version auschecken} Es wird selten gebraucht, aber manchmal denkt man: ``Verdammt, an dem Punkt da vor ein paar Tagen/Wochen/Monaten, da lief das System besser!''\\ Besonders, wenn man mal ``was ausprobieren'' will, ist es ganz nett, wenn man eine ``uralte'' Version des Projektes auschecken kann.\\ Geht recht einfach!\\ Na gut, man muss ein wenig arbeiten, denn zuerst muss man den richtigen Commit wiederfinden. Um das Log eines GIT-Projektes anzuzeigen, verwendet man \textit{git log}.\\ Das sieht zum Beispiel so aus: \begin{verbatim} commit 43632ef9d9ed259a33d030d2e71549bba752e97b Author: Max Mustermann Date: Tue Mar 27 18:10:22 2018 +0200 blah => blubb commit 90845d50545e2bb7069622dbe0c645241f25e9d2 Merge: 19a30b3 201d71f Author: Max Mustermann Date: Thu Mar 22 15:08:02 2018 +0100 Merge branch 'hallo' commit 201d71f352307d88b98aa4d1c5d5892b468948e7 Author: Max Mustermann Date: Thu Mar 22 15:07:54 2018 +0100 Blah commit 19a30b330ab250a6d3ab3f0a9ecf1c6d9b2d9fd5 Author: Hauke Zühl Date: Thu Mar 22 13:40:59 2018 +0100 LIESMICH angelegt \end{verbatim} Zur Info: Ich bin zur Zeit im Masterbranch.\\ \begin{verbatim} -rw-rw-r-- 1 hauke 0 Mar 22 15:08 blubb -rw-rw-r-- 1 hauke 14 Mar 22 13:20 LIESMICH \end{verbatim} Jetzt will ich die Version vom 22.3, 13:40:59 auschecken. Das ist der Commit\\ 19a30b330ab250a6d3ab3f0a9ecf1c6d9b2d9fd5. Dann mal los: \textit{git checkout\\ 19a30b330ab250a6d3ab3f0a9ecf1c6d9b2d9fd5}\\ Das ist verdammt lang, oder?\\ An dieser Stelle ein Hinweis: Es reichen die eersten 7 Zeichen des Hashes des Commits, also ein \textit{git checkout 19a30b3} h"atte es auch getan!\\ Wie dem auch sein, das Verzeichnis sieht jetzt so aus: \begin{verbatim} -rw-rw-r-- 1 hauke 14 Mar 22 13:20 LIESMICH \end{verbatim} Es fehlt also eine Datei (``blubb'')! Logisch, die gab es zu diesem Zeitpunkt noch nicht.\\ Aber Vorsicht: Es muss nicht sein, dass du dich dann noch in dem gew"unschten Zweig befindest; du kannst an jeder Stelle jede "Anderung auschecken und von da an weitermachen!\\ Tip: Das solltest du ein wenig "uben und noch ein Tip: An dieser Stelle sind grafische GIT-Clients sehr n"utzlich, um dir eine gute "Ubersicht "uber dein Projekt zu geben.\\ Wenn du aber tapfer bist und auf der Konsole bleiben willst, bitte sch"on: \textit{git log --graph} zaubert ein sch"ones Log auf den Bildschirm. Und wenn du die Kurzform der Commits haben willst, dann bringt dich \textit{git log --abbrev-commit --graph} ans Ziel. \chapter{Ignorieren von Dateien} Ich starte mal mit einem Beispiel, um zu zeigen, was das Problem ist:\\ Wir gehen jetzt davon aus, dass wir ein C++-Projekt compilieren, d.h. aus dem Quellcode ein Programm ``basteln'' wollen. Wenn du dich damit nicht auskennst, ist das nicht schlimm, es geht um Dateien und nicht um irgendwelche freakigen Sachen.\\ Zuerst der Verzeichnisbaum eines ``frischen'' Repos: \begin{alltt} hauke@apollo:~/git/Lara$ tree . . \textbar\textendash\textendash CMakeLists.txt \textbar\textendash\textendash Doxyfile \textbar\textendash\textendash README.md \textbar\textendash\textendash sql \textbar\ \ \textbar\textendash\textendash address.sql \textbar\ \ \(\llcorner\)\textendash\textendash customer.sql \(\llcorner\)\textendash\textendash src \textbar\textendash\textendash addons \textbar\ \ \textbar\textendash\textendash Address \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressAddon.cc \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressAddon.h \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressMainWindow.cc \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressMainWindow.h \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash CMakeLists.txt \textbar\ \ \(\llcorner\)\textendash\textendash CMakeLists.txt \textbar\textendash\textendash CMakeLists.txt \textbar\textendash\textendash core \textbar\ \ \textbar\textendash\textendash Addon.h \textbar\ \ \textbar\textendash\textendash Base.cc \textbar\ \ \textbar\textendash\textendash Base.h \textbar\ \ \textbar\textendash\textendash CMakeLists.txt \textbar\ \ \textbar\textendash\textendash Config.cc \textbar\ \ \textbar\textendash\textendash Config.h \textbar\ \ \textbar\textendash\textendash Convert.cc \textbar\ \ \textbar\textendash\textendash Convert.h \textbar\ \ \textbar\textendash\textendash Database.cc \textbar\ \ \textbar\textendash\textendash Database.h \textbar\ \ \textbar\textendash\textendash Files.cc \textbar\ \ \textbar\textendash\textendash Files.h \textbar\ \ \textbar\textendash\textendash IDatabase.cc \textbar\ \ \textbar\textendash\textendash IDatabase.h \textbar\ \ \textbar\textendash\textendash Lara.cc \textbar\ \ \textbar\textendash\textendash Lara.h \textbar\ \ \textbar\textendash\textendash Loader.cc \textbar\ \ \textbar\textendash\textendash Loader.h \textbar\ \ \textbar\textendash\textendash Map.cc \textbar\ \ \textbar\textendash\textendash Map.h \textbar\ \ \textbar\textendash\textendash models \textbar\ \ \textbar\ \ \textbar\textendash\textendash Address.h \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash Customer.h \textbar\ \ \(\llcorner\)\textendash\textendash UserData.h \textbar\textendash\textendash GUI \textbar\ \ \textbar\textendash\textendash CMakeLists.txt \textbar\ \ \textbar\textendash\textendash MainWindow.cc \textbar\ \ \(\llcorner\)\textendash\textendash MainWindow.h \(\llcorner\)\textendash\textendash main.cc 7 directories, 39 files \end{alltt} Ein ``git status'' s"ahe so aus: \begin{verbatim} hauke@apollo:~/git/Lara$ git status Auf Branch develop Ihr Branch ist auf dem selben Stand wie 'origin/develop'. nichts zu committen, Arbeitsverzeichnis unverändert hauke@apollo:~/git/Lara$ \end{verbatim} Um dieses Projekt zu compilieren, muss ich folgende Schritte durchf"uhren: \begin{itemize} \item mkdir build \item cd build \item cmake ../ \item make \end{itemize} Das heisst, ich erzeuge ein neues Verzeichnis namens ``build'', wechsele in das dortige Verzeichnis, f"uhre ein wenig Magie aus und am Ende f"allt das fertige Programm im Unterverzeichnis ``src'' raus.\\ Wenn ich das alles gemacht habe, sieht der Verzeichnisbaum so aus: \begin{alltt} . \textbar\textendash\textendash build \textbar\ \ \textbar\textendash\textendash CMakeCache.txt \textbar\ \ \textbar\textendash\textendash CMakeFiles \textbar\ \ \textbar\ \ \textbar\textendash\textendash 2.8.12.2 \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeCCompiler.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeCXXCompiler.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDetermineCompilerABI\_C.bin \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDetermineCompilerABI\_CXX.bin \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeSystem.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CompilerIdC \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash a.out \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash CMakeCCompilerId.c \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash CompilerIdCXX \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash a.out \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash CMakeCXXCompilerId.cpp \textbar\ \ \textbar\ \ \textbar\textendash\textendash cmake.check\_cache \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDirectoryInformation.cmake \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeOutput.log \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeTmp \textbar\ \ \textbar\ \ \textbar\textendash\textendash Makefile2 \textbar\ \ \textbar\ \ \textbar\textendash\textendash Makefile.cmake \textbar\ \ \textbar\ \ \textbar\textendash\textendash progress.marks \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash TargetDirectories.txt \textbar\ \ \textbar\textendash\textendash cmake\_install.cmake \textbar\ \ \textbar\textendash\textendash Makefile \textbar\ \ \(\llcorner\)\textendash\textendash src \textbar\ \ \textbar\textendash\textendash addons \textbar\ \ \textbar\ \ \textbar\textendash\textendash Address \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash address.so \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeFiles \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash address.dir \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressAddon.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressMainWindow.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash build.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash cmake_clean.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CXX.includecache \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash DependInfo.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash depend.internal \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash depend.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash flags.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash link.txt \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash progress.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDirectoryInformation.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash progress.marks \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash cmake\_install.cmake \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash Makefile \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeFiles \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDirectoryInformation.cmake \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash progress.marks \textbar\ \ \textbar\ \ \textbar\textendash\textendash cmake\_install.cmake \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash Makefile \textbar\ \ \textbar\textendash\textendash CMakeFiles \textbar\ \ \textbar\ \ \textbar\textendash\textendash CMakeDirectoryInformation.cmake \textbar\ \ \textbar\ \ \textbar\textendash\textendash lara.dir \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash build.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash cmake\_clean.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash core \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Base.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Config.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Convert.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Database.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Files.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash IDatabase.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Lara.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash Loader.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash Map.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash CXX.includecache \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash DependInfo.cmake \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash depend.internal \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash depend.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash flags.make \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash GUI \textbar\ \ \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash MainWindow.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash link.txt \textbar\ \ \textbar\ \ \textbar\ \ \textbar\textendash\textendash main.cc.o \textbar\ \ \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash progress.make \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash progress.marks \textbar\ \ \textbar\textendash\textendash cmake\_install.cmake \textbar\ \ \textbar\textendash\textendash lara \textbar\ \ \(\llcorner\)\textendash\textendash Makefile \textbar\textendash\textendash CMakeLists.txt \textbar\textendash\textendash Doxyfile \textbar\textendash\textendash README.md \textbar\textendash\textendash sql \textbar\ \ \textbar\textendash\textendash address.sql \textbar\ \ \(\llcorner\)\textendash\textendash customer.sql \(\llcorner\)\textendash\textendash src \textbar\textendash\textendash addons \textbar\ \ \textbar\textendash\textendash Address \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressAddon.cc \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressAddon.h \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressMainWindow.cc \textbar\ \ \textbar\ \ \textbar\textendash\textendash AddressMainWindow.h \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash CMakeLists.txt \textbar\ \ \(\llcorner\)\textendash\textendash CMakeLists.txt \textbar\textendash\textendash CMakeLists.txt \textbar\textendash\textendash core \textbar\ \ \textbar\textendash\textendash Addon.h \textbar\ \ \textbar\textendash\textendash Base.cc \textbar\ \ \textbar\textendash\textendash Base.h \textbar\ \ \textbar\textendash\textendash CMakeLists.txt \textbar\ \ \textbar\textendash\textendash Config.cc \textbar\ \ \textbar\textendash\textendash Config.h \textbar\ \ \textbar\textendash\textendash Convert.cc \textbar\ \ \textbar\textendash\textendash Convert.h \textbar\ \ \textbar\textendash\textendash Database.cc \textbar\ \ \textbar\textendash\textendash Database.h \textbar\ \ \textbar\textendash\textendash Files.cc \textbar\ \ \textbar\textendash\textendash Files.h \textbar\ \ \textbar\textendash\textendash IDatabase.cc \textbar\ \ \textbar\textendash\textendash IDatabase.h \textbar\ \ \textbar\textendash\textendash Lara.cc \textbar\ \ \textbar\textendash\textendash Lara.h \textbar\ \ \textbar\textendash\textendash Loader.cc \textbar\ \ \textbar\textendash\textendash Loader.h \textbar\ \ \textbar\textendash\textendash Map.cc \textbar\ \ \textbar\textendash\textendash Map.h \textbar\ \ \textbar\textendash\textendash models \textbar\ \ \textbar\ \ \textbar\textendash\textendash Address.h \textbar\ \ \textbar\ \ \(\llcorner\)\textendash\textendash Customer.h \textbar\ \ \(\llcorner\)\textendash\textendash UserData.h \textbar\textendash\textendash GUI \textbar\ \ \textbar\textendash\textendash CMakeLists.txt \textbar\ \ \textbar\textendash\textendash MainWindow.cc \textbar\ \ \(\llcorner\)\textendash\textendash MainWindow.h \(\llcorner\)\textendash\textendash main.cc 23 directories, 103 files \end{alltt} Du siehst den Unterschied!\\ Git w"urde jetzt also alle ``neuen'' Dateien unterhalb von build finden und nat"urlich daraus schliessen, dass man diese auch ins Repo aufnehmen will: \begin{verbatim} Auf Branch develop Ihr Branch ist auf dem selben Stand wie 'origin/develop'. Unversionierte Dateien: (benutzen Sie "git add ...", um die Änderungen zum Commit vorzumerken) build/ keine Änderungen zum Commit vorgemerkt (benutzen Sie "git add" und/oder "git commit -a") \end{verbatim} Nein! Will man nicht!\\ Man h"atte jetzt den ganzen unn"utzen ``M"ull'' f"ur eine bestimmte Plattform und das ist nicht Sinn eines Quellcode Repositories.\\ Ergo m"ussen wir daf"ur sorgen, dass git nicht nervt, wenn wir auf unserem Rechner das Programm bauen wollen. Dazu soll git also das gesamte Verzeichnis ``build'', mit allen Dateien und Unterverzeichnissen ignorieren.\\ Dazu erstellen wir im Hauptverzeichnis unseres Repos die Datei ``.gitignore'' (man beachte den Punkt vor dem Dateinamen). Die sieht dann so aus: \begin{verbatim} build/ \end{verbatim} Wenn wir jetzt ``git status'' machen, sieht das so aus: \begin{verbatim} Auf Branch develop Ihr Branch ist auf dem selben Stand wie 'origin/develop'. nichts zu committen, Arbeitsverzeichnis unverändert \end{verbatim} Cool! Genau das, was wir haben wollen! Das Verzeichnis ``build'' wird von git ignoriert.\\ \\ Ein weiteres Beispiel:\\ Unter MacOS wird gerne die Datei ``.DS\_Store'' angelegt. Da diese Datei f"ur Nutzer anderer Systeme uninteressant, ja sogar nervig ist, sollte man also, wenn Maccies mit im Team sind, in die .gitignore die Datei aufnehmen. Dann sieht also die .gitignore f"ur unser C++-Projekt so aus: \begin{verbatim} build/ .DS_Store \end{verbatim} Je nach Projekt, Programmiersprache, verwendetem Editor, oder verwendeter IDE gibt es noch weitere Dateien, die f"ur andere uninteressant oder unwichtig sind. Diese k"onnen dann nach und nach in die .gitignore aufgenommen werden, wobei nat"urlich auch Wildcards verwendet werden k"onnen. \chapter{Hooks} Stell dir vor, du sitzt als Softwareentwickler in deinem Büro, es ist Freitag nachmittag, kurz vor Feierabend, gute 30 Grad Celsius warm und dein Chef kommt herein und trägt dir auf, das auf der Firmenwebseite die Zeile ``Über uns'' in Fettschrift angezeigt werden soll. Also änderst du die Zeile \begin{verbatim} echo "Über uns"; \end{verbatim} um in \begin{verbatim} echo "

Über uns

" \end{verbatim} in der Datei ``header.php''.\\ Du lädst die Seite in das Git-Repo, lädst die geänderte Datei auf das Produktivsystem, fährst deinen Rechner runter und gehst in den Feierabend.\\ \\ Montag morgen kommst du in die Firma und darfst erst einmal zum Chef kommen, der dir erzählt, dass statt der Firmenwebseite das ganze Wochenende nur eine weisse Seite zu sehen war. Das demonstriert er dir eindeutig auf seinem Laptop. Deine Gesichtsfarbe wechselt von sommerlich gebräunt zum Rot eines Herbstapfels, hin zu einem weiss, wogegen die Wandfarbe eines bekannten Farbherstellers grau wirkt!\\ \\ Was war passiert? \chapter{Ein paar kleinere Tricks} \section{Wenn es schnell gehen muss} Es gibt durchaus Situationen, in denen man alle Branches in einem Rutsch auf den git-Server pushen will, dann verwende man ``git push --all origin''. Für Tags gilt analog ``git push --tags origin''. \section{Repository von einem Server zu einem anderen umziehen} Manchmal ändert sich der Name des Servers, auf dem die Repos gepackt werden, z.B. wenn der Name des Unternehmens sich ändert, oder wenn man von GitHub zu einem eigenen git-Server migriert. Gründe gibt es genug. Jedenfalls muss man erst einmal dafür Sorge tragen, dass das Repo auf dem alten Server vollständig ist und keiner im Team mehr dorthin einen Push durchführt. Ausserdem muss das eigene Repo ebenfalls komplett auf dem aktuellsten Stand sein. Der Umzug geht dann ganz unspektakulär per ``git git remote set-url origin '' von sich. Ein aktuelles Beispiel für dieses Repo: \begin{verbatim} git remote set-url origin opengit@opengit.hauke-zuehl.de: \ hauke/Git-Einfuehrung.git \end{verbatim} \section{Zweige miteinander vergleichen} ``git diff'' in einem Zweig anzuwenden, um Unterschiede anzeigen zu lassen, ist für Dich ein Kiderspiel, aber nehmen wir mal an, du bist im Zweig ``develop'' und willst die Änderungen gegenüber den Masterzweig wissen. Dann gibst du einfach mal ``git diff master'' ein. Das geht natürlich mit jedem anderen Zweig dieses Repositories, den du einmal ausgecheckt (und nicht gelöscht) hast. \chapter{GIT in IDEs} Die meisten IDEs bringen inzwischen Unterst"utzung f"ur GIT mit.\\ \section{Geany} Geany ist eine kleine, erweiterbare IDE, die kostenlos f"ur diverse Plattformen angeboten wird.\\ Mit Hilfe eines Plugins kann die Verbindung zu GIT installiert werden. Nach der Aktivierung des Plugins steht dann unter dem Menü ``Werkzeuge'' der Eintrag ``Versionskontrolle'' zur Verfügung. Hier kann dann GIT für die zur Zeit bearbeitete Datei oder für das gesamte Projektverzeichnis verwendet werden.\\ \\ \textbf{Tip:}\\ Geany legt individuelle Projektdateien in einem eigenen Verzeichnis an. Dies sollte, wenn möglich, nicht im Verzeichnis des GIT-Repos liegen, da es sonst Probleme mit anderen Teammitgliedern geben kann! \section{NetBeans} NetBeans ist eine recht verbreitete IDE, die kostenlos f"ur diverse Plattformen angeboten wird.\\ Die Verbindung von NetBeans zu GIT kann "uber ein Plugin ggf. nachinstalliert werden.\\ Startet man NetBeans, hat man unter Team->Git die M"oglichkeit, GIT-Repos zu verwenden.\\ Als Beispiel verwende ich nun das Repository unter https://github.com/hauke68/LibTgBotPP, das jedoch das C-/C++-Plugin voraussetzt.\\ Um dies anonym auszuchecken und in ein NetzBeans-Projekt zu packen, geht man wie folgt vor:\\ Unter Team->Git->Clone wird die obige URL eingetragen. Benutzer und Passwort bleiben leer. Im n"achsten Schritt kann man die Zweige ausw"ahlen, die ausgecheckt werden sollen. Ich empfehle, erst einmal alle auszuchecken. Im dritten Schritt lassen wir alles so, wie es ist.\\ Ist alles ordnugsgem"a"s ausgecheckt, sollten wir im Git Repository Browser bereits das GIT-Repo sehen. Nun fehlt noch das NetBeans-Projekt.\\ Dazu auf File->New Project klicken und ein neues C-/C++-Projekt anlegen. Dabei darauf achten, dass im Fenster ``Projects'' ``C/C++ Project with existing sources'' ausgew"ahlt ist. Im zweiten Schritt w"ahlen wir das Verzeichnis aus, in dem die Quellen des Repos sind. Das ist nat"urlich das vorhin erzeugte Verzeichnis vom GIT-Repo.\\ Da das hier nur ein Beispiel ist, w"ahlen wir als Configuration Mode ``custom'' aus. Jetzt nur noch auf ``Next'' klicken, bis nur noch ``Finish'' m"oglich ist. Voila, das NetBeans-Projekt existiert und man kann auch GIT als Versionskontrollsystem verwenden.\\ Wenn du nun eine Datei l"adst, "anderst und speicherst, kannst du unter ``Team'' sehen, dass es mehr Auswahlm"oglichkeiten in Bezug auf GIT gibt.\\ Spiele hier einfach mal ein wenig rum. Da du das Repo anonym ausgecheckt hast, kannst du nichts kaputt machen. Etwas anderes w"are es nat"urlich, wenn du unser Einstiegsprojekt ``Welt'' mit Hilfe von NetBeans bearbeiten willst. Ich wei"s aber nicht, in welche Kategorie dieses ``Projekt'' f"allt.\\ \\ \textbf{Tip:}\\ Da NetBeans im Verzeichnis des Quellcodes gerne das Verzeichnis ``nbproject'' anlegt, sollte dies in die .gitignore aufgenommen werden, das es sonst zu Konflikten mit dem nbproject anderer Teammitglieder kommen kann. Noch besser w"are es, nbproject ganz woanders hin auszulagern (Zum Beispiel in das eigene Benutzerverzeichnis). \chapter{Zum Ende noch ein paar Ideen und Worte} Zum Ende hin noch ein paar Anregungen bzgl. der Einsatzzwecke von GIT.\\ Man kann GIT alleine nutzen, kein Problem. Das f"angt mit den eigenen Skripten und Programmen an, geht "uber Korrespondenz bis hin zu Konfigurationsdateien des Rechners (bzw. der Rechner). Nimm dir zum Beispiel einen Raspberry Pi als GIT- und Puppetserver, dann kannst du deine Linuxb"uchsen ganz einfach per Puppet konfigurieren.\\ Oder du willst dir nicht gleich einen Cloudserver einrichten, dann kannst du deine pers"onlichen Dateien mit Hilfe von GIT verwalten.\\ \\ Ich hoffe, ich konnte dir einen kleinen Einblick in die Arbeitsweise von GIT vermitteln. Es ist ein wenig "Ubung n"otig, aber mit der Zeit hast du die Grundkommandos verinnerlicht und solltest keine Probleme mehr haben.\\ Tip: Committe oft! Damit ist nicht nur das ``commit'' gemeint, sondern durchaus auch das ``push''. ``push'' sollte aber definitiv immer kurz vor Feierabend gemacht werden.\\ Mit dieser Einstellung sorgst du daf"ur, dass man deine "Anderungen bessser nachvollziehen kann; es ist einfacher, zwei oder drei Zeilen sp"ater nachzuvollziehen, als wenn du 234 Zeilen in 20 Dateien "anderst und man diese "Anderungen sp"ater nachvollziehen will. \\ Viel Spa"s mit GIT. \end{document}