[JAVA] Erstellen Sie einen wöchentlichen Git-GUI-Client [2] für eine unvollständige Erfassung

Dies ist eine Fortsetzung von Erstellen eines wöchentlichen Git-GUI-Clients [1] Stage / Unstage-Grundwissen.

Ich spreche noch nicht über GUI

Dies ist der Weg vom Beginn der Verwendung von JGit bis zum Aufgeben. Es kann auch als Einführung in JGit gelesen werden. Ich habe noch nicht über GUI gesprochen.

libgit2 und Sprachbindungen

Es gibt eine C-Bibliothek namens libgit2. Wenn es eine Sprache ist, die mit C (?) Kooperieren kann Sie können damit Git-Anwendungen und -Bibliotheken erstellen. https://github.com/libgit2/libgit2#language-bindings Wenn Sie eine schöne Bibliothek in der Sprache haben, die Sie verwenden möchten Sie können es in Ihrer eigenen Anwendung verwenden oder libgit mit Bezug darauf einbetten. [A2.2 Anhang B: Einbinden von Git in Ihre Anwendung - Verwendung von Libgit2](https://git-scm.com/book/ja/v2/Appendix-B:-Git%E3%82%92% E3% 81% 82% E3% 81% AA% E3% 81% 9F% E3% 81% AE% E3% 82% A2% E3% 83% 97% E3% 83% AA% E3% 82% B1% E3% 83% BC% E3% 82% B7% E3% 83% A7% E3% 83% B3% E3% 81% AB% E7% B5% 84% E3% 81% BF% E8% BE% BC% E3% 82% 80-Libgit2% E3% 82% 92% E4% BD% BF% E3% 81% 86% E6% 96% B9% E6% B3% 95)

Kämpfe nicht gegen die Umwelt

Zum Beispiel bin ich ein iOS / Android-App-Entwickler Es fühlt sich an wie ein wenig JavaScript und TypeScript in einer Hybrid-App. Ich wollte ein TypeScript schreiben, also habe ich nodegit ausprobiert, aber Ich gab auf, weil ich es mit Electron in meiner Umgebung nicht bewegen konnte. Atoms git-utils funktioniert auch nicht mit Electron.

Verwenden wir also Java. Da es sich um einen Androider handelt, können Sie beeindruckt sein, wenn Sie nur Java 8 sagen.

Die oben genannten Sprachbindungen haben gezackt,

This is very experimental, very mediocre JNI bindings for libgit2.

Ich bin nicht an JNI gewöhnt, daher habe ich mich entschlossen, JGit hier ruhig zu verwenden.

JGit

Aus der Schlussfolgerung gibt es nicht genug. Außerdem scheint es sich eher um eine ursprüngliche Implementierung als um eine Bindung an libgit2 zu handeln, und es verhält sich anders als der Befehl git.

Nicht nur auf JGit beschränkt, Bibliotheken in jeder Sprache verfügen möglicherweise nicht über alle erforderlichen Git-Funktionen. Ich denke, dass es in Ordnung sein wird, bis Sie ein GUI-Framework wie "Diff erwerben und anzeigen" erstellen.

Die verwendete Version war 4.8.0.201706111038-r.

build.gradle


dependencies {
    // https://mvnrepository.com/artifact/org.eclipse.jgit/org.eclipse.jgit
    compile group: 'org.eclipse.jgit', name: 'org.eclipse.jgit', version: '4.8.0.201706111038-r'
}

diff

Ausgabe als Text

So erhalten Sie das Diff als Text: Die Übergabe an FileRepositoryBuilder.create () erfolgt nicht oben im Repository, sondern im Verzeichnis .git.

        final File gitDir; // .Git-Verzeichnis
        final Repository repository = FileRepositoryBuilder.create(gitDir)
        final Git git = new Git(repository);
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        final List<DiffEntry> entryList = git.diff()
                .setCached(cached)
                .setOutputStream(bos)
                .call();
        final String text = new String(bos.toByteArray(), StandardCharsets.UTF_8)

Verschiedene Optionen für DiffCommand werden von git.diff () zurückgegeben Call () aufrufen.

Gleiches gilt für andere Befehle

Andere Befehle als diff haben eine ähnliche Schnittstelle.

  1. Rufen Sie eine Instanz der Klasse ab, die dem Befehl git entspricht
  2. Legen Sie die Optionen fest
  3. Holen Sie sich das Ergebnis mit der Methode call ()

DiffFormatter

[DiffEntry] mit git.diff (). Call () (http://download.eclipse.org/jgit/site/4.8.0.201706111038-r/apidocs/org/eclipse/jgit/diff/DiffEntry.html) Sie können es auch abrufen und dann erneut an OutputStream ausspucken. Verwenden Sie die Klasse DiffFormatter. (Auch wenn OutputStream in DiffCommand festgelegt ist, wird DiffFormatter in der Methode call () verwendet.)

Bei der Verwendung von DiffFormatter und DiffEntry gibt es einige Einschränkungen. Wenn Sie sich den Unterschied eines Arbeitsbereichs ansehen, der die Änderung nicht bereitgestellt hat (nicht im Index registriert). (Wenn Sie sich das Diff im Arbeitsbereich ansehen, dh in "git diff", ist es natürlich normal, dass Sie nicht inszeniert sind.)

        final Git git = new Git(repository);
        final ByteArrayOutputStream bos = new ByteArrayOutputStream();
        final List<DiffEntry> entryList = git.diff()
                .setCached(false)
//                .setOutputStream(bos)
                .call();

        final DiffFormatter fmt = new DiffFormatter(bos);
        fmt.setRepository(repository);
        fmt.format(entryList);
        final String text = new String(bos.toByteArray(), StandardCharsets.UTF_8);

Dadurch wird eine org.eclipse.jgit.errors.MissingObjectException ausgelöst. Es gibt kein Problem mit "git.diff (). SetCached (true) .call ()", was "git add --cached" entspricht.

** Als nächstes werde ich die Ursache und das Mittel aufschreiben, aber es gibt keinen praktischen Wert. ** ** ** Für diejenigen, die in Schwierigkeiten sind oder Probleme beim Schreiben von Code wie dem oben genannten haben.

Es gibt zwei Arten von Diff-Zielen

Es gibt zwei Arten von Diff-Zielen in Git.

Mit der Git-Datenbank können Sie eine komprimierte Datei mit dem Hash-Wert der Datei abrufen, bei der es sich um ein Blob-Objekt handelt. git add Mit anderen Worten, wenn Sie inszenieren, wird es aus der geänderten Datei berechnet und erstellt und im Index registriert. Sie können es auch mit dem Befehl git hash-object -w erstellen.

DiffFormatter ist ein Paar ContentSource für diff. .Pair](http://download.eclipse.org/jgit/site/4.8.0.201706111038-r/apidocs/org/eclipse/jgit/diff/ContentSource.Pair.html). Abhängig von den beiden Arten von Diff-Zielen gibt es zwei Möglichkeiten, eine ContentSource zu erstellen.

Wenn jedoch "format (DiffEntry ent)" ausgeführt wird, sind beide ContentSource.Pair ContentSource für Blob-Objekte. Und die Änderungen des Arbeitsbereichs, die nicht bereitgestellt wurden (geänderte Dateien), sind nicht als Blob-Objekte in der Git-Datenbank vorhanden.

Das Ergebnis ist eine org.eclipse.jgit.errors.MissingObjectException. Dies ist auch bei der Methode "FileHeader to FileHeader (DiffEntry ent)" der Fall.

In einem solchen Fall lautet der Code innerhalb von "git.diff (). Call ()" wie folgt (ohne Urteil und andere). Wenn Sie dasselbe tun, wird es normal an OutputStream ausgegeben.

        fmt.setRepository(repository)
        final AbstractTreeIterator oldTree = new DirCacheIterator(repository.readDirCache());
        final AbstractTreeIterator newTree = new FileTreeIterator(repository);
        fmt.scan(oldTree, newTree);

Dieser [List <DiffEntry> -Scan (AbstractTreeIterator a, AbstractTreeIterator b)](http://download.eclipse.org/jgit/site/4.8.0.201706111038-r/apidocs/org/eclipse/jgit/diff/DiffFormatter. Die HTML-Methode # scan-org.eclipse.jgit.treewalk.AbstractTreeIterator-org.eclipse.jgit.treewalk.AbstractTreeIterator-) ist für diesen Zweck nicht vorhanden, es gibt jedoch eine andere DiffFormatter ContentSource. Es gibt keine Möglichkeit, dies von außen zu ändern.

Um den Diff aus dem DiffEntry des Rückgabewerts von ** git.diff (). Call () auszugeben, wird übrigens die Scanmethode und die Formatmethode von DiffFormatter ** verwendet. Da der Rückgabewert der Scanmethode jedoch auch DiffEntry ist, ist git.diff (). Call () nicht erforderlich, danke.

untracked files

Ich weiß nicht, ob es das beabsichtigte Ergebnis ist oder nicht implementiert, aber der Diff-Befehl von JGit enthält auch ** nicht verfolgte Dateien ** im Diff. Mit anderen Worten, "git.diff (). Call ()", was "git diff" entsprechen sollte, vergleicht das im Index registrierte nicht verfolgte Dateilob-Objekt mit der Arbeitsbereichsdatei, wie es ist.

Befehl old new
git diff Arbeitsbereichsdateien (nicht verfolgte Dateien)außer Im Index registriertes Blob-Objekt
git.diff().call() by JGit Arbeitsbereichsdateien (nicht verfolgte Dateien)Einschließlich Im Index registriertes Blob-Objekt

Ich glaube nicht, dass es viele gibt, wenn Sie Unterschiede sehen möchten und Sie keine nicht verfolgten Dateien sehen möchten, daher denke ich, dass das Verhalten von JGit nicht so problematisch ist. Es ist am besten, es als Option anzugeben.

Das Ausgeben eines Unterschieds von nicht verfolgten Dateien mit dem Befehl git ist etwas mühsam.

git ls-files -o --exclude-standard

Sie können die Liste mit und den Diff mit dem folgenden Befehl abrufen.

git diff --no-index /dev/null [untracked file name]

Seien Sie versichert, dass sogar Windows mit / dev / null verglichen wird. Wenn Sie nur den Unterschied sehen möchten, handelt es sich um eine neue Datei, sodass Sie sich die Datei selbst ansehen können. Im aktuellen Kontext möchte ich ein Diff im Patch-Format, das angewendet werden kann. Deshalb habe ich es hier vorgestellt.

Arbeitsplatz? Arbeitsbaum?

Wenn ich "Works Pace Diff" sage, scheint es seltsam, dass der Diff keine nicht verfolgten Dateien enthält.

Aber ist "Git Diff" überhaupt ein "Arbeitsbereich" und ein Index-Diff? Zumindest ist "Arbeitsbereich" kein Git-Begriff, also Vielleicht ist die Realität, dass Sie durch die Verwendung beliebiger Wörter verwirrt sind.

Das Wort Arbeitsbereich wird in der offiziellen Dokumentation selten verwendet. https://git-scm.com/search/results?search=workspace https://git-scm.com/search/results?search=work%20space

Das Wort Arbeitsbaum wird häufig verwendet. https://git-scm.com/search/results?search=worktree https://git-scm.com/search/results?search=work%20tree

Dies ist eine Herausforderung, da wir nicht genau wissen, was das Wort Arbeitsbaum bedeutet.

apply

ApplyCommand und git apply --cached

** Die Schlussfolgerung, die ich in der vorherigen Ausgabe erhalten habe, lautete: "Um in Linieneinheiten zu inszenieren, erstellen Sie einen Patch, der die Änderungen der Linieneinheiten widerspiegelt, und" git apply --cached "" **. (Git apply -R --cached für zeilenweise Unstage.)

Wie DiffCommand for diff hat apply ApplyCommand. .. Und die Beschreibung der JavaDoc-Klasse lautet:

Apply a patch to files and/or to the index.

ApplyCommand kann jedoch keinen Patch auf den Index anwenden. Es ist nicht von Dose. Im Gegensatz zu DiffCommand gibt es keine Methode wie setCached (). Auch wenn Sie sich [Quelle] ansehen (https://github.com/eclipse/jgit/blob/6dab29f4b578bc164acb77083440e4087ed94ff4/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java#L2) Es schien, als würde ich nur eine Datei schreiben und Berechtigungen festlegen.

https://github.com/eclipse/jgit/blob/6dab29f4b578bc164acb77083440e4087ed94ff4/org.eclipse.jgit/src/org/eclipse/jgit/api/ApplyCommand.java#L262


		FileWriter fw = new FileWriter(f);
		fw.write(sb.toString());
		fw.close();

		getRepository().getFS().setExecute(f, fh.getNewMode() == FileMode.EXECUTABLE_FILE);

Ich war beunruhigt.

Git gilt bisher als Zusammenstellung

Ich habe bestätigt, dass ich dies nur mit "Patch auf Dateien anwenden" durch das folgende Verfahren tun kann.

  1. Ändern Sie die Datei
  2. Erstellen Sie einen Patch
  3. Dateiänderungen rückgängig machen
  4. Übergeben Sie den Patch an ApplyCommand

Verwenden Sie in Schritt 2 DiffCommand, um in eine Datei auszugeben, und übergeben Sie in Schritt 4 die Datei an ApplyCommand. Bisher ist es eine Zusammenstellung.

AddCommand und ResetCommand

Git add, um die Phase für jede Datei auszuführen, entspricht AddCommand Es gibt .html). Es ist schwer zu glauben, dass es überhaupt mehr als "git add" gibt. JGit ist keine vollständige Kopie von git. Wenn Sie sich also die Methodenliste ansehen, während Sie sie erwarten, Es besteht die leichte Hoffnung, dass die Leistung von WorkingTreeIterator, die an "AddCommand setWorkingTreeIterator (WorkingTreeIterator f)" übergeben wurde, irgendwie verwaltet werden kann. ResetCommand verfügt jedoch nicht über eine ähnliche Methode. Lass uns anhalten.

Ich habe versucht, eine Datei zu finden, die ernsthaft so aussah, aber ich konnte sie nicht finden. Es war eine kurze Beziehung, aber es scheint, dass es Zeit ist, sich von JGit zu verabschieden.

CRLF

Ein weiterer Punkt vor dem Abschied.

Normalerweise (?) In einer Windows-Umgebung wird eine CRLF unterbrochen.

Setzen Sie dann die autocrlf-Funktion auf true, schreiben Sie mit LF fest und rufen Sie mit CRLF remote ab. Das sollte offiziell empfohlen werden. Ich denke, es gab eine Empfehlung im Installationsprogramm. (Es ist jedoch ärgerlich, da Sie manchmal als LF abrufen möchten.)

JGit prüft vor der Anwendung, ob der Arbeitsbereich und der Patch der Situation entsprechen sollen. Es scheint, dass CRLF bei diesem Vergleich nicht berücksichtigt wird und jede Zeile so interpretiert wird, dass sie am Ende eine CR aufweist. cr.PNG Und da nicht jede Zeile übereinstimmt, wird org.eclipse.jgit.api.errors.PatchApplyException ausgelöst.

Wenn der Patch selbst auf CRLF eingestellt ist, wird er nicht als gültiger Patch erkannt. Dies ist auch beim Befehl git der Fall Es scheint, dass CL richtig ist.

Hinweis zur nächsten Ausgabe

git.exe

Es gibt auch eine Möglichkeit, eine Reise zu unternehmen, um die höchste Bibliothek zu erkunden. Nicht auf JGit beschränkt, sondern auch an libgit2 und andere Bibliotheken gebunden Möglicherweise treten Probleme mit mangelnder Funktionalität auf. Daher werden wir ab der nächsten Ausgabe git.exe verwenden, eine Git-Anwendung mit den besten Funktionen. Der Umgang mit unterschiedlichen Prozessen kann Herausforderungen mit sich bringen. Es scheint, dass Sie in der Lage sein werden, Kenntnisse zu erwerben, die in anderen Sprachen und Umgebungen verstanden werden können.

workaround

Überraschenderweise (?) Weiß ich nicht, ob es sich um einen Fehler oder eine Spezifikation handelt. Ob es der git-Befehl oder die git-gui ist, die mit dem git selbst geliefert wird Es gibt einige Muster, die mir gerade aufgefallen sind und die nicht normal inszeniert / nicht inszeniert werden können.

In der nächsten Ausgabe werden hauptsächlich diese Probleme vorgestellt und umgangen.

Vielleicht macht die Welt nicht zeilenweise Bühnen / Bühnen. Dann macht es Sinn, es selbst zu machen.

Anmerkung der Redaktion

Ich habe es gespürt, bevor ich die vorherige Ausgabe "Basic Knowledge" geschrieben habe. Je häufiger Sie den Befehl git verwenden, desto besser sind Sie mit der CLI vertraut. Beachten Sie, dass einige Leute die Motivation verlieren, einen Git-GUI-Client zu erstellen.

Recommended Posts

Erstellen Sie einen wöchentlichen Git-GUI-Client [2] für eine unvollständige Erfassung
Erstellen Sie einen wöchentlichen Git-GUI-Client [4] diff et al.
Erstellen Sie einen wöchentlichen Git-GUI-Client. [5] Erste Desktop-App