Benutzer-Werkzeuge

Webseiten-Werkzeuge


de:software:git:index

git

Ein paar Hinweise zum Arbeiten mit dem Versionsverwaltungssystem (VCS) git. Ziel ist, den Leser grundlegend dazu zu befähigen, Projekte mit git versionszuverwalten - sei es ein Programmierprojekt oder eine (Abschluss-)Arbeit mit LaTeX.

Grundsätzlich ist das Arbeiten mit einem (verteilten) Versionsverwaltungssystem wie git jedem empfohlen, der entweder programmiert (egal wie klein das Projekt sein mag) oder eine Arbeit mit LaTeX schreibt. Es gibt viele gute Quellen zum Umgang mit git, aber vielleicht ist manch Mensch einfach zu faul. Deshalb hier eine Kurzanleitung ohne Anspruch auf Allgemeingültigkeit.

Es gibt Möglichkeiten, git über grafische Oberflächen oder integriert in Entwicklungsumgebungen (IDEs) zu verwenden. Zum Erlernen empfiehlt sich aber in jedem Fall die Kommandozeile. Davon wird im Folgenden ausgegangen. Ansonsten werden stillschweigend an viele Stellen die englischen Begriffe (Commit, Repository, …) verwendet.

Nachfolgend behandelte Themen:

  • Grundsätzliches zu git
  • Installation von git
  • Lokal Repository erzeugen
  • Die Datei .gitignore
  • Der erste Commit
  • Konfiguration
  • Remotes: Abgleich mehrerer lokaler Instanzen
  • Tags
  • Releases
  • Und jetzt?

Grundsätzliches zu git

git ist ein verteiltes Versionsverwaltungssystem. Das bedeutet, dass es lokal auf einem Rechner funktioniert, vollkommen unabhängig von Internetzugang etc.

Git-Repositories sind zunächst einmal lokal, sie lassen sich aber beliebig untereinander abgleichen. Das geht der Einfachheit halber auch über via Internet erreichbare „zentrale“ Repository-Kopien, die als „remote“ eingetragen werden. Plattformen wie GitHub, aber auch selbstgehostete Installationen von GitLab oder Gitea sind dafür sehr praktikabel.

Git ist das (lokale bzw. verteilte) Versionsverwaltungssystem, die genannten Plattformen sind unabhängig davon und stellen eine (mehr oder weniger komplexe) (Web-)Oberfläche mit weiteren Funktionalitäten bereit. Hier geht es um git, nur ganz am Rande um die genannten Plattformen.

Erzeugen einer Version (Revision)

Der Ablauf zum Erzeugen einer „Version“ (Revision) ist in git zweistufig: Zunächst werden Dateien der sogenannten „staging area“ hinzugefügt (git add), anschließend dann ein neuer Commit (git commit) erzeugt.

Man sollte tunlichst, insbesondere beim Hinzufügen aller Änderungen, vor einem Commit überprüfen, was in den Commit einfließen würde (git status). Sonst schleichen sich oft ungewollte Dateien ein (temporäre Dateien etc.).

Generelle Befehlssyntax

Die generelle Befehlssyntax von git lautet:

git <Befehl>

wobei <Befehl> so etwas wie init, status, add, commit sein kann. Zu den einzelnen Befehlen später mehr. Zu jedem Befehl kann auf dem Terminal eine Hilfe angezeigt werden:

git help <Befehl>

Installation

Die Installation unterscheidet sich je nach Betriebssytem:

  • Linux
    • git ist meist bereits vorinstalliert
    • ansonsten über die Paketquellen installieren
  • macOS
    • git ist mittlerweile nicht mehr vorinstalliert, kann aber über die „developer tools“ installiert werden.
    • Der Aufruf von „git“ im Terminal gibt entsprechende Hilfestellung
  • Windows

Nach der Erstinstallation sollte man git noch grundlegend konfigurieren, zumindest den Namen und eine (gültige) Email-Adresse angeben. Siehe dazu den Abschnitt Konfiguration.

Lokal Repository erzeugen

Der erste Schritt bei einem neuen Projekt ist meist, lokal ein Git-Repository zu erzeugen. Dazu in einem Terminal in das Verzeichnis wechseln, in dem das Repository erzeugt werden soll, und den folgenden Befehl eingeben:

git init

Die Antwort im Terminal sieht ungefähr wie folgt aus:

Initialized empty Git repository in /path/to/your/repo/.git/

wobei /path/to/your/repo der aktuelle Dateipfad zum Verzeichnis ist.

Es spielt keine Rolle, ob im Verzeichnis bereits Dateien (und weitere Verzeichnisse) liegen. D.h. konkret, dass ein bestehendes Projekt einfach in ein git-Repository verwandelt werden kann.

Die Datei .gitignore

Temporäre Dateien sollten grundsätzlich nicht in die Versionsverwaltung einbezogen werden, da sie meist automatisch erzeugt werden, sich häufig ändern und für das Projekt nicht essentiell sind. Beispiele wären die diversen Dateien, die (pdf)LaTeX bei der Übersetzung eines LaTeX-Dokuments erzeugt. macOS hat die Angewohnheit, in jedem Verzeichnis eine Datei „.DS_Store“ zu erzeugen, die ebenfalls nicht versioniert werden sollte.

Git bringt Mechanismen mit, ungewollte Dateien zu ignorieren: die Datei .gitignore im Hauptverzeichnis des Repositorys. Ein Beispiel für eine .gitignore-Datei für LaTeX-Projekte könnte wie folgt aussehen:

.gitignore
.DS_Store
*~
*zip
*gz
*aux
*dvi
*log
*nav
*out
*snm
*toc
*bbl
*blg
*pdf
*lo?
*bcf
*run.xml
*vrb
*maf
*mtc*

Für andere Arten von Projekten (Python, MATLAB, …) sollten entsprechend Anpassungen vorgenommen werden. In jeder Zeile steht entweder ein Dateiname oder ein Suchmuster.

Ausführlichere Beispiele:

.gitignore-Dateien sind reine Textdateien. Sie können entsprechend mit jedem Texteditor bearbeitet werden.

Der erste Commit

Sind bereits Dateien im Repository vorhanden oder hat man die ersten Dateien angelegt (.gitignore nicht vergessen, s.o.), geht es daran, die erste „Version“ (Revision) zu erzeugen. Zur Erinnerung: Das ist bei git ein zweistufiger Prozess – erst werden die Dateien zur „staging area“ hinzugefügt, danach die eigentliche Revision erzeugt.

Änderungen anschauen

Bevor man Änderungen der staging area hinzufügt, ist es immer hilfreich, sich anzuschauen, was man gemacht hat:

git status

Im Falle eines leeren, frisch erzeugten Repositorys ohne Commits und mit hinzugefügter .gitignore-Datei sieht dass dann wie folgt aus:

On branch master

No commits yet

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	.gitignore

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

Die Meldungen von git sind überwiegend selbsterklärend. Wer lesen kann und das dann auch noch tut, ist (einmal mehr) klar im Vorteil.

Gibt es bereits Revisionen, lässt sich die Veränderung zum letzten Mal anschauen:

git diff

Die Ausgabe ist zunächst gewöhnungsbedürftig, insbesondere bei mehreren Dateien, zumal sie der Reihe nach angezeigt werden. Wenn die Ausgabe länger als das aktuelle Terminalfenster hoch ist: Navigieren mit den Pfeiltasten, Verlassen der Vergleichsansicht mit q.

Alle Änderungen stagen

Sollen alle Änderungen der staging area hinzugefügt werden, lautet der Befehl:

git add .

Anschließend am Besten noch einmal über git status überprüfen, was man getan hat:

git status

Die Rückgabe sähe im obigen Fall (nur die Datei .gitignore existierte und wurde hinzugefügt) wie folgt aus:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

	new file:   .gitignore

Ist versehentlich eine Datei mit in die staging area gerutscht, die da gar nicht sein sollte, lässt sich das wie angegeben (git rm –cached <file>…) wieder rückgängig machen.

Commit: Neue Version/Revision erzeugen

Wenn alles gefällt, kann schließlich eine neue Version/Revision erzeugt werden, sprich: die Änderungen committed bzw. ein neuer Commit erzeugt werden:

git commit -m "<Beschreibung>"

Wichtig: Jeder Commit sollte eine kurze Beschreibung haben, die über den Parameter -m angegeben wird. <Beschreibung> zwischend den doppelten Anführungszeichen entsprechend durch eine kompakte Beschreibung ersetzen. Die Beschreibung sollte die Änderungen zusammenfassen. Die eigentlichen Änderungen lassen sich bequem über von git mitgelieferte Werkzeuge (git diff) nachvollziehen.

Ein Beispiel:

git commit -m "Initial commit"

Die Ausgabe auf dem Terminal sieht dann wie folgt aus:

[master (root-commit) 44bc177] Initial commit
 1 file changed, 2 insertions(+)
 create mode 100644 .gitignore

Wurden Name und Email-Adresse des Nutzers noch nicht konfiguriert (was der Normalfall bei einer frischen Installation von git bzw. einer Erstbenutzung ist), dann sieht die Ausgabe etwas anders aus:

 Committer: Till Biskup <till@Tills-MBP.fritz.box>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly. Run the
following command and follow the instructions in your editor to edit
your configuration file:

    git config --global --edit

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 1 file changed, 2 insertions(+)
 create mode 100644 .gitignore

In diesem Fall sollte den Anweisungen Folge geleistet werden. Die Konfiguration wird in der Datei .gitconfig im Home-Verzeichnis des Nutzers abgelegt. Für Details einer solchen Datei s.u. im Abschnitt Konfiguration.

Eine anschließende Überprüfung via

git status

zeigt, dass alles in bester Ordnung ist:

On branch master
nothing to commit, working tree clean

Hurra, der erste erfolgreiche Commit. Viel komplizierter wird es erst einmal nicht, wenn man alleine an einem Projekt arbeitet und die Vorzüge der Versionsverwaltung haben möchte. Unterschiedliche Versionen zu vergleichen etc. ist etwas für später, Details in der offiziellen Dokumentation zu git.

Konfiguration

Git speichert zu jeder Revision den Namen und die Email-Adresse des Beitragenden. Deshalb ist es sinnvoll, dass hier korrekte Werte hinterlegt werden. Die Information wird für jeden Nutzer in der Datei .gitconfig in dessen Nutzerverzeichnis abgelegt.

Ein Beispiel für eine solche Datei könnte wie folgt aussehen:

.gitconfig
[user]
	name = Hans Wurst
	email = hans@wurst

Es lassen sich aber noch viele weitere Einstellungen vornehmen. Ein etwas komplexeres Beispiel könnte wie folgt aussehen:

.gitconfig
[user]
	name = Hans Wurst
	email = hans@wurst
[core]
	editor = vim
[color]
	status = auto
	branch = auto
[alias]
	ci = commit
	st = status
	co = checkout

Hier werden die git-Meldungen farbig ausgegeben, außerdem wird eine Reihe von Kurzbefehlen eingeführt, die das Leben mitunter immens vereinfachen können.

Remotes: Abgleich mehrerer lokaler Instanzen

Ein Wahlspruch von git lautet: „everything is local“. Das ist einer der unschlagbaren Vorteile verteilter Versionsverwaltungssysteme: keine Abhängigkeit von Internetverbindung und Servern, entsprechend schnelle lokale Aktionen.

Trotzdem ist ein häufiger Anwendungsfall von git, die Codebasis eines Projektes (seien es die LaTeX-Quellen einer Arbeit o.ä. oder ein Programmierprojekt) auf mehreren Rechnern synchron zu halten - ganz zu schweigen vom gemeinsamen Arbeiten an einem Projekt. Dafür gibt es „Remotes“, git-Repositories, die zum Abgleich mehrerer lokaler Repositories dienen. Über die Befehle git push und git pull werden Commits dorthin gespiegelt bzw. von dort eingeholt. Die ausgeprägten Fähigkeiten von git, mit unterschiedlichen Versionen und an mehreren Stellen gleichzeitig geänderten Dateien umzugehen, macht die Synchronisation entsprechend einfach(er).

Remote lokal hinzufügen

Die allgemeine Syntax, um ein Remote einem lokalen Repository hinzuzufügen, lautet:

git remote add <Name> <URL>

Das setzt voraus, dass es diesen Remote bereits gibt, z.B. ein Repository über die Webschnittstelle von GitHub oder einer GitLab- oder Gitea-Instanz erzeugt wurde. Meist zeigen diese Plattformen dann auch die Befehle an, die man lokal ausführen muss, um den Remote hinzuzufügen.

Ein spezieller Name für einen Remote ist origin, das ist dann der Standard-Remote, den man bei git push und git pull nicht angeben muss.

Entsprechend führt man einmalig, nachdem man einen Remote auf GitHub/GitLab/Gitea angelegt hat, diesen Befehl aus:

git remote add origin <URL>

Es kann beliebig viele Remotes geben, sie müssen dann eben unterschiedliche (möglichst sprechende) Namen tragen.

Um sich die existierenden Remotes detailliert anzeigen zu lassen, eignet sich der Befehl:

git remote -v

Hier werden jeweils zwei Zeilen angezeigt, eine für fetch (Änderungen nach lokal holen), eine für push (Änderungen veröffentlichen).

Commit zu einem Remote übertragen

Ist lokal ein Remote eingetragen, können die lokalen Änderungen veröffentlicht werden:

git push

Wird kein Name für einen Remote angegeben, wird implizit „origin“ verwendet.

Es empfiehlt sich immer, zunächst ein git pull zu machen und eventuelle entfernte Änderungen lokal einzuarbeiten, bevor man lokale Änderungen veröffentlicht. Sollten die lokalen Änderungen inkompatibel zum Zustand des Remotes sein, wird die Veröffentlichung nämlich abgelehnt.

Änderungen von einem Remote holen

Um Änderungen von einem Remote ins lokale git-Repository zu holen, dient der Befehl:

git pull

Sollten lokal Änderungen aufgetreten sein, gibt git ggf. entsprechende Hinweise aus und versucht, soweit möglich die Änderungen automatisch zusammenzuführen (merge). Ggf. ist Handarbeit notwendig.

Vor einem git pull sollte in der Regel erst ein git commit lokal durchgeführt werden, um einen definierten Zustand lokal zu haben.

Kommunikation mit dem Remote: SSH-Keys

In der Regel ist der Zugriff auf ein Remote-Repository auf gewisse Nutzer beschränkt, die sich vorher authentifizieren müssen. Da es mühsam ist, jedesmal Nutzername und Passwort einzugeben, gibt es meist die Möglichkeit, über einen SSH-Schlüssel (genauer: ein Schlüsselpaar aus öffentlichem und privatem Schlüssel) die Authentifizierung abzuwickeln.

Unter Linux und macOS liegt das Schlüsselpaar im Verzeichnis .ssh/ im Home-Verzeichnis des jeweiligen Nutzers. Der Standard-Schlüssel heißt id_rsa.pub (öffentlicher Schlüssel). Sollte es diesen Schlüssel bereits geben, ist es das Einfachste, ihn auf der jeweiligen Plattform (GitHub, GitLab, Gitea) zu hinterlegen. Gibt es keinen entsprechenden Schlüssel, muss er zunächst erzeugt werden:

ssh-keygen -t rsa -b 4096

Hier sollten alle Fragen durch drücken der „Enter/Return“-Taste beantwortet und so die Standardeinstellungen gewählt werden. Anschließend liegen die Schlüssel unter ~/.ssh/id_rsa.pub (öffentlich) und ~/.ssh/id_rsa (privat).

Der private Schlüssel darf niemals in fremde Hände gelangen.

Der Inhalt der Datei ~/.ssh/id_rsa.pub kann dann auf die jeweilge Plattform (GitHub, GitLab, Gitea) hochgeladen werden. Um den Inhalt auf dem Terminal anzeigen zu lassen und ihn so einfach kopieren zu können, kann unter Linux/macOS der Befehl

cat ~/.ssh/id_rsa.pub

verwendet werden.

Gitea: Der Schlüssel wird unter „Einstellungen“ ⇒ „SSH-/GPG-Schlüssel“ hinzugefügt. Das Menü „Einstellungen“ erreicht man durch Anklicken des Symbols für den Nutzer oben rechts in der Ecke.

GitHub: Der Schlüssel wird über „Preferences“ ⇒ „SSH keys“ hinzugefügt. Das Menü „Preferences“ erreicht man durch Anklicken des Symbols für den Nutzer oben rechts/links in der Ecke.

GitHub: Der Schlüssel wird über „Settings“ ⇒ „SSH and GPG keys“ hinzugefügt. Das Menü „Settings“ erreicht man durch Anklicken des Symbols für den Nutzer oben rechts in der Ecke.

Tags

Mitunter möchte man eine Version besonders hervorheben. Ein typischer Anwendungsfall ist das Hinzufügen von Versionsnummern (ggf. dem SemVer-Schema folgend) zu Commits einer Veröffentlichung.

Der git-Befehl dazu lautet tag, z.B. so:

git tag -a v0.2.2 -m "Release v0.2.2"

Die Tags sind normalerweise lokal. Um sie mit einem Remote (s.o.) abzugleichen, müssen sie explizit gepushed werden, im Fall des oben erzeugten Tags sähe das dann so aus:

git push origin v0.2.2

Hier ist „origin“ der Standard-Remote. Sollten weitere Remotes konfiguriert sein, muss der entsprechende Name angegeben werden.

Releases

Wie geht man sinnvoll mit Releases um? Dazu gibt es vermutlich so viele Ideen wie Nutzer. Eine Möglichkeit soll hier vorgestellt werden.

  • Releases sind einzelne Commits in einem speziellen Zweig („stable“).
  • Releases werden via Semantic Versioning benannt.

Der Ablauf für ein Release sähe also grob wie folgt aus, ausgehend von der Entwickung im Zweig „master“:

In Zweig „stable“ wechseln:

git checkout stable

Alle Änderungen aus dem master-Zweig mergen (aber ohne Commit):

git merge --no-commit -X theirs master

Dieser Befehl muss im Wurzel-Verzeichnis des Repositorys ausgeführt werden, um sinnvoll zu funktionieren. Alternativ kann man natürlich auch einzelne Pfade angeben.

Versionsnummer in Datei VERSION anpassen, i.d.R. das Suffix „dev#“ abschneiden. Ggf. Release-Datum in der Changelog in der Dokumentation und Roadmap anpassen.

Änderungen hinzufügen und committen:

git add .
git commit -m "Release v#.#.#" -a

Vorausgesetzt es existiert die Datei VERSION und sie enthält nichts außer der Versionsnummer (nach SemVer-Schema), kann man sich das Leben auch etwas einfacher machen:

git commit -m "Release `cat VERSION`" -a

Version taggen:

git tag v#.#.#
git tag -f v#.#

Natürlich muss „#.#.#“ an die jeweils aktuelle Versionsnummer angepasst werden.

Auch hier wieder, für etwas mehr Bequemlichkeit (gegeben die oben genannten Voraussetzungen):

git tag v`cat VERSION`
git tag -f v`cat VERSION | cut -d. -f1-2`

Release und Tag veröffentlichen:

git push
git push --tags -f origin stable

Anschließend zurück in den master-Zweig wechseln und die Versionsnummer in der Datei „VERSION“ anpassen, also meist zumindest „MINOR“ hochzählen und das Suffix „dev0“ oder „dev1“ anhängen. Sollte die Changelog-Datei in der Dokumentation zwischendurch angepasst worden sein, cherry-pick auf diese Datei machen, z.B.:

git co stable docs/changelog.rst

Und jetzt?

Gratulation: Wer bis hierhin gekommen ist und alle Schritte umgesetzt hat, hat ein lokales git-Repository, das zudem je nach Wunsch auch noch mit einem anderen Repository (remote) abgeglichen wird.

Das war natürlich nur ein allererster Anfang mit git, aber immerhin sollten das alle notwendigen Schritte sein, um seine Projekte in einer Versionsverwaltung liegen zu haben.

Für die nächsten Schritte sei der geneigte Leser auf die Literatur (Abschnitt Literatur und Links) verwiesen.

offizielle Quellen und Bücher

allgemeine Diskussion von Versionsverwaltungssytemen

  • Versionsverwaltung
    Kapitel aus der Vorlesung „Programmierkonzepte in der Physikalischen Chemie“ des Autors

Heise-Artikelserie zu git und seinen komplexeren Fähigkeiten:

de/software/git/index.txt · Zuletzt geändert: 2023/06/28 14:07 von till