Versionskontrollsystem git: Erste Schritte

https://bildung.social/@oerinformatik/110326723919640390

https://oer-informatik.de/git01-repo_anlegen_und_lokal_commiten

tl/dr; (ca. 16 min Lesezeit): Bevor wir uns in die weite Welt von Github, Gitlab, Bitbucket usw. aufmachen wollen wir erst einmal verstehen, was lokal passiert und ein paar Begriffe klären: Was ist ein Commit? Was ist ein Repository? Was ist der Workspace? Was ist die Stage? In welchen Schritten versioniere ich? Wie gestalte ich meine Commit-Nachrichten? Neben diesem Teil gibt es noch die beiden Tutorialfolgen Versionieren mit Branches und Git Remote nutzen. (Zuletzt geändert am 27.05.2023)

Bei git handelt es sich um ein dezentrales Versionskontrollsystem. Es dient dazu, verschiedene Versionsstände eines Projektes zu verwalten. Häufig wird git mit Diensten wie Github, Gitlab oder Bitbucket gleichgesetzt, denn git übernimmt bei allen drei Diensten die Versionierung im Hintergrund. git bleibt ein dezentraler Dienst, auch wenn das Projekt auf einer zentralen Website gehostet wird, denn jeder Client verfügt i.d.R. über alle vergangenen Versionsstände (die gesamte Historie).

Oft wird git über Plugins oder über Integration in einer Entwicklungsumgebung genutzt. Wir wollen jedoch direkt die git-Befehle in der Konsole absetzen, um den Versionierungsprozess zu verstehen und um bei Versionierungsproblemen eingreifen zu können.

git Installieren

Die aktuelle git-Version lässt sich über die URL https://git-scm.com/download laden. Bei der Installation können im Wesentlichen Voreinstellungen verwendet werden, allerdings sollte folgendes beachtet werden: + Es sollte ein Editor nach Wahl eingestellt werden, andernfalls ist der für Einsteiger etwas sperrige vim ausgewählt (atom, notepad++, VSCode: ganz nach Belieben). + git, aber nicht die Unix-Befehle von der Kommandozeile nutzen (voreingestellt) + Unix-Konvertierung der Zeilenumbrüche aktivieren (oberste Option) Dann kann es losgehen. Starten Sie die git-bash!

git-bash starten und konfigurieren

Funktioniert git? In der Konsole kann die Versionsnummer abgefragt werden:

git version 2.35.1.windows.2

Damit die einzelnen Versionen zum einen zuordenbar sind, zum anderen die Hash-Werte berechnet werden können, ist noch eine Personalisierung erforderlich, beispielsweise über diese beiden Befehle:

Damit ist alles einsatzbereit für die ersten Gehversuche mit git.

Welche Konfiguration aktuell eingestellt ist lässt sich überprüfen mit

Ein erstes Repository anlegen:

Die nötigen Dateien im .git Ordner lassen wir im Folgenden anlegen: Navigieren Sie in der git-bash mit cd in den Ort, an dem Sie ein Projektverzeichnis eröffnen wollen und erstellen dort mit mkdir ein Projektverzeichnis (ich nenne mein Verzeichnis “mein-git-versuch”):

Navigieren Sie mit cd ins gerade erstellte Projektverzeichnis:

Erzeugen Sie für diesen Projektordner mit git init ein Repository. Was geschieht dadurch? git legt einen Unterordner .git an (je nach Einstellung des Betriebssystems ist dieser versteckt, lässt sich aber in der git-bash mit ls -la anzeigen). In diesem Unterordner speichert git alle Versionsstände, und Konfigurationen dieses Repositories.

Mit der Option -b main kann man bei neueren git-Versionen dafür sorgen, dass der Haupt-Zweig dieses neuen Versionierungsprojekts “main” heißt (früher wurde häufig “master” genutzt):

Die Antwort des Systems:

Initialized empty Git repository in ../mein-git-versuch/

Den aktuellen Status des Repositorys kann man sich mit git status ausgeben lassen:

On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)

Commit: Eine erste Projektversion erstellen

git unterscheidet drei Stadien, in denen sich Dateien in einem Projekt befinden können:

  • Workspace: Im Workspace sind alle Dateien, die aktuell im Dateisystem des Projektordners liegen.

  • Stage: Dateien, die angemeldet sind, um der nächsten Version anzugehören, wurden quasi auf die Bühne (stage) geholt. Sie können aber noch verändert werden, die aktuellen Änderungen sind noch nicht das Versionsverwaltungssystem eingefügt.

  • Repository: Das Repository bezeichnet die Gesamtheit aller bisherigen Änderungen. Alle Versionsstände sind im Repository gespeichert. Im Dateisystem befinden sich diese Daten im .git-Unterordner. Wenn man eine neue Version in das Repostory übernimmt, spricht man von einem commit.

Bislang gibt es natürlich noch keine Datei zu versionieren. Wir werden jetzt eine als einfaches Beispiel im Projektverzeichnis eine neue Datei erstellen, stagen und commiten. Wir erstellen also eine Python-Datei mit dem folgenden Inhalt und speichern sie als hello.py im Projektordner ab.

Die Datei liegt nun im Workspace. Eine erneute Ausgabe des Status’ zeigt, dass git zwar registriert hat, dass es eine neue Datei gibt, diese ist jedoch noch nicht zur Versionierung angemeldet (“untracked”).

On branch main
No commits yet
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        hello.py

nothing added to commit but untracked files present (use "git add" to track)

git gibt uns aber auch direkt einen Hinweis, was wir tun können: Die neue Datei muss auf die Stage gehoben werden. Hierzu dient der Befehl git add:

Bei vielen Änderungen ist es natürlich mühsam, jede Datei einzeln anzumelden. git kann mithilfe der Option --all (Kurzform -A) auch einfach jede Datei des Projektverzeichnisses (“Workspace”) zur Versionierung anmelden

Der neue Status lässt sich wieder abfragen:

On branch main
No commits yet
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   hello.py

Im Hintergrund passiert noch gar nicht so wahnsinnig viel. Die git weiß jetzt nur, dass diese Datei im nächsten Schritt versioniert werden soll.

Datei für die nächste Version vormerken mit git add (UML-Sequenzdiagramm)
Datei für die nächste Version vormerken mit git add (UML-Sequenzdiagramm)

Noch ist die Datei nur vorgemerkt. Die vorbereiteten Änderungen können jetzt in eine Version des Projekts übernommen werden, wobei für die Versionsübersicht (das Log) eine Nachricht angefügt werden sollte, im einfachsten Fall mit der Option --message (Kurzform: -m).

[main (root-commit) d04664e] new feature: say 'Hello NAME'
 1 file changed, 2 insertions(+)
 create mode 100644 hello.py

In der Ausgabe finden wir erste Informationen zu unserem commit:

  • Die ersten Zeichen des Hashes (“d04664e”). Der Hashwert tritt bei git an die Stelle einer Versionsnummer, die aufgrund der dezentralen Struktur nicht fortlaufend erstellt werden kann. Der Hash wird aus Autorenname und Commit-Zeitpunkt ermittelt und ist mit an Sicherheit grenzender Wahrscheinlichkeit eindeutig.

  • Ab der dritten Zeile finden sich Informationen zu den enthaltenen Dateien, wie Name und Zugriffsrechte (im Beispiel: “100644” - nach Linux Konvention)

Bei einem Commit wird die Liste aller Dateien auf der Stage geholt und für jede Datei die Änderungen ermittelt. Diese Änderungen werden dann ins Repository geschrieben:

Einen neuen Versionsstand erstellen mit git commit (UML-Sequenzdiagramm)
Einen neuen Versionsstand erstellen mit git commit (UML-Sequenzdiagramm)

Den aktuellen Status der veröffentlichten Projektversion:

Und siehe da: alle Änderungen wurden erfasst. Workspace und Repository sind auf dem gleichen Stand, die Stage ist leer.

On branch main
nothing to commit, working tree clean

Informationen zur aktuellen Version erhalten.

Zum Commit selbst können wir uns mit git log genauere Informationen ausgeben lassen, am kompaktesten mit der Option --oneline.

d04664e (HEAD -> main) new feature: say 'Hello NAME'

Den kompletten Hashwert der _Commits_zeigt log ohne Optionen an:

commit d04664ee3bb278cec2021a54c2f17d5fe86d002a (HEAD -> main)
Author: Martin Mustermann <martin.mustermann@test.de>
Date:   Mon Feb 7 17:40:13 2022 +0100

    new feature: say 'Hello NAME'

Detaillierte Informationen zu den einzelnen betroffenen Dateien erhält man mit der Option --stat:

commit d04664ee3bb278cec2021a54c2f17d5fe86d002a (HEAD -> main)
Author: martin.mustermann <martin.mustermann@test.de>Date:   Mon Feb 7 17:40:13 2022 +0100
    new feature: say 'Hello python2.7'
 hello.py | 2 ++
 1 file changed, 2 insertions(+)

Dateien ändern

Wir erstellen beispielhaft eine neue Version. Es gibt ein paar kleine Änderungen und Ergänzungen:

Nach dem Speichern zeigt ein git status direkt, was zu tun ist:

On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   hello.py

no changes added to commit (use "git add" and/or "git commit -a")

Also, wie bei der ersten Runde, zunächst die Datei auf die Stage hieven:

… dann eine neue Version speichern:

[main 7a910bf] new feature: say Good-bye
 1 file changed, 2 insertions(+), 1 deletion(-)

Die Ausgabe von git log --oneline wird jetzt schon interessanter:

7a910bf (HEAD -> main) new feature: say Good-bye
d04664e new feature: say 'Hello NAME'

Versionsunterschiede darstellen

Was unterscheidet die eine Version von der anderen? Diese Informationen erhalten wir mit dem git Kommando diff. Wenn wir zwei Commits vergleichen wollen übergeben wir (mindestens) die ersten vier Zeichen der Hashwerte (erst alte Version, dann neue Version):

Die Ausgabe erfolgt in der Konsole farbig. Es werden gelöschte Zeilen (erstes Zeichen ein -), angefügte Zeilen (+) ausgegeben. In der Zeile mit dem Doppelklammeraffen wird angegeben:

@@  -alte Zeilennummer,  Länge des ausgeschnittenen +neueZeilennummer, Länge der Einfügung @@
diff --git a/hello.py b/hello.py
index d6abd70..a6f9d07 100644
--- a/hello.py
+++ b/hello.py
@@ -1,3 +1,2 @@
-name = input("Bitte geben Sie den Namen ein: ")
+name = input("Bitte den Namen eingeben: ")
 print("Hallo", name, "!")
-print("Auf Wiedersehen!")

Wer es noch genauer benötigt, der dann sich auch das Diff auf Wortebene ausgeben lassen mit Hilfe der Option --word-diff. Hier werden die jeweiligen Passagen in Klammern gekennzeichnet: [-GELÖSCHTE TEXTE-] und {+EINGEFÜGTE TEXTE+}.

diff --git a/hello.py b/hello.py
index d6abd70..a6f9d07 100644
--- a/hello.py
+++ b/hello.py
@@ -1,3 +1,2 @@
name = input("Bitte[-geben Sie-] den Namen [-ein:-]{+eingeben:+} ")
print("Hallo", name, "!")
[-print("Auf Wiedersehen!")-]

Dateien verschieben, löschen, anfügen

Wir erstellen eine neue Datei:

… und ändern den Namen unseres Python-Quelltextes.

Wieder zeigt git status unmittelbar an, dass eine gelöschte (hello.py) noch Bestandteil des Repositories ist, wohingegen zwei andere noch nicht erfasst wurden (hallo.py, readme.md). Wir ändern das in einem Aufwasch:

Eine Übersicht der unterschiedlichen Stadien, in denen sich ein git-versioniertes Projekt befinden kann (mit den jeweiligen git-Befehlen) findet sich in folgendem UML-Zustandsdiagramm:

Die unterschiedlichen Zustände eines mit git versionierten lokalen Projekts im UML-Zustandsdiagramm
Die unterschiedlichen Zustände eines mit git versionierten lokalen Projekts im UML-Zustandsdiagramm

Aussagekräftige commit-messages

Für die ersten Gehversuche reicht für einen Commit eine kurze einzeilige Nachricht an unser zukünftiges ich. Es sollte im Imperativ formuliert sein und sich auf das “Was?” und “Warum?” konzentrieren.

In der git-Dokumentation ist davon die Rede, dass die Commit-Message aus Subject, Description und Footer bestehen soll, jeweils durch eine Leerzeile getrennt.1].

Eine verbreitete Umsetzung dieser Dreiteilung ist beispielsweise die angular style-Konvention für Commit-Nachrichten.2 Die erste Zeile hat demnach folgenden Aufbau:

TYPE[(SCOPE)]: SUBJECT

Die Zeile ist begrenzt auf maximal 50 Zeichen und besteht aus den Komponenten

  • TYPE (z.B. feat, fix, refactor, test, docs) gibt an, in welchem Umfang sich das Projekt geändert hat

  • SCOPE ist optional und wird eingeklammert (z.B. gui, plugin, logging-modul). Sofern die Veränderung nur eine bestimmte Schicht oder Komponente betriff, wird das in Klammern notiert.

  • Das SUBJECT beginnt mit einem Großbuchstaben und endet ohne Punkt. Es fasst zusammen was geändert wurde.

Für kleine Projekt und häufige Commit sollte der Einzeiler reichen. Wer aber in größeren Projekten arbeitet und die komplette Tagesleistung in einen Commit fasst sollte sich nicht auf Einzeiler begrenzen: oftmals ist es wichtig, sich genauer auf das “Was?” und “Warum?” zu beziehen. Der angular-stype sieht folgende Komponenten vor:

TYPE[(SCOPE)]: SUBJECT

[BODY]

[FOOTER]
  • Auf die Betreffzeile folgt nach einer Leerzeile die genaue Beschreibung, was sich geändert hat und v.a.: warum!

  • Auch dieser Text wird im Imperativ geschrieben und sollte (wie Code generell) nach 72 Zeichen umbrechen. Es gilt das richtige Maß zu finden. Nur relevante Informationen, aber nicht zu wenige (“So einfach wie möglich, aber nicht einfacher” A. Einstein)

  • Unterhalb des Bodys kann im footer noch beschrieben werden, welches Ticket/Issue durch den Commit gelöst wurde.

Teile dieses Tutorials

Weitere Literatur zur Versionsverwaltung git

  • als Primärquelle: die git-Dokumentation - lässt sich im Terminal mit git --help aufrufen oder unter https://git-scm.com/doc

  • Als Info v.a. zu zentralen Workflows mit git: René Preißel / Bjørn Stachmann: Git (dPunkt Verlag, ISBN Print: 978-3-86490-649-7

  • Aus der “von Kopf bis Fuß”-Serie von O’Reilly - erfrischend anders: “Head First Git” von Raju Gandhi (englisch), ISBN: 9781492092513

  • Zahllose Tutorials im Internet wie z.B. dieses von Atlassian


Hinweis zur Nachnutzung als Open Educational Resource (OER)

Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: Versionskontrollsystem git: Erste Schritte” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/git01-repo_anlegen_und_lokal_commiten veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/devoptools/git. Stand: 27.05.2023.

[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]


  1. Customizing-Git-Git-Configuration

  2. Angular Commit Convention

Kommentare gerne per Mastodon, Verbesserungsvorschläge per gitlab issue (siehe oben). Beitrag teilen: