(Это началось как ответ на дубликат вопроса. Я сделал небольшое редактирование, чтобы очистить его.)
Все внутренние стрелки 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).