-
1. Erste Schritte
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches auf einen Blick
- 3.2 Einfaches Branching und Merging
- 3.3 Branch-Management
- 3.4 Branching-Workflows
- 3.5 Remote-Branches
- 3.6 Rebasing
- 3.7 Zusammenfassung
-
4. Git auf dem Server
- 4.1 Die Protokolle
- 4.2 Git auf einem Server einrichten
- 4.3 Erstellung eines SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git-Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Von Drittanbietern gehostete Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git Tools
- 7.1 Revisions-Auswahl
- 7.2 Interaktives Stagen
- 7.3 Stashen und Bereinigen
- 7.4 Deine Arbeit signieren
- 7.5 Suchen
- 7.6 Den Verlauf umschreiben
- 7.7 Reset entzaubert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debuggen mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Replace (Ersetzen)
- 7.14 Anmeldeinformationen speichern
- 7.15 Zusammenfassung
-
8. Git einrichten
- 8.1 Git Konfiguration
- 8.2 Git-Attribute
- 8.3 Git Hooks
- 8.4 Beispiel für Git-forcierte Regeln
- 8.5 Zusammenfassung
-
9. Git und andere VCS-Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git Interna
-
A1. Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Schnittstellen
- A1.2 Git in Visual Studio
- A1.3 Git in Visual Studio Code
- A1.4 Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine
- A1.5 Git in Sublime Text
- A1.6 Git in Bash
- A1.7 Git in Zsh
- A1.8 Git in PowerShell
- A1.9 Zusammenfassung
-
A2. Anhang B: Git in deine Anwendungen einbetten
- A2.1 Die Git-Kommandozeile
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Anhang C: Git Kommandos
- A3.1 Setup und Konfiguration
- A3.2 Projekte importieren und erstellen
- A3.3 Einfache Snapshot-Funktionen
- A3.4 Branching und Merging
- A3.5 Projekte gemeinsam nutzen und aktualisieren
- A3.6 Kontrollieren und Vergleichen
- A3.7 Debugging
- A3.8 Patchen bzw. Fehlerkorrektur
- A3.9 E-mails
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Basisbefehle
10.3 Git Interna - Git Referenzen
Git Referenzen
Wenn du den Verlauf deines Repositorys sehen möchtest, der über Commit erreichbar ist, z. B. 1a410e
, kannst du so etwas wie git log 1a410e
ausführen, um diesen Verlauf anzuzeigen. Dennoch musst du sich weiterhin daran erinnern, dass 1a410e
der Commit ist den du als Ausgangspunkt für diese Historie verwenden möchtest.
Es wäre aber einfacher, wenn du eine Datei hättest, in der du diesen SHA-1-Wert unter einem einfachen Namen speichern kannst, sodass du diesen einfachen Namen anstelle des unformatierten SHA-1-Werts verwenden könntest.
In Git werden diese einfachen Namen „Referenzen“ oder „Refs“ genannt. Du findest die Dateien, die diese SHA-1-Werte enthalten, im Verzeichnis .git/refs
.
Im aktuellen Projekt enthält dieses Verzeichnis keine Dateien, es enthält eine einfache Struktur:
$ find .git/refs
.git/refs
.git/refs/heads
.git/refs/tags
$ find .git/refs -type f
Um eine neue Referenz zu erstellen, die dir hilft, dich zu erinnern, wo sich dein letzter Commit befindet, kannst du einfach folgendes machen:
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
Jetzt kannst du die soeben erstellte Kopfreferenz anstelle des SHA-1-Werts in deinem Git-Befehlen verwenden:
$ git log --pretty=oneline master
1a410efbd13591db07496601ebc7a059dd55cfe9 Third commit
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Es wird nicht empfohlen, die Referenzdateien direkt zu bearbeiten. Stattdessen bietet Git den sichereren Befehl git update-ref
, um dies zu tun, wenn du eine Referenz aktualisieren möchtest:
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
Das ist im Grunde genommen ein Branch in Git: ein einfacher Zeiger oder ein Verweis auf den Kopf einer Arbeitslinie. So erstellst du eine Verzweigung beim zweiten Commit:
$ git update-ref refs/heads/test cac0ca
Dein Branch enthält nur Arbeiten von diesem Commit an abwärts:
$ git log --pretty=oneline test
cac0cab538b970a37ea1e769cbbde608743bc96d Second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d First commit
Nun sieht deine Git-Datenbank konzeptionell ungefähr so aus:
Wenn du Befehle wie git branch <branch>
ausführst, führt Git grundsätzlich den Befehl update-ref
aus, um den SHA-1 des letzten Commits des Branches, in dem du sich befindest, in die neue Referenz einzufügen, die du erstellen möchtest.
HEAD
Die Frage ist nun, wenn du git branch <branch>
ausführst, woher kennt Git den SHA-1 des letzten Commits?
Die Antwort ist die HEAD-Datei.
Normalerweise ist die HEAD-Datei ein symbolischer Verweis auf den Branch, in dem du dich gerade befindest. Mit symbolischer Referenz meinen wir, dass sie im Gegensatz zu einer normalen Referenz einen Zeiger auf eine andere Referenz enthält.
In einigen seltenen Fällen kann die HEAD-Datei jedoch den SHA-1-Wert eines Git-Objekts enthalten. Dies geschieht beim Auschecken eines Tags, Commits oder eines Remote-Branches, wodurch dein Repository in den Status "detached HEAD" versetzt wird.
Wenn du dir die Datei ansiehst, siehst du normalerweise Folgendes:
$ cat .git/HEAD
ref: refs/heads/master
Wenn du git checkout test
ausführst, aktualisiert Git die Datei folgendermaßen:
$ cat .git/HEAD
ref: refs/heads/test
Wenn du git commit
ausführst, wird das Commitobjekt erstellt, wobei das übergeordnete Objekt dieses Commitobjekts als der SHA-1-Wert angegeben wird, auf den die Referenz in HEAD verweist.
Du kannst diese Datei auch manuell bearbeiten, es gibt jedoch wieder einen sichereren Befehl: git symbolic-ref
.
Du kannst den Wert deines HEAD über diesen Befehl lesen:
$ git symbolic-ref HEAD
refs/heads/master
Du kannst den Wert von HEAD auch mit demselben Befehl festlegen:
$ git symbolic-ref HEAD refs/heads/test
$ cat .git/HEAD
ref: refs/heads/test
Du kannst keine symbolische Referenz außerhalb des Refs-Stils festlegen:
$ git symbolic-ref HEAD test
fatal: Refusing to point HEAD outside of refs/
Tags
Wir haben gerade die drei Hauptobjekttypen von Git (blobs, trees und commits) besprochen, aber es gibt einen vierten. Das tag-Objekt ähnelt stark einem Commitobjekt — es enthält einen Tagger, ein Datum, eine Nachricht und einen Zeiger. Der Hauptunterschied besteht darin, dass ein Tag-Objekt im Allgemeinen eher auf ein Commit als auf einen Baum verweist. Es ist wie eine Branchreferenz, aber es bewegt sich nie — es zeigt immer auf den gleichen Commit, gibt ihm aber einen lesbareren Namen.
Wie in Git Grundlagen beschrieben, gibt es zwei Arten von Tags: Annotierte- und Leichtgewichtige-Tags. Du kannst einen leichtgewichtigen Tag erstellen, indem du Folgendes ausführst:
$ git update-ref refs/tags/v1.0 cac0cab538b970a37ea1e769cbbde608743bc96d
Das ist alles, was ein leichtgewichtiges Tag ist — eine Referenz, die sich nie bewegt.
Ein annotiertes Tag ist jedoch komplexer.
Wenn du ein annotiertes Tag erstellst, erstellt Git ein Tag-Objekt und schreibt dann einen Verweis, um darauf zu zeigen, anstatt direkt auf den Commit.
Du kannst dies sehen, indem du ein annotiertes Tag (mit der Option -a
) erstellst:
$ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'Test tag'
Hier ist der Wert für das Objekt SHA-1, das erstellt wurde:
$ cat .git/refs/tags/v1.1
9585191f37f7b0fb9444f35a9bf50de191beadc2
Führe nun git cat-file -p
für diesen SHA-1-Wert aus:
$ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2
object 1a410efbd13591db07496601ebc7a059dd55cfe9
type commit
tag v1.1
tagger Scott Chacon <schacon@gmail.com> Sat May 23 16:48:58 2009 -0700
Test tag
Du kannst sehen, dass der Objekteintrag auf den Commit SHA-1-Wert verweist, den du getagged hast. Beachte auch, dass es nicht auf ein Commit verweisen muss. Du kannst jedes Git-Objekt taggen. Beispielsweise hat der Betreuer im Git-Quellcode seinen öffentlichen GPG-Schlüssel als Blob-Objekt hinzugefügt und dann mit Tags versehen. Du kannst den öffentlichen Schlüssel anzeigen, indem du diesen in einem Klon des Git-Repositorys ausführst:
$ git cat-file blob junio-gpg-pub
Das Linux-Kernel-Repository verfügt auch über ein Tag-Objekt, das nicht auf Commits verweist. Das erste erstellte Tag verweist auf den ursprünglichen Baum des Imports des Quellcodes.
Remotes
Der dritte Referenztyp, den du siehst, ist eine Remotereferenz.
Wenn du ein Remote hinzufügst und darauf pushst, speichert Git den Wert, den du zuletzt an diesen Remote gesendet hast, für jeden Branch im Verzeichnis refs/remotes
.
Zum Beispiel kannst du eine Remote mit dem Namen origin
hinzufügen und deinen master
-Branch darauf pushen:
$ git remote add origin git@github.com:schacon/simplegit-progit.git
$ git push origin master
Counting objects: 11, done.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (7/7), 716 bytes, done.
Total 7 (delta 2), reused 4 (delta 1)
To git@github.com:schacon/simplegit-progit.git
a11bef0..ca82a6d master -> master
Anschließend kannst du in der Datei refs/remotes/origin/master
sehen, in welchen master
Branch auf dem origin
Remote du das letzte Mal mit dem Server kommuniziert hast:
$ cat .git/refs/remotes/origin/master
ca82a6dff817ec66f44342007202690a93763949
Remote Referenzen unterscheiden sich von Branches (refs/heads
Referenzen) hauptsächlich darin, dass sie als schreibgeschützt gelten.
Du kannst git checkout
darauf ausführen, aber HEAD wird nicht symbolisch darauf referenzieren, so dass du es niemals mit einem commit
Befehl aktualisieren kannst.
Git verwaltet sie als Lesezeichen für den letzten bekannten Status, in dem sich diese Branches auf diesen Servern befinden.