(Dies begann als Antwort auf eine doppelte Frage. Ich habe ein wenig Licht bearbeitet, um sie zu bereinigen.)
Alle internen Pfeile von Git sind einseitig und zeigen nach hinten. Es gibt daher keine kurze bequeme Syntax für das Vorwärtsbewegen: Es ist einfach nicht möglich.
Es ist möglich, sich "gegen die Pfeile zu bewegen", aber die Vorgehensweise ist überraschend, wenn Sie es noch nicht gesehen haben und danach offensichtlich. Nehmen wir an, wir haben:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
Mit middle~2
folgt die Pfeile zweimal von C
zurück nach A
. Wie bewegen wir uns von C
nach D
? Die Antwort ist: Wir beginnen bei E
, den Namen mit last
, und die Arbeit nach hinten , bis wir bekommen middle
, das Aufzeichnen der Punkte , die wir auf dem Weg besuchen . Dann bewegen wir uns einfach so weit wie wir wollen in die Richtung last
: einen Schritt nach D
oder zwei nach E
.
Dies ist besonders wichtig, wenn wir Niederlassungen haben:
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
Welches Commit ist einen Schritt später C
? Es gibt keine richtige Antwort, bis Sie der Frage hinzufügen: in Richtung feature___ (füllen Sie die Lücke aus ).
Um die Commits zwischen C
(ohne C
) sich selbst und beispielsweise aufzuzählen G
, verwenden wir:
git rev-list --topo-order --ancestry-path master..feature2
Dies --topo-order
stellt sicher, dass die Commits auch bei komplexen Verzweigungen und Zusammenführungen in topologisch sortierter Reihenfolge ausgeführt werden. Dies ist nur erforderlich, wenn die Kette nicht linear ist. Die --ancestry-path
Einschränkung bedeutet, dass wir, wenn wir rückwärts von arbeiten feature2
, nur Commits auflisten, die Commit C
als einen ihrer eigenen Vorfahren haben. Das heißt, wenn das Diagramm - oder der relevante Teil davon - tatsächlich so aussieht:
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
eine einfache Anfrage des Formulars feature2..master
aufzählt Commits J
, G
und I
, und F
und H
in einer bestimmten Reihenfolge. Mit --ancestry-path
schlagen wir aus H
und I
: Sie sind keine Nachkommen von C
, nur von A
. Mit stellen --topo-order
wir sicher, dass die tatsächliche Aufzählungsreihenfolge J
dann G
, dann ist F
.
Der git rev-list
Befehl verschüttet diese Hash-IDs in seiner Standardausgabe, eine pro Zeile. Um einen Schritt vorwärts in Richtung zu gehen feature2
, wollen wir nur die letzte Zeile.
Das Hinzufügen ist möglich (und verlockend und kann nützlich sein), --reverse
sodass git rev-list
die Commits nach dem Generieren in umgekehrter Reihenfolge gedruckt werden. Dies funktioniert, aber wenn Sie es in einer Pipeline wie dieser verwenden:
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
Um nur das "nächste Commit in Richtung von id2" zu erhalten, und es gibt eine sehr lange Liste von Commits, kann der git rev-list
Befehl eine fehlerhafte Pipe bekommen, wenn er versucht zu schreiben, head
die seine Eingabe nicht mehr gelesen und beendet hat. Da Rohrbruchfehler normalerweise von der Shell ignoriert werden, funktioniert dies meistens. Stellen Sie einfach sicher, dass sie bei Ihrer Verwendung ignoriert werden .
Es ist auch verlockend, -n 1
den git rev-list
Befehl zusammen mit hinzuzufügen --reverse
. Tu es nicht! Dies führt dazu, git rev-list
dass Sie nach einem Schritt zurück anhalten und dann die Liste der besuchten Commits (mit einem Eintrag) umkehren. Das produziert also <id2>
jedes Mal.
Wichtige Randnotiz
Beachten Sie, dass bei "Diamant" - oder "Benzolring" -Graphenfragmente:
I--J
/ \
...--H M--... <-- last
\ /
K--L
Wenn Sie ein Commit "vorwärts" von in H
Richtung bewegen, last
erhalten Sie entweder I
oder K
. Daran können Sie nichts ändern: Beide Commits sind einen Schritt vorwärts! Wenn Sie dann mit dem resultierenden Commit beginnen und einen weiteren Schritt ausführen, werden Sie jetzt auf den Pfad festgelegt, auf dem Sie begonnen haben.
Die Heilung dafür besteht darin, zu vermeiden, dass Sie sich Schritt für Schritt bewegen und in pfadabhängige Ketten geraten. Wenn Sie stattdessen vorhaben, eine gesamte Ahnenpfadkette zu besuchen, bevor Sie etwas anderes tun, erstellen Sie eine vollständige Liste aller Commits in der Kette:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
Besuchen Sie dann jedes Commit in dieser Liste nacheinander, und Sie erhalten die gesamte Kette. Das --topo-order
wird sicherstellen , dass Sie treffen I
-und- J
in dieser Reihenfolge, und K
-und- L
in dieser Reihenfolge (obwohl es keine einfache Möglichkeit , vorherzusagen , ob Sie vor oder nach dem KL Paar das IJ Paar werde tun).