(Questo è iniziato come una risposta a una domanda duplicata. Ho fatto un po 'di editing leggero per ripulirlo.)
Tutte le frecce interne di Git sono unidirezionali, rivolte all'indietro. Non esiste quindi una sintassi breve per spostarsi in avanti: semplicemente non è possibile.
E ' è possibile "muoversi contro le frecce", ma il modo per farlo è sorprendente se non avete visto prima, e poi evidente in seguito. Diciamo che abbiamo:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
L'utilizzo middle~2
segue le frecce due volte da C
dietro a A
. Quindi come ci spostiamo da C
a D
? La risposta è: iniziamo da E
, usando il nome last
, e lavoriamo all'indietro fino a quando arriviamo middle
, registrando i punti che visitiamo lungo la strada . Quindi ci spostiamo semplicemente nella direzione di last
: muoviamo di un passo verso D
o due verso E
.
Ciò è particolarmente importante quando abbiamo filiali:
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
Quale commit è un passo dopo C
? Non c'è una risposta corretta fino a quando non si aggiunge alla domanda: nella direzione di feature___ (riempire lo spazio vuoto).
Per elencare i commit tra C
(escluso C
) stesso e, diciamo, G
usiamo:
git rev-list --topo-order --ancestry-path master..feature2
Questo --topo-order
assicura che anche in presenza di complesse ramificazioni e fusioni, i commit escano in ordine topologicamente ordinato. Ciò è necessario solo se la catena non è lineare. Il --ancestry-path
vincolo significa che quando lavoriamo a ritroso da feature2
, elenchiamo solo i commit che hanno commesso C
come uno dei loro stessi antenati. Cioè, se il grafico, o comunque il relativo pezzo, in realtà assomiglia a questo:
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
una semplice richiesta del modulo feature2..master
enumera commit J
, G
e I
, e F
e H
in un certo ordine. Con --ancestry-path
knock out H
e I
: non sono discendenti di C
, solo di A
. Con --topo-order
ci assicuriamo che l'attuale ordine di enumerazione sia J
, quindi G
, allora F
.
Il git rev-list
comando distribuisce questi ID hash sull'output standard, uno per riga. Per avanzare di un passo nella direzione di feature2
, quindi, vogliamo solo l' ultima riga.
È possibile (e allettante e può essere utile) aggiungere in --reverse
modo da git rev-list
stampare i commit in ordine inverso dopo averli generati. Questo funziona, ma se lo usi in una pipeline come questa:
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
per ottenere il "prossimo commit nella direzione di id2", e c'è un elenco molto lungo di commit, il git rev-list
comando può ottenere una pipe spezzata quando tenta di scrivere su head
cui ha smesso di leggere il suo input ed è uscito. Dal momento che gli errori di tubo rotto vengono normalmente ignorati dalla shell, questo funziona principalmente. Assicurati solo che siano ignorati nel tuo utilizzo.
È anche allettante aggiungere -n 1
al git rev-list
comando, insieme a --reverse
. Non farlo! Ciò si git rev-list
interrompe dopo aver fatto un passo indietro e quindi invertire l'elenco (una voce) di commit visitati. Quindi questo produce solo <id2>
ogni volta.
Nota a margine importante
Si noti che con i frammenti del grafico "diamante" o "anello benzene":
I--J
/ \
...--H M--... <-- last
\ /
K--L
spostando una commettere "avanti" da H
direzione last
si arriva sia I
o K
. Non c'è niente che tu possa fare al riguardo: entrambi i commit sono un passo avanti! Se poi inizi dal commit risultante e fai un altro passo, ora sei impegnato in qualunque percorso tu abbia iniziato.
La cura per questo è di evitare di muoverti di un passo alla volta e rimanere bloccati in catene dipendenti dal percorso. Invece, se prevedi di visitare un'intera catena di percorsi degli antenati, prima di fare qualsiasi altra cosa , fai un elenco completo di tutti i commit nella catena:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
Quindi, visita ogni commit in questo elenco, uno alla volta, e otterrai l'intera catena. La --topo-order
farà in modo di colpire I
-e- J
in questo ordine, e K
-e- L
in questo ordine (anche se non c'è un modo semplice per prevedere se si farà la coppia IJ prima o dopo la coppia KL).