Im letzten Teil ging es um das Rebasen und das Einrichten und Nutzen von
Remote-Repositorys. In diesem Teil wird es rein um GitHub und dessen Workflow gehen. Darunter
fällt unter anderem das Erstellen eines Repositorys und wie man sich an Open-Source-Projekten
auf GitHub beteiligen kann.
Dieses Tutorium besteht aus vier Teilen. Wem das Tutorium gefällt und mehr über
Git lernen möchte, der kann sich das Buch „Versionsverwaltung mit Git“
für 29,99€ bestellen. In diesem Buch, was ich geschrieben habe, werden die Themen rund um Git noch
deutlich ausführlicher behandelt.
Was ist GitHub?
Im dritten Teil dieses Tutoriums wurde zwar erläutert wie man mit Remote-Repositorys
arbeitet, allerdings fehlte bislang eine sinnvolle Möglichkeit um Repositorys
auf entfernt liegenden Servern zu lagern, die man über das öffentliche Internet
erreichen kann. Eines der Dienste um dies zu erledigen ist GitHub.
GitHub besitzt sehr viele Funktionen die sich um das kollaborative
Arbeiten an Projekten mit Git drehen. Darüber hinaus besitzt GitHub zwar noch einige weitere
Dienste, dieser Teil des Tutorium dreht sich allerdings mehr um die grundsätzlichen
Funktionen, die Git betreffen.
Hinweis: Da GitHub stetig weiterentwickelt wird, ändert sich auch die Web-Oberfläche.
Die in diesem Artikel enthaltenen Screenshots könnten bereits nach wenigen Monaten veraltet
sein.
Repository anlegen
Bei GitHub können Git-Repositorys angelegt werden. Bevor man sein
erstes Repository anlegen kann, muss man sich zunächst registrieren. Der
Funktionsumfang mit einem Standardkonto ist auf öffentliche Git-Repositorys
beschränkt, das heißt vor allem, dass alle Dateien aus den Repositorys öffentlich
und somit für jeden lesbar sind. Gegen Bezahlung kann man auch private Repositorys anlegen.
Nach der Registrierung und dem Einloggen findet man in der oberen Leiste in
GitHub diverse Bedienelemente, darunter auch ein Knopf um ein neues Repository
bzw. eine neue Organisation anzulegen. Eine Organisation ist an dieser Stelle
noch nicht so wichtig, kurz gesagt, kann man Organisationen anlegen, damit
eine Gruppe an Entwicklern sich die Rechte an Repositorys teilen können. Wenn
man hingegen einen Account als normalen Nutzer besitzt, sind die Rechte standardmäßig
auf die eigenen Repositorys für sich alleine beschränkt.
Wenn man nun ein Repository anlegen möchte, muss man dem Repository zunächst einen
Namen vergeben. Optional ist hingegen eine kurze Beschreibung. Als zusätzliche
Möglichkeit, kann man dem Repository direkt eine README-Datei hinzufügen lassen,
ebenso wie eine “.gitignore”-Datei sowie eine Datei mit den Lizenz-Bestimmungen
des Projektes im Repository.
Die “README”-Datei ist dafür da, um Informationen über das Projekt bzw. das Repository
auf der Startseite des Repositorys darzustellen. GitHub stellt dies automatisch
dar.
In diesem Tutorium wurde bislang noch nicht die Datei “.gitignore” behandelt.
Innerhalb jedem Repositorys kann eine solche Datei anlegt werden. Alles was man
dort einträgt, wird von Git schlicht ignoriert und somit nicht weiter beobachtet. Wenn
man etwa an LaTeX-Dokumenten arbeitet, hat man bei jedem Kompilieren der TeX-Datei
einige Dateien, die nicht direkt für das Projekt selbst relevant sind und somit
auch eine Versionierung nicht notwendig ist. Diese Dateien kann man in der Datei
“.gitignore” eintragen und Git zeigt diese Dateien in keinen der Befehle an.
GitHub macht das Anlegen der Datei noch ein wenig komfortabler, da es sehr viele
vordefinierte gitignore-Dateien anbietet, etwa für Java-, Android- oder TeX-Projekte.
Weiterhin kann man beim Anlegen eines Repositorys über GitHub eine Lizenz-Datei
anlegen lassen. Dies ist wichtig, damit auch
andere Leute von dem Inhalt des Repositorys profitieren können.
Wenn man nun einen Namen, eine Beschreibung sowie eine Lizenz-Datei ausgewählt
hat und anschließend das Repository erzeugt, dann besitzt das Repository zu Beginn
genau einem Commit mit der Commit-Message „Initial Commit“.
SSH-Key anlegen und hinzufügen
Bevor man das neu angelegte Repository klonen kann, muss man dem GitHub-Account
noch einen SSH-Key hinzufügen. Sofern man auf dem lokalen Rechner noch kein
SSH-Key erzeugt hat, muss zunächst ein Key anlegt werden.
Falls man nicht weiß, ob man schon mindestens einen SSH-Key besitzt, kann man
den Inhalt vom Ordner “~/.ssh” überprüfen. Ein SSH-Key setzt sich aus
zwei Dateien zusammen. Dies ist zum einen der private und zum anderen
der öffentliche Schlüssel. Beispielsweise ist die Datei “id_rsa” der private Schlüssel,
während “id_rsa.pub” öffentlicher Schlüsselteil ist.
Sofern man noch keinen SSH-Key angelegt hat, kann man das mit dem folgenden Befehl
erledigen:
$ ssh-keygen -t rsa -C "mail@svij.org"
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sujee/.ssh/id_rsa): /home/sujee/.ssh/id_github
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sujee/.ssh/id_github.
Your public key has been saved in /home/sujee/.ssh/id_github.pub.
The key fingerprint is:
SHA256:LFM8YkUe+ACh4+mH0GXZ4xAlWXT3zpHDEKdg/r9jBHI mail@svij.org
The key's randomart image is:
+---[RSA 2048]----+
| =B+oB +.. |
| ..=oB + * . |
| o = =o. . * |
| o = + =ooEo o |
|. + + So..o |
| o . o .. |
| o . .. |
| . o. |
| ... |
+----[SHA256]-----+
Beim Ausführen des gelisteten Befehls werden interaktiv einige Fragen gestellt,
die beantwortet werden sollten. Darunter den exakten Speicherort des Schlüssels,
sowie ein Passwort. Man kann zwar auch einen Schlüssel ohne Passwort generieren,
dies ist allerdings nicht empfehlenswert, da man sonst vollständigen Zugriff auf
die Repositorys erhält, falls der private Schlüssel in falsche Hände gerät.
Nachdem nun das Schlüsselpaar generiert worden ist, muss nun der öffentliche
Schlüssel in GitHub eintragen werden. Der öffentliche Schlüssel liegt in diesem Beispiel
in “~/.ssh/id_github.pub”. In den GitHub-SSH-Einstellungen
muss dann der Inhalt dieser Datei eingefügt werden.
Repository klonen
An dieser Stelle kann man das Repository erstmals klonen. Dazu braucht man
die URL, um es über SSH zu klonen. Dies findet man entweder auf der GitHub-Repository-Seite
oder man setzt es sich selbst zusammen, da es immer dem gleichen Schema folgt.
In meinem Beispiel heißt das Repository „drunken-nemesis“ im Nutzer-Konto „svijee“.
Das Repository findet sich daher unter https://github.com/svijee/drunken-nemesis.
Unter der rechten Seitenleiste auf GitHub findet sich die URL zum Klonen via SSH, HTTPS oder
Subversion. Relevant ist in der Regel nur das Klonen via SSH.
$ git clone git@github.com:svijee/drunken-nemesis.git
Klone nach 'drunken-nemesis'...
Enter passphrase for key '/home/sujee/.ssh/id_github':
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Empfange Objekte: 100% (3/3), Fertig.
Prüfe Konnektivität... Fertig.
Wenn man das Repository direkt klont, konfiguriert Git automatisch das geklonte
Repository als das „origin“ Remote-Repository. Dies kann man nachvollziehen, wenn man in das
Verzeichnis wechselt und dort die Remote-Repositorys auflistet.
$ cd drunken-nemesis
$ git remote -v
origin git@github.com:svijee/drunken-nemesis.git (fetch)
origin git@github.com:svijee/drunken-nemesis.git (push)
Anschließend kann man alle gewünschten Funktionen von Git nutzen, wie das Erstellen
von Branches und Commits. Diese können dann anschließend gepusht werden, um die
Änderungen über GitHub zur Verfügung zustellen. Die Änderungen lassen sich auch
auf der Webseite von GitHub selbst ansehen, sodass man Repositorys nicht zwangsläufig
klonen muss. Unter github.com/svijee/drunken-nemesis/commits/master
finden sich etwa alle Commits die auf dem Branch “master” getätigt wurden. Ebenfalls
kann man dort zwischen den Branches wechseln.
GitHub-Workflow
Das Besondere an GitHub ist, dass es nicht nur eine einfache Möglichkeit bietet
eigene Git-Repositorys zu hosten, sondern auch, dass man mit wenigen Schritten
Änderungen an Repositorys von anderen Personen oder Organisationen vorschlagen
kann, die dann übernommen werden können.
Jedes GitHub-Repository lässt sich im Browser forken. Bei einem Fork spricht man
von einer Abspaltung. Hin und wieder hört man bei größeren Open-Source-Projekten,
das ein Fork entstanden ist. So ist die Büro-Suite LibreOffice ein Fork von OpenOffice.org, wo
allerdings nicht die Änderungen zu OpenOffice.org zurückgeflossen sind. Bei GitHub
hat ein Fork in der Regel eine etwas andere Bedeutung. In der Regel liegen die
Zugriffsberechtigungen an einem Repository allein bei dem Besitzer des Repositorys.
Über GitHub kann man nun Änderungen an einem Repository vorschlagen, dazu muss
man den Fork-Button im Browser drücken. Dann wird eine Kopie (der Fork) des Repositorys
erzeugt und im eigenen Account abgelegt. Dort besitzt man anschließend alle
nötigen Schreibrechte. Wenn man also an dem Repository svijee/drunken-nemesis
Änderungen vorschlagen möchte, erstellt GitHub nach dem Drücken des Fork-Buttons
eine Kopie des Repositorys unter $DEINNAME/drunken-nemesis. GitHub zeigt selbst
direkt auch an, dass es sich um einen Fork des Haupt-Repositorys handelt.
An dem Fork kann man nun wie gewünscht auf einem Branch die gewünschten Änderungen
in Form von Commits durchführen. In der Regel bietet es sich an, dafür einen extra
Branch anzulegen in dem man die Commits hinzufügt. Fehlen darf dafür natürlich kein
Beispiel:
$ git clone git@github.com:$DEINUSERNAME/drunken-nemesis.git
$ cd drunken-nemesis
Anschließend kann man etwa eine Datei namens “README” mit beliebigen Inhalt
hinzufügen, die anschließend commited werden kann.
$ git add README
$ git commit -m "README Datei hinzugefügt."
Zur Wiederholung: Wichtig ist an diesem Punkt, dass man nicht vergisst das Repository
zu GitHub zu pushen. Da Git bekanntlich ein verteiltes Versionsverwaltungssystem
ist, sind die Änderungen bis zu diesem Punkt nur lokal verfügbar. Daher muss man
noch “git push” ausführen, um die Änderungen zu dem Remote-Repository auf GitHub zu
übertragen.
Anschließend kann man über GitHub den sogenannten Pull-Request erstellen, in dem
man die Änderungen die man gemacht hat, dem Haupt-Repository zur Übernahme vorschlägt.
Bei jedem Repository, wo die Pull-Request-Funktion nicht abgeschaltet wurde, findet
sich auf der Repository-Seite der Menüpunkt „Pull Requests“
auf der sich vorhandene, offene Pull-Requests befinden und auch neue angelegt
werden können. Beim Anlegen müssen dann beide Branches, jeweils aus dem Quell-
und Ziel-Repository, ausgewählt werden, die zunächst verglichen werden können.
Sofern alle benötigten Änderungen in dem Pull-Request enthalten sind, kann der
Request angelegt werden. Die Mitarbeiter an dem Haupt-Repository, an dem der Pull-Request
gestellt wurde, können diesen Kommentieren oder direkt annehmen.
Arbeiten mit zwei Remote-Repositorys
Wenn man regelmäßig an einem Projekt über GitHub beiträgt, bietet sich eine
lokale Konfiguration an, die das Arbeiten mit zwei Remote-Repositorys erleichtert.
Dadurch, dass man letztendlich mit zwei Repositorys arbeitet, müssen beide
korrekt verwaltet werden. So gibt es einmal das eigene Repository, in dem man
Schreibrechte besitzt und das Repository des Projektes, wohin die Pull-Requests
und auch anderen Änderungen des Projektes fließen. Man sollte daher immer beachten,
dass man sein eigenes Repository auf dem eigenen Stand hält.
Wenn die oben aufgeführten Befehle ausgeführt hat, ist der eigene Fork als Remote-Repository
“origin” konfiguriert. Dies sollte man genau so belassen, da man alle Branches
in das eigene Repository pusht. Jetzt sollte man das Repository des Projektes ebenfalls
als Remote-Repository hinzufügen, hier bietet es sich an, es “upstream” zu nennen,
da es sich schließlich um das Upstream-Projekt handelt.
$ git remote add upstream git@github.com:svijee/drunken-nemesis.git
Jetzt ist zwar das Repository konfiguriert, allerdings sind die Änderungen noch nicht
heruntergeladen. Dies kann man mit einem der beiden aufgeführten Befehle durchführen.
$ git remote update
$ git fetch upstream
Während der erste Befehl alle Remote-Repositorys herunterlädt, lädt letzterer
Befehl nur das Remote “upstream” herunter. In der Regel ist es nun so, dass sich
auf dem Upstream-Repository einiges tut, diese Änderungen müssten dann regelmäßig
in das eigene Repository übernommen werden. Dazu sollte man regelmäßig “git remote update”
ausführen und anschließend den Branch aus dem Remote-Repository in den Branch des eigenen
Repositorys mergen. In diesem Beispiel, ist es der Branch “master” den man
aktualisieren möchte.
$ git merge upstream/master
Sofern keine Änderungen auf dem Branch “master” im eigenen Repository sind, sollte
der Merge problemlos funktionieren. Änderungen, die man dem Haupt-Repository beifügen
will, sollte man daher immer in einem neuen Branch anlegen, um Merge-Konflikte
zu vermeiden.
Häufig passiert es aber auch, dass man Pull-Requests anlegt, die zu einem späteren
Zeitpunkt nicht mehr automatisch ohen Konflikte gemergt werden können. Als Einreicher
von Pull-Requests sollte man also immer darauf achten, dass der Pull-Request ohne
Konflikte gemergt werden kann. Da dies nicht immer möglich ist, müssen gegebenfalls
Commits aus dem Entwicklungs-Branch des Haupt-Repositorys übernommen werden. Diese
kann man entweder mit dem “git merge” Befehl mergen, schöner ist es allerdings, wenn
man ein Rebase durchführt, der im dritten Teil dieses Tutoriums erläutert wurde.
Weitere Funktionen von GitHub
GitHub bietet nicht nur das Hosten von Repositorys an. Die Funktionen sind mittlerweile
vielfältig und decken so gut wie alle Wünsche ab, die man für ein Software-Projekt
haben kann. Darunter ein Ticket-System („Issues“) und ein Wiki. Beides ist direkt
über das Repository zu erreichen. Daneben kann man auch statische Webseiten
mit GitHub Pages hosten oder Gists
als Lager für einzelne Dateien anlegen.
Alternativen
GitHub ist nicht die einzige Plattform, welche das Hosten von Repositorys mit
sinnvollen Features erweitert um einfach und kollaborativ an Projekten zu arbeiten.
So hat GitHub auch Nachteile, etwa steht es selbst nicht unter eine Open Source
Lizenz und das Hosten von privaten, nicht öffentlichen Repositorys kostet Geld.
Als Alternative seien Gitlab und Bitbucket
genannt, bei denen man auch private Repositorys mit einigen Begrenzungen kostenlos hosten kann. Gitlab
kann man aber auch selbst auf eigenen Servern hosten, sodass man etwa für den
Firmen-internen Gebrauch von Closed Source Software den Quellcode nicht auf
fremde Server hochladen muss.