(Це почалося як відповідь на повторне запитання. Я трохи проробив редагування, щоб очистити його.)
Усі внутрішні стрілки Git є односторонніми, спрямовані назад. Тому немає короткого зручного синтаксису для руху вперед: це просто неможливо.
Це є можливим «рухатися проти стріл», але спосіб зробити це дивно , якщо ви ще не бачили його раніше, і потім очевидно після цього. Скажімо, у нас є:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
Використання middle~2
слідує стрілками двічі від C
спини до A
. Отже, як ми переходимо C
до D
? Відповідь: ми починаємо E
, використовуючи ім'я last
, і працюємо назад, поки не дістаємось middle
, записуючи пункти, які ми відвідуємо по дорозі . Тоді ми просто рухаємось, наскільки хочемо, у напрямку last
: рухаємось на один крок D
або два наE
.
Це особливо важливо, коли у нас є філії:
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
Яка фіксація є кроком після C
? Правильної відповіді немає, поки ви не додасте до запитання: у напрямку особливості___ (заповніть пусту).
Для перерахування комітетів між C
(без C
), скажімо G
, ми використовуємо:
git rev-list --topo-order --ancestry-path master..feature2
Забезпечує --topo-order
, що навіть за наявності складних розгалужень та злиття коміти виходять у топологічно відсортованому порядку. Це потрібно лише в тому випадку, якщо ланцюг не лінійний. В --ancestry-path
означає обмеження , що , коли ми працюємо в зворотному напрямку від feature2
, ми тільки список коммітов , які мають зобов'язання в C
якості одного зі своїх предків. Тобто, якщо графік - або його відповідний фрагмент - все-таки виглядає так:
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
простий запит форми feature2..master
перераховує коміти J
, G
і I
, і, F
і H
в певному порядку. З --ancestry-path
вибивають H
і I
: вони не є нащадками C
, тільки A
. З --topo-order
ми впевнені , що фактичний порядок перерахування є J
, то G
, то F
.
git rev-list
Команда розливає ці ідентифікатори хеш на свій стандартний висновок, по одному в рядку. Щоб рухатись на крок вперед в напрямку feature2
, тоді ми просто хочемо останнього рядка.
Можна додати (і спокусливо, і може бути корисно) додати --reverse
так, git rev-list
щоб після їх генерування друкувалися комісії у зворотному порядку. Це працює, але якщо ви використовуєте його в конвеєрі так:
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
щоб просто отримати "наступний фіксатор у напрямку id2", і існує дуже довгий список комітетів, git rev-list
команда може отримати зламану трубку, коли вона намагається написати, до head
якої перестав читати свій вхід і вийшов. Оскільки помилки зламаної труби оболонкою зазвичай ігноруються, це здебільшого працює. Просто переконайтесь, що вони ігноруються у вашому користуванні.
Це також спокусливо додати -n 1
до git rev-list
команди разом з --reverse
. Не робіть цього! Це git rev-list
зупиняється після того, як піти на крок назад , а потім перевернути (одноразовий) список відвідуваних комітетів. Тож це <id2>
щоразу виробляється .
Важлива бічна примітка
Зауважте, що з фрагментами графіка "алмаз" або "бензольне кільце":
I--J
/ \
...--H M--... <-- last
\ /
K--L
переміщаючи один робить «вперед» від в H
сторону last
отримає Вас або I
або K
. З цим нічого не можна зробити: обидва дії - це крок вперед! Якщо ви почнете з отриманого комітету і перейдете до іншого кроку, тепер ви покладете на той шлях, яким ви почали.
Вирішення цього полягає в тому, щоб уникнути переміщення покроково і не замикатися на ланцюгах, залежних від шляху. Натомість, якщо ви плануєте відвідати цілий ланцюжок породних шляхів, перш ніж робити щось інше , складіть повний перелік усіх зобов'язань у ланцюжку:
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
Потім відвідайте кожну комісію в цьому списку, по одному, і ви отримаєте всю ланцюжок. --topo-order
Буде переконатися , що ви потрапили I
-і- J
в такому порядку, і K
-і- L
в такому порядку (хоча немає ніякого простого способу передбачити , чи будете ви зробити пару IJ до або після пари KL).