(Це почалося як відповідь на повторне запитання. Я трохи проробив редагування, щоб очистити його.)
Усі внутрішні стрілки 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).