English ▾ Themen ▾ Neueste Version ▾ git-read-tree zuletzt aktualisiert in 2.52.0

NAME

git-read-tree - Liest Baum-Informationen in den Index ein

SYNOPSIS

git read-tree [(-m [--trivial] [--aggressive] | --reset | --prefix=<prefix>)
		[-u | -i]] [--index-output=<file>] [--no-sparse-checkout]
		(--empty | <tree-ish1> [<tree-ish2> [<tree-ish3>]])

BESCHREIBUNG

Liest die Baum-Informationen von <tree-ish> in den Index ein, ohne jedoch tatsächlich Dateien zu "cachen" oder zu aktualisieren. (Siehe: git-checkout-index[1])

Optional kann es einen Baum in den Index einfügen, einen Fast-Forward (d.h. 2-Wege)-Merge oder einen 3-Wege-Merge mit dem Flag -m durchführen. Wenn -m verwendet wird, bewirkt das Flag -u, dass auch die Dateien im Arbeitsverzeichnis mit dem Ergebnis des Merges aktualisiert werden.

Nur triviale Merges werden von git read-tree selbst durchgeführt. Nur widersprüchliche Pfade werden in einem unmerged Zustand sein, wenn git read-tree zurückkehrt.

OPTIONEN

-m

Führt einen Merge durch, nicht nur ein Einlesen. Der Befehl wird sich weigern zu laufen, wenn Ihre Indexdatei unmerged Einträge hat, was darauf hinweist, dass Sie einen vorher begonnenen Merge nicht beendet haben.

--reset

Gleich wie -m, außer dass unmerged Einträge verworfen werden, anstatt fehlzuschlagen. Wenn mit -u verwendet, werden Updates, die zum Verlust von Arbeitsverzeichnis-Änderungen oder nicht nachverfolgten Dateien oder Verzeichnissen führen, die Operation nicht abbrechen.

-u

Nach einem erfolgreichen Merge, aktualisiert die Dateien im Arbeitsverzeichnis mit dem Ergebnis des Merges.

-i

Normalerweise erfordert ein Merge, dass die Indexdatei sowie die Dateien im Arbeitsverzeichnis auf dem neuesten Stand des aktuellen Head-Commits sind, um lokale Änderungen nicht zu verlieren. Dieses Flag deaktiviert die Prüfung des Arbeitsverzeichnisses und ist für die Erstellung eines Merges von Bäumen gedacht, die nicht direkt mit dem aktuellen Status des Arbeitsverzeichnisses in Beziehung stehen, in eine temporäre Indexdatei.

-n
--dry-run

Prüft, ob der Befehl fehlschlagen würde, ohne den Index oder die Dateien im Arbeitsverzeichnis tatsächlich zu aktualisieren.

-v

Zeigt den Fortschritt beim Auschecken von Dateien an.

--trivial

Beschränkt den Drei-Wege-Merge durch git read-tree auf Fälle, in denen keine Datei-Level-Merges erforderlich sind, anstatt triviale Fälle zu lösen und widersprüchliche Dateien ungelöst im Index zu lassen.

--aggressive

Normalerweise löst ein Drei-Wege-Merge durch git read-tree sehr triviale Fälle und lässt andere Fälle ungelöst im Index, damit Porzellane unterschiedliche Merge-Richtlinien implementieren können. Dieses Flag bewirkt, dass der Befehl intern einige weitere Fälle löst

  • wenn eine Seite einen Pfad entfernt und die andere Seite den Pfad unverändert lässt. Die Auflösung besteht darin, diesen Pfad zu entfernen.

  • wenn beide Seiten einen Pfad entfernen. Die Auflösung besteht darin, diesen Pfad zu entfernen.

  • wenn beide Seiten einen Pfad identisch hinzufügen. Die Auflösung besteht darin, diesen Pfad hinzuzufügen.

--prefix=<präfix>

Behält den aktuellen Indexinhalt bei und liest den Inhalt des benannten Tree-ish unter dem Verzeichnis unter <präfix> ein. Der Befehl wird sich weigern, Einträge zu überschreiben, die bereits in der ursprünglichen Indexdatei vorhanden waren.

--index-output=<datei>

Anstatt die Ergebnisse in $GIT_INDEX_FILE zu schreiben, wird der resultierende Index in die benannte Datei geschrieben. Während der Befehl arbeitet, wird die ursprüngliche Indexdatei mit demselben Mechanismus wie üblich gesperrt. Die Datei muss es ermöglichen, sie aus einer temporären Datei, die neben der üblichen Indexdatei erstellt wird, per rename(2) umzubenennen; typischerweise bedeutet dies, dass sie sich im selben Dateisystem wie die Indexdatei befindet und Sie Schreibrechte für die Verzeichnisse haben, in denen sich die Indexdatei und die Index-Ausgabedatei befinden.

--recurse-submodules
--no-recurse-submodules

Die Verwendung von --recurse-submodules aktualisiert den Inhalt aller aktiven Submodule gemäß dem im Superprojekt aufgezeichneten Commit, indem read-tree rekursiv aufgerufen wird, und setzt den HEAD der Submodule auf diesen Commit. Dies löst auch die Submodule auf und setzt sie auf diesen Commit.

--no-sparse-checkout

Deaktiviert die Unterstützung für Sparse Checkout, auch wenn core.sparseCheckout true ist.

--empty

Anstatt Objekt(e) vom Typ Baum in den Index einzulesen, leert ihn einfach.

-q
--quiet

Leise, unterdrückt Feedback-Meldungen.

<tree-ish#>

Die ID des/der Baum-Objekt(e), die/der eingelesen/zusammengeführt werden soll.

ZUSAMMENFÜHREN

Wenn -m angegeben ist, kann git read-tree 3 Arten von Merges durchführen: einen einzelnen Baum-Merge, wenn nur 1 Baum gegeben ist, einen Fast-Forward-Merge mit 2 Bäumen oder einen 3-Wege-Merge, wenn 3 oder mehr Bäume bereitgestellt werden.

Single Tree Merge

Wenn nur 1 Baum angegeben ist, verhält sich git read-tree so, als ob der Benutzer nicht -m angegeben hätte, mit dem Unterschied, dass, wenn der ursprüngliche Index einen Eintrag für einen bestimmten Pfadnamen hat und die Inhalte des Pfads mit dem eingelesenen Baum übereinstimmen, die Stat-Informationen aus dem Index verwendet werden. (Anders ausgedrückt: Die Stat()s des Index haben Vorrang vor denen des gemergten Baums).

Das bedeutet, dass, wenn Sie einen git read-tree -m <newtree> ausführen, gefolgt von einem git checkout-index -f -u -a, git checkout-index nur die Dinge auscheckt, die sich wirklich geändert haben.

Dies dient dazu, unnötige Fehlalarme zu vermeiden, wenn git diff-files nach git read-tree ausgeführt wird.

Two Tree Merge

Typischerweise wird dies als git read-tree -m $H $M aufgerufen, wobei $H der Head-Commit des aktuellen Repositories ist und $M der Head eines externen Baums, der einfach vor $H liegt (d.h. wir sind in einer Fast-Forward-Situation).

Wenn zwei Bäume angegeben sind, teilt der Benutzer git read-tree Folgendes mit:

  1. Der aktuelle Index und das Arbeitsverzeichnis leiten sich von $H ab, aber der Benutzer hat möglicherweise seit $H lokale Änderungen daran vorgenommen.

  2. Der Benutzer möchte zu $M vorspulen (fast-forward).

In diesem Fall stellt der Befehl git read-tree -m $H $M sicher, dass keine lokale Änderung als Ergebnis dieses "Merges" verloren geht. Hier sind die "Carry Forward"-Regeln, wobei "I" den Index bezeichnet, "clean" bedeutet, dass Index und Arbeitsverzeichnis übereinstimmen, und "exists"/"nothing" sich auf die Anwesenheit eines Pfades im angegebenen Commit beziehen

	I                   H        M        Result
       -------------------------------------------------------
     0  nothing             nothing  nothing  (does not happen)
     1  nothing             nothing  exists   use M
     2  nothing             exists   nothing  remove path from index
     3  nothing             exists   exists,  use M if "initial checkout",
				     H == M   keep index otherwise
				     exists,  fail
				     H != M

        clean I==H  I==M
       ------------------
     4  yes   N/A   N/A     nothing  nothing  keep index
     5  no    N/A   N/A     nothing  nothing  keep index

     6  yes   N/A   yes     nothing  exists   keep index
     7  no    N/A   yes     nothing  exists   keep index
     8  yes   N/A   no      nothing  exists   fail
     9  no    N/A   no      nothing  exists   fail

     10 yes   yes   N/A     exists   nothing  remove path from index
     11 no    yes   N/A     exists   nothing  fail
     12 yes   no    N/A     exists   nothing  fail
     13 no    no    N/A     exists   nothing  fail

	clean (H==M)
       ------
     14 yes                 exists   exists   keep index
     15 no                  exists   exists   keep index

        clean I==H  I==M (H!=M)
       ------------------
     16 yes   no    no      exists   exists   fail
     17 no    no    no      exists   exists   fail
     18 yes   no    yes     exists   exists   keep index
     19 no    no    yes     exists   exists   keep index
     20 yes   yes   no      exists   exists   use M
     21 no    yes   no      exists   exists   fail

In allen Fällen "Keep Index" bleibt der Indexeintrag wie in der ursprünglichen Indexdatei. Wenn der Eintrag nicht aktuell ist, behält git read-tree die Kopie im Arbeitsverzeichnis intakt, wenn es unter dem Flag -u operiert.

Wenn diese Form von git read-tree erfolgreich zurückkehrt, können Sie sehen, welche der von Ihnen vorgenommenen "lokalen Änderungen" übernommen wurden, indem Sie git diff-index --cached $M ausführen. Beachten Sie, dass dies nicht unbedingt dem entspricht, was git diff-index --cached $H vor einem solchen Zwei-Baum-Merge ergeben hätte. Dies liegt an den Fällen 18 und 19 – wenn Sie die Änderungen bereits in $M hatten (z. B. per E-Mail in Patch-Form erhalten), hätte git diff-index --cached $H Sie vor diesem Merge über die Änderung informiert, aber sie würde nach dem Zwei-Baum-Merge nicht in der Ausgabe von git diff-index --cached $M erscheinen.

Fall 3 ist etwas knifflig und bedarf einer Erklärung. Das Ergebnis dieser Regel sollte logischerweise das Entfernen des Pfads sein, wenn der Benutzer die Entfernung des Pfads gestaged hat und dann zu einem neuen Branch wechselt. Das würde jedoch den anfänglichen Checkout verhindern, daher wird die Regel modifiziert, um M (neuer Baum) nur dann zu verwenden, wenn der Inhalt des Index leer ist. Andernfalls bleibt die Entfernung des Pfads erhalten, solange $H und $M gleich sind.

3-Way Merge

Jeder "Index"-Eintrag hat zwei Bits für den "Stage"-Status. Stage 0 ist der normale, und ist der einzige, den Sie in irgendeiner normalen Verwendung sehen würden.

Wenn Sie jedoch git read-tree mit drei Bäumen verwenden, beginnt der "Stage" bei 1.

Das bedeutet, dass Sie Folgendes tun können:

$ git read-tree -m <tree1> <tree2> <tree3>

und Sie erhalten einen Index mit allen Einträgen von <tree1> in "Stage 1", allen Einträgen von <tree2> in "Stage 2" und allen Einträgen von <tree3> in "Stage 3". Beim Mergen eines anderen Branches in den aktuellen Branch verwenden wir den Baum des gemeinsamen Vorfahren als <tree1>, den aktuellen Branch-Head als <tree2> und den Head des anderen Branches als <tree3>.

Darüber hinaus hat git read-tree spezielle Logik, die besagt: Wenn eine Datei in allen drei Bäumen in den folgenden Zuständen übereinstimmt, "kollabiert" sie zurück zu "Stage 0".

  • Stage 2 und 3 sind identisch; nehmen Sie eine davon (es macht keinen Unterschied - die gleiche Arbeit wurde in unserem Branch in Stage 2 und ihrem Branch in Stage 3 geleistet)

  • Stage 1 und Stage 2 sind identisch und Stage 3 ist unterschiedlich; nehmen Sie Stage 3 (unser Branch in Stage 2 hat seit dem Vorfahren in Stage 1 nichts getan, während ihr Branch in Stage 3 daran gearbeitet hat)

  • Stage 1 und Stage 3 sind identisch und Stage 2 ist unterschiedlich; nehmen Sie Stage 2 (wir haben etwas getan, während sie nichts getan haben)

Der Befehl git write-tree weigert sich, einen unsinnigen Baum zu schreiben, und beschwert sich über unmerged Einträge, wenn er einen einzelnen Eintrag sieht, der nicht Stage 0 ist.

OK, das klingt alles wie eine Sammlung völlig unsinniger Regeln, aber es ist tatsächlich genau das, was Sie wollen, um einen schnellen Merge durchzuführen. Die verschiedenen Stages repräsentieren den "Ergebnisbaum" (Stage 0, auch "merged" genannt), den ursprünglichen Baum (Stage 1, auch "orig" genannt) und die beiden Bäume, die Sie zusammenführen möchten (Stage 2 bzw. 3).

Die Reihenfolge der Stages 1, 2 und 3 (daher die Reihenfolge der drei <tree-ish> Kommandozeilenargumente) ist signifikant, wenn Sie einen 3-Wege-Merge mit einer bereits gefüllten Indexdatei starten. Hier ist eine Übersicht, wie der Algorithmus funktioniert.

  • Wenn eine Datei in allen drei Bäumen im identischen Format existiert, wird sie von git read-tree automatisch in den "merged"-Zustand überführt.

  • Eine Datei, die sich in irgendeiner Weise in den drei Bäumen unterscheidet, bleibt als separate Einträge im Index erhalten. Es liegt an der "Porcelain-Richtlinie", festzulegen, wie die Nicht-0-Stages entfernt und eine zusammengeführte Version eingefügt werden.

  • Die Indexdatei speichert und stellt all diese Informationen wieder her, sodass Sie Merges inkrementell durchführen können, aber solange sie Einträge in den Stages 1/2/3 hat (d. h. "unmerged Einträge"), können Sie das Ergebnis nicht schreiben. Der Merge-Algorithmus ist also wirklich einfach.

    • Sie durchlaufen den Index in Ordnung und ignorieren alle Einträge der Stage 0, da diese bereits erledigt sind.

    • Wenn Sie eine "Stage 1" finden, aber keine übereinstimmende "Stage 2" oder "Stage 3", wissen Sie, dass sie aus beiden Bäumen entfernt wurde (sie existierte nur im ursprünglichen Baum), und Sie entfernen diesen Eintrag.

    • Wenn Sie einen übereinstimmenden "Stage 2" und "Stage 3" Baum finden, entfernen Sie einen davon und wandeln Sie den anderen in einen "Stage 0" Eintrag um. Entfernen Sie auch einen übereinstimmenden "Stage 1" Eintrag, falls vorhanden. .. all die normalen trivialen Regeln ..

Normalerweise würden Sie git merge-index mit einem bereitgestellten git merge-one-file verwenden, um diesen letzten Schritt durchzuführen. Das Skript aktualisiert die Dateien im Arbeitsverzeichnis, während es jeden Pfad zusammenführt, und am Ende eines erfolgreichen Merges.

Wenn Sie einen 3-Wege-Merge mit einer bereits gefüllten Indexdatei starten, wird davon ausgegangen, dass diese den Zustand der Dateien in Ihrem Arbeitsverzeichnis repräsentiert, und Sie können sogar Dateien mit Änderungen haben, die nicht im Index erfasst sind. Es wird ferner davon ausgegangen, dass dieser Zustand vom Stage 2-Baum abgeleitet ist. Der 3-Wege-Merge weigert sich zu laufen, wenn er einen Eintrag in der ursprünglichen Indexdatei findet, der nicht mit Stage 2 übereinstimmt.

Dies geschieht, um zu verhindern, dass Sie Ihre Work-in-Progress-Änderungen verlieren und Ihre zufälligen Änderungen in einen nicht zusammenhängenden Merge-Commit einbringen. Zur Veranschaulichung, nehmen wir an, Sie starten von dem, was zuletzt in Ihrem Repository committet wurde.

$ JC=`git rev-parse --verify "HEAD^0"`
$ git checkout-index -f -u -a $JC

Sie nehmen zufällige Bearbeitungen vor, ohne git update-index auszuführen. Und dann bemerken Sie, dass die Spitze Ihres "upstream"-Baums seit dem letzten Pull fortgeschritten ist.

$ git fetch git://.... linus
$ LT=`git rev-parse FETCH_HEAD`

Ihr Arbeitsverzeichnis basiert immer noch auf Ihrem HEAD ($JC), aber Sie haben einige Bearbeitungen seitdem. Der Drei-Wege-Merge stellt sicher, dass Sie seit $JC keine Indexeinträge hinzugefügt oder geändert haben und führt dann, wenn nicht, das Richtige durch. Also mit der folgenden Sequenz

$ git read-tree -m -u `git merge-base $JC $LT` $JC $LT
$ git merge-index git-merge-one-file -a
$ echo "Merge with Linus" | \
  git commit-tree `git write-tree` -p $JC -p $LT

würde das, was Sie committen, ein reiner Merge zwischen $JC und $LT ohne Ihre Work-in-Progress-Änderungen sein, und Ihr Arbeitsverzeichnis würde auf das Ergebnis des Merges aktualisiert.

Wenn Sie jedoch lokale Änderungen im Arbeitsverzeichnis haben, die durch diesen Merge überschrieben würden, weigert sich git read-tree zu laufen, um den Verlust Ihrer Änderungen zu verhindern.

Mit anderen Worten, Sie müssen sich keine Sorgen machen, was nur im Arbeitsverzeichnis existiert. Wenn Sie lokale Änderungen in einem Teil des Projekts haben, der nicht am Merge beteiligt ist, stören Ihre Änderungen den Merge nicht und bleiben erhalten. Wenn sie sich **doch** stören, beginnt der Merge gar nicht erst (git read-tree meckert laut und schlägt fehl, ohne etwas zu ändern). In einem solchen Fall können Sie einfach fortfahren, was Sie gerade getan haben, und wenn Ihr Arbeitsverzeichnis bereit ist (d. h. Sie Ihre Arbeit abgeschlossen haben), versuchen Sie den Merge erneut.

SPARSER CHECKOUT

Hinweis: Die skip-worktree-Funktionen in git-update-index[1] und read-tree existierten vor der Einführung von git-sparse-checkout[1]. Benutzer werden ermutigt, den Befehl sparse-checkout anstelle dieser Plumbing-Befehle für Sparse-Checkout/skip-worktree-bezogene Bedürfnisse zu verwenden. Die untenstehenden Informationen können jedoch für Benutzer nützlich sein, die versuchen, den Musterstil zu verstehen, der im Nicht-Kegel-Modus des sparse-checkout-Befehls verwendet wird.

"Sparse Checkout" ermöglicht das spärliche Befüllen des Arbeitsverzeichnisses. Es verwendet das skip-worktree-Bit (siehe git-update-index[1]), um Git mitzuteilen, ob eine Datei im Arbeitsverzeichnis relevant ist.

git read-tree und andere merge-basierte Befehle (git merge, git checkout...) können beim Verwalten der skip-worktree-Bitmap und der Aktualisierung des Arbeitsverzeichnisses helfen. $GIT_DIR/info/sparse-checkout wird verwendet, um die skip-worktree-Referenz-Bitmap zu definieren. Wenn git read-tree das Arbeitsverzeichnis aktualisieren muss, setzt es das skip-worktree-Bit im Index basierend auf dieser Datei zurück, die dieselbe Syntax wie .gitignore-Dateien verwendet. Wenn ein Eintrag einem Muster in dieser Datei entspricht oder der Eintrag einer Datei entspricht, die im Arbeitsverzeichnis vorhanden ist, dann wird skip-worktree auf diesen Eintrag nicht gesetzt. Andernfalls wird skip-worktree gesetzt.

Dann vergleicht es den neuen skip-worktree-Wert mit dem vorherigen. Wenn skip-worktree von gesetzt auf nicht gesetzt wechselt, wird die entsprechende Datei wieder hinzugefügt. Wenn es von nicht gesetzt auf gesetzt wechselt, wird diese Datei entfernt.

Während $GIT_DIR/info/sparse-checkout normalerweise verwendet wird, um anzugeben, welche Dateien enthalten sind, können Sie auch angeben, welche Dateien *nicht* enthalten sind, indem Sie Negativmuster verwenden. Zum Beispiel, um die Datei unwanted zu entfernen.

/*
!unwanted

Eine weitere knifflige Sache ist das vollständige Wiederbefüllen des Arbeitsverzeichnisses, wenn Sie kein Sparse Checkout mehr wünschen. Sie können "Sparse Checkout" nicht einfach deaktivieren, da skip-worktree-Bits immer noch im Index vorhanden sind und Ihr Arbeitsverzeichnis immer noch spärlich gefüllt ist. Sie sollten das Arbeitsverzeichnis mit dem Inhalt der Datei $GIT_DIR/info/sparse-checkout wie folgt wieder auffüllen.

/*

Dann können Sie Sparse Checkout deaktivieren. Sparse Checkout-Unterstützung in git read-tree und ähnlichen Befehlen ist standardmäßig deaktiviert. Sie müssen core.sparseCheckout aktivieren, um Sparse Checkout-Unterstützung zu haben.

GIT

Teil der git[1] Suite