Рассмотрим следующую картину:
I <-J
/
... <-G <-H
\
K <-L
Вышеприведенное представляет коммиты Git - H
обозначает какой-то большой некрасивый хеш-идентификатор, как и G
, I
и так далее. (Примечание: строки от K
до H
и от I
до H
должны указывать влево / назад, как и другие, но у меня нет хороших символов со стрелками, которые работают в любой системе, и Я рисую это с текстом вместо графики.)
Причина, по которой вы можете легко вернуться назад, заключается в том, что коммит H
содержит большой уродливый идентификатор хеша коммита G
. Мы говорим, что H
указывает на G
. Поэтому, если вы стоите на H
и запускаете git log
, Git показывает вам H
, затем G
, затем все, что предшествует G
(вероятно, F
), и т. Д.
Вы хотите пойти другим путем. Но ... в каком направлении это это? Есть два пути вперед, ни один из которых Git не сможет легко найти для вас. Один идет к I
, а затем J
. Другой идет к K
, а затем L
.
То, что вы можете сделать, это выбрать более позднюю начальную точку - конечную точку? Git может сделать это легко благодаря встроенным стрелкам, направленным назад от каждого коммита.
Когда у вас Git работает в обратном направлении, Git, в конце концов, придет к какому-то коммиту, чей родитель H
. Это «прямой» коммит в направлении конечной точки, которую вы выбрали . Конечно, это не другой форвардный коммит.
Основная проблема здесь заключается в том, что может быть много конечных точек, из которых только несколько, если таковые имеются, ведут к H
:
...--G--H--o <-- master
\
J--o--o <-- develop
\
o--o <-- feature
Мы называем эти конечные точки ветви , или, точнее, имена ветвей . Имя указывает на коммит tip . Каждый коммит слева - независимо от того, в какой строке он находится - находится в этой ветви, что означает, что на этом графике коммит G
находится в каждой ветви. Коммит J
включен и develop
и feature
.
Выберите название ветви, которое, по вашему мнению, в конечном итоге приведет вас туда, где вы сейчас находитесь. Затем попросите Git сделать:
git log --topo-order --ancestry-path HEAD..master
Например,
, чтобы Git начинался с master
и работал в обратном направлении. (HEAD
- это коммит, на котором вы стоите сейчас, на этой карте коммитов и их соединений. Это большая красная точка «вы здесь», и она автоматически перемещается вместе с вами по мере вашего движения о.)
Последовательный последний коммит будет получен сразу после вашего текущего коммита, , если ваш текущий коммит будет достигнут с верхушкой master
. Если нет, то последним коммитом, который получается из этого, является некоторый коммит, достижимый из master
, который не находится в той же ветви (ветвях), которые содержат HEAD
. Например, git log --ancestry-path HEAD..feature
будет перечислять коммиты, начиная с одного feature
пункта, и работая обратно, пока не достигнет J
. С J
, git log
вернется к G
. Это не HEAD
/ H
, но достижимо с H
, поэтому на этом остановится git log
. Это не коммит после H
.
Это означает, что если вы не знаете наверняка, какие ветви содержат H
, вы не будете знать, с чего начать. Так что используйте:
git branch --contains HEAD
, чтобы получить список имен веток, который, когда Git запускает их и работает в обратном направлении, эти ветки содержат commit H
/ HEAD
. Затем вы можете использовать трюк --ancestry-path
, чтобы идти «вперед» в этом направлении (вы все еще действительно идете назад, вы просто останавливаете как раз перед тем, как вы доберетесь до H
).
Если вы нажмете вилку на дороге, вы возьмете ее . Вы возьмете его в направлении конечной точки, которую вы указали. Обратите внимание, что в некоторых случаях это может пропустить некоторые коммиты:
I--J
/ \
...--o--H M--N <-- branch
\ /
K--L
Moving «вперед» с H
до N
, вы либо идете I-J-M-N, либо K-L-M-N. В любом случае вы можете забыть посетить два, которые вы пропустили. Так что будьте осторожны с этим.
Использование git rev-list
Зачастую вы не хотите просматривать весь вывод git log
здесь. Есть несколько коротких путей, но помните, если / когда вы используете их, вы можете потерять на внутренних структурах ветвления и слияния, таких как кольцо, нарисованное выше. В любом случае, git rev-list
делает то же самое, что и git log
, за исключением того, что он просто печатает хэш-идентификаторы. Используя --topo-order --reverse | head -1
, вы можете напечатать список в обратном направлении, а затем удалить все, кроме первого; или используйте его без --reverse
и | tail -1
для того же эффекта. Вы также можете опустить имя HEAD
. Итак:
git checkout $(git rev-list --ancestry-path --topo-order ..branch | tail -1)
переместит вашу отдельную ГОЛОВКУ на один шаг в направлении к branch
, если такой шаг есть.