(Zaczęło się to jako odpowiedź na zduplikowane pytanie. Przeprowadziłem trochę lekkiej edycji, aby je oczyścić).
Wszystkie wewnętrzne strzałki Gita są jednokierunkowe, skierowane do tyłu. Dlatego nie ma krótkiej wygodnej składni do poruszania się do przodu: to po prostu niemożliwe.
Możliwe jest „poruszanie się przeciw strzałom”, ale sposób na zrobienie tego jest zaskakujący, jeśli nie widziałeś go wcześniej, a potem oczywisty później. Powiedzmy, że mamy:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
Używanie middle~2
następuje dwukrotnie zgodnie ze strzałkami od C
tyłu do A
. Więc jak możemy przenieść C
się D
? Odpowiedź brzmi: zaczynamy od E
, używając nazwy last
i pracujemy wstecz, aż do niej dojdziemy middle
, rejestrując punkty, które odwiedzamy po drodze . Następnie poruszamy się tak daleko, jak chcemy, w kierunku last
: przesuń się o jeden krok D
lub dwa do E
.
Jest to szczególnie ważne, gdy mamy oddziały:
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
Który zatwierdzenie jest krok po kroku C
? Nie ma poprawnej odpowiedzi, dopóki nie dodasz do pytania: w kierunku cechy___ (wypełnij puste pole).
Aby wyliczyć commits pomiędzy C
(wykluczając C
) samą i, powiedzmy, G
używamy:
git rev-list --topo-order --ancestry-path master..feature2
W --topo-order
gwarantuje, że nawet w obecności złożonego rozgałęzienia i-łączących się commity wyjdzie w topologicznie-posortowanych. Jest to wymagane tylko wtedy, gdy łańcuch nie jest liniowy. Te --ancestry-path
środki ograniczające że gdy pracujemy z tyłu feature2
, tylko commity list, które mają zobowiązać C
jako jeden z ich własnych przodków. To znaczy, jeśli wykres - lub jego odpowiednia część - faktycznie wygląda tak:
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
prosty wniosek formie feature2..master
wylicza zobowiązuje J
, G
a I
, a F
, a H
w pewnym porządku. Z --ancestry-path
nokautujemy H
i I
: nie są potomkami C
, tylko z A
. Dzięki --topo-order
nam upewnić się, że rzeczywista kolejność jest wyliczenie J
, potem G
, potem F
.
git rev-list
Komenda wycieki tych identyfikatorów hash na standardowe wyjście, po jednej w wierszu. Aby przejść o krok do przodu w kierunku feature2
, chcemy tylko ostatniej linii.
Jest możliwe (i kuszące i może być użyteczne) dodawanie, --reverse
dzięki czemu git rev-list
po wygenerowaniu drukuje zatwierdzenia w odwrotnej kolejności. To działa, ale jeśli używasz go w potoku takim jak ten:
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
aby uzyskać „następny zatwierdzenie w kierunku id2”, a istnieje bardzo długa lista zatwierdzeń, git rev-list
polecenie może uzyskać zepsuty potok, gdy próbuje zapisać, do head
którego przestał czytać dane wejściowe i zakończył działanie. Ponieważ błędy w potokach są zwykle ignorowane przez powłokę, działa to głównie. Tylko upewnij się, że są ignorowane w twoim użyciu.
Kuszące jest także dodanie -n 1
do git rev-list
polecenia wraz z --reverse
. Nie rób tego! To git rev-list
zatrzymuje się po przejściu o jeden krok wstecz , a następnie odwróceniu (jednopunktowej) listy odwiedzonych zatwierdzeń. Tak powstaje za <id2>
każdym razem.
Ważna uwaga dodatkowa
Zauważ, że w przypadku fragmentów graficznych „diament” lub „pierścień benzenowy”:
I--J
/ \
...--H M--... <-- last
\ /
K--L
przesunięcie jednego zatwierdzenia „do przodu” z w H
kierunku last
spowoduje albo I
albo K
. Nic nie możesz na to poradzić: oba zobowiązania są o krok do przodu! Jeśli następnie zaczniesz od wynikowego zatwierdzenia i przejdziesz do następnego kroku, jesteś teraz zaangażowany w dowolną ścieżkę, którą zacząłeś.
Lekarstwem na to jest unikanie przemieszczania się o krok i blokowanie łańcuchów zależnych od ścieżki. Zamiast tego, jeśli planujesz odwiedzić cały łańcuch ścieżki przodków, zanim zrobisz cokolwiek innego , utwórz pełną listę wszystkich zatwierdzeń w łańcuchu:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
Następnie odwiedzaj każdy zatwierdzenie na tej liście, pojedynczo, a otrzymasz cały łańcuch. --topo-order
Zadba trafisz I
-i- J
w tej kolejności, a K
-i- L
w tej kolejności (choć nie ma łatwego sposobu, aby przewidzieć, czy zrobisz parę IJ przed lub po parę KL).