-
1. Erste Schritte
- 1.1 Über Versionskontrolle
- 1.2 Eine kurze Geschichte von Git
- 1.3 Was ist Git?
- 1.4 Die Kommandozeile
- 1.5 Git installieren
- 1.6 Erstmalige Git-Einrichtung
- 1.7 Hilfe bekommen
- 1.8 Zusammenfassung
-
2. Git Grundlagen
-
3. Git Branching
- 3.1 Branches im Überblick
- 3.2 Grundlegendes 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 Generieren Ihres SSH-Public-Keys
- 4.4 Einrichten des Servers
- 4.5 Git Daemon
- 4.6 Smart HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Drittanbieter-Hosting-Optionen
- 4.10 Zusammenfassung
-
5. Verteiltes Git
-
6. GitHub
-
7. Git-Werkzeuge
- 7.1 Revisionsauswahl
- 7.2 Interaktives Staging
- 7.3 Stashing und Bereinigen
- 7.4 Ihre Arbeit signieren
- 7.5 Suchen
- 7.6 Historie umschreiben
- 7.7 Reset entmystifiziert
- 7.8 Fortgeschrittenes Merging
- 7.9 Rerere
- 7.10 Debugging mit Git
- 7.11 Submodule
- 7.12 Bundling
- 7.13 Ersetzen
- 7.14 Credential-Speicher
- 7.15 Zusammenfassung
-
8. Git anpassen
-
9. Git und andere Systeme
- 9.1 Git als Client
- 9.2 Migration zu Git
- 9.3 Zusammenfassung
-
10. Git-Interna
- 10.1 Plumbing und Porcelain
- 10.2 Git-Objekte
- 10.3 Git-Referenzen
- 10.4 Packfiles
- 10.5 Die Refspec
- 10.6 Übertragungsprotokolle
- 10.7 Wartung und Datenwiederherstellung
- 10.8 Umgebungsvariablen
- 10.9 Zusammenfassung
-
Anhang A: Git in anderen Umgebungen
- A1.1 Grafische Oberflächen
- 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
-
Anhang B: Git in Ihre Anwendungen einbetten
- A2.1 Kommandozeilen-Git
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
Anhang C: Git-Befehle
- A3.1 Einrichtung und Konfiguration
- A3.2 Projekte abrufen und erstellen
- A3.3 Grundlegendes Snapshotting
- A3.4 Branching und Merging
- A3.5 Projekte teilen und aktualisieren
- A3.6 Inspektion und Vergleich
- A3.7 Debugging
- A3.8 Patching
- A3.9 E-Mail
- A3.10 Externe Systeme
- A3.11 Administration
- A3.12 Plumbing-Befehle
A2.3 Anhang B: Git in Ihre Anwendungen einbetten - JGit
JGit
Wenn Sie Git aus einem Java-Programm heraus verwenden möchten, gibt es eine voll ausgestattete Git-Bibliothek namens JGit. JGit ist eine relativ voll ausgestattete Implementierung von Git, die nativ in Java geschrieben ist und in der Java-Community weit verbreitet ist. Das JGit-Projekt steht unter dem Schirm von Eclipse, und seine Heimat ist unter https://projects.eclipse.org/projects/technology.jgit zu finden.
Einrichtung
Es gibt eine Reihe von Möglichkeiten, Ihr Projekt mit JGit zu verbinden und mit der Programmierung dagegen zu beginnen. Wahrscheinlich am einfachsten ist die Verwendung von Maven – die Integration wird durch Hinzufügen des folgenden Ausschnitts zum <dependencies>-Tag in Ihrer pom.xml-Datei erreicht.
<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>3.5.0.201409260305-r</version>
</dependency>
Die version wird höchstwahrscheinlich fortgeschritten sein, bis Sie dies lesen; überprüfen Sie https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit für aktualisierte Repository-Informationen. Sobald dieser Schritt abgeschlossen ist, wird Maven automatisch die benötigten JGit-Bibliotheken abrufen und verwenden.
Wenn Sie die Binärabhängigkeiten lieber selbst verwalten möchten, sind vorkompilierte JGit-Binärdateien unter https://projects.eclipse.org/projects/technology.jgit/downloads verfügbar. Sie können sie in Ihr Projekt integrieren, indem Sie einen Befehl wie diesen ausführen.
javac -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App.java
java -cp .:org.eclipse.jgit-3.5.0.201409260305-r.jar App
Plumbing
JGit hat zwei grundlegende API-Ebenen: Plumbing und Porcelain. Die Terminologie dafür stammt aus Git selbst, und JGit ist grob in dieselben Bereiche unterteilt: Porcelain-APIs sind ein freundliches Frontend für gängige Aktionen auf Benutzerebene (die Art von Dingen, die ein normaler Benutzer mit dem Git-Befehlszeilen-Tool machen würde), während die Plumbing-APIs für die direkte Interaktion mit Low-Level-Repository-Objekten gedacht sind.
Der Ausgangspunkt für die meisten JGit-Sitzungen ist die Klasse Repository, und das erste, was Sie tun möchten, ist, eine Instanz davon zu erstellen. Für ein dateisystembasiertes Repository (ja, JGit erlaubt auch andere Speicherformate) wird dies mit FileRepositoryBuilder erreicht.
// Create a new repository
Repository newlyCreatedRepo = FileRepositoryBuilder.create(
new File("/tmp/new_repo/.git"));
newlyCreatedRepo.create();
// Open an existing repository
Repository existingRepo = new FileRepositoryBuilder()
.setGitDir(new File("my_repo/.git"))
.build();
Der Builder verfügt über eine flüssige API, um alle notwendigen Informationen zur Suche nach einem Git-Repository bereitzustellen, unabhängig davon, ob Ihr Programm genau weiß, wo es sich befindet. Es kann Umgebungsvariablen verwenden (.readEnvironment()), von einem Ort im Arbeitsverzeichnis ausgehen und suchen (.setWorkTree(…).findGitDir()) oder einfach ein bekanntes .git-Verzeichnis wie oben öffnen.
Sobald Sie eine Repository-Instanz haben, können Sie damit alle möglichen Dinge tun. Hier ist eine kleine Auswahl.
// Get a reference
Ref master = repo.getRef("master");
// Get the object the reference points to
ObjectId masterTip = master.getObjectId();
// Rev-parse
ObjectId obj = repo.resolve("HEAD^{tree}");
// Load raw object contents
ObjectLoader loader = repo.open(masterTip);
loader.copyTo(System.out);
// Create a branch
RefUpdate createBranch1 = repo.updateRef("refs/heads/branch1");
createBranch1.setNewObjectId(masterTip);
createBranch1.update();
// Delete a branch
RefUpdate deleteBranch1 = repo.updateRef("refs/heads/branch1");
deleteBranch1.setForceUpdate(true);
deleteBranch1.delete();
// Config
Config cfg = repo.getConfig();
String name = cfg.getString("user", null, "name");
Hier passiert ziemlich viel, also gehen wir es Abschnitt für Abschnitt durch.
Die erste Zeile ruft einen Zeiger auf die master-Referenz ab. JGit holt sich automatisch die *tatsächliche* master-Referenz, die unter refs/heads/master liegt, und gibt ein Objekt zurück, mit dem Sie Informationen über die Referenz abrufen können. Sie können den Namen (.getName()) und entweder das Zielobjekt einer direkten Referenz (.getObjectId()) oder die von einer symbolischen Referenz referenzierte Referenz (.getTarget()) abrufen. Ref-Objekte werden auch verwendet, um Tag-Referenzen und -Objekte darzustellen, sodass Sie fragen können, ob der Tag „gepeelt“ ist, was bedeutet, dass er auf das endgültige Ziel einer (potenziell langen) Zeichenkette von Tag-Objekten zeigt.
Die zweite Zeile ruft das Ziel der master-Referenz ab, das als ObjectId-Instanz zurückgegeben wird. ObjectId repräsentiert den SHA-1-Hash eines Objekts, das in der Objektdatenbank von Git vorhanden sein kann oder auch nicht. Die dritte Zeile ist ähnlich, zeigt aber, wie JGit die Rev-Parse-Syntax (für mehr dazu siehe Branch References) handhabt; Sie können jeden Objektbezeichner übergeben, den Git versteht, und JGit gibt entweder eine gültige ObjectId für dieses Objekt oder null zurück.
Die nächsten beiden Zeilen zeigen, wie die rohen Inhalte eines Objekts geladen werden. In diesem Beispiel rufen wir ObjectLoader.copyTo() auf, um die Inhalte des Objekts direkt nach stdout zu streamen. ObjectLoader hat aber auch Methoden, um den Typ und die Größe eines Objekts zu lesen und es als Byte-Array zurückzugeben. Für große Objekte (bei denen .isLarge() true zurückgibt) können Sie .openStream() aufrufen, um ein InputStream-ähnliches Objekt zu erhalten, das die Rohdaten des Objekts lesen kann, ohne sie alle auf einmal in den Speicher zu laden.
Die nächsten Zeilen zeigen, was zur Erstellung eines neuen Branches erforderlich ist. Wir erstellen eine RefUpdate-Instanz, konfigurieren einige Parameter und rufen .update() auf, um die Änderung auszulösen. Direkt danach folgt der Code zum Löschen desselben Branches. Beachten Sie, dass .setForceUpdate(true) dafür erforderlich ist; andernfalls gibt der Aufruf .delete() REJECTED zurück und es passiert nichts.
Das letzte Beispiel zeigt, wie der Wert user.name aus den Git-Konfigurationsdateien abgerufen wird. Diese Config-Instanz verwendet das zuvor geöffnete Repository für die lokale Konfiguration, erkennt aber automatisch die globalen und Systemkonfigurationsdateien und liest auch Werte daraus.
Dies ist nur eine kleine Auswahl der vollständigen Plumbing-API; es gibt viele weitere Methoden und Klassen. Nicht gezeigt ist auch, wie JGit Fehler behandelt, nämlich durch die Verwendung von Ausnahmen. JGit-APIs werfen manchmal Standard-Java-Ausnahmen (wie IOException), aber es gibt auch eine Vielzahl von JGit-spezifischen Ausnahmetypen, die ebenfalls bereitgestellt werden (wie NoRemoteRepositoryException, CorruptObjectException und NoMergeBaseException).
Porcelain
Die Plumbing-APIs sind ziemlich vollständig, aber es kann umständlich sein, sie zu verketten, um gängige Ziele zu erreichen, wie z. B. das Hinzufügen einer Datei zum Index oder das Erstellen eines neuen Commits. JGit bietet eine übergeordnete Menge von APIs, um dabei zu helfen, und der Einstiegspunkt zu diesen APIs ist die Klasse Git.
Repository repo;
// construct repo...
Git git = new Git(repo);
Die Git-Klasse verfügt über eine schöne Sammlung von High-Level-Methoden im Builder-Stil, mit denen sich ziemlich komplexe Verhaltensweisen erstellen lassen. Werfen wir einen Blick auf ein Beispiel – etwas Ähnliches wie git ls-remote.
CredentialsProvider cp = new UsernamePasswordCredentialsProvider("username", "p4ssw0rd");
Collection<Ref> remoteRefs = git.lsRemote()
.setCredentialsProvider(cp)
.setRemote("origin")
.setTags(true)
.setHeads(false)
.call();
for (Ref ref : remoteRefs) {
System.out.println(ref.getName() + " -> " + ref.getObjectId().name());
}
Dies ist ein gängiges Muster bei der Git-Klasse; die Methoden geben ein Befehlsobjekt zurück, mit dem Sie Methodenaufrufe verketten können, um Parameter festzulegen, die ausgeführt werden, wenn Sie .call() aufrufen. In diesem Fall fragen wir den Remote-Server origin nach Tags, aber nicht nach Heads. Beachten Sie auch die Verwendung eines CredentialsProvider-Objekts zur Authentifizierung.
Viele andere Befehle sind über die Git-Klasse verfügbar, darunter unter anderem add, blame, commit, clean, push, rebase, revert und reset.
Weiterführende Literatur
Dies ist nur eine kleine Auswahl der vollen Fähigkeiten von JGit. Wenn Sie interessiert sind und mehr erfahren möchten, finden Sie hier Informationen und Inspiration.
-
Die offizielle JGit-API-Dokumentation finden Sie unter https://help.eclipse.org/latest/topic/org.eclipse.egit.doc/help/JGit/User_Guide/User-Guide.html. Dies sind Standard-Java-Docs, sodass Ihre bevorzugte JVM-IDE sie auch lokal installieren kann.
-
Das JGit Cookbook unter https://github.com/centic9/jgit-cookbook enthält viele Beispiele, wie Sie spezifische Aufgaben mit JGit erledigen können.