В чем разница между HEAD^ и HEAD~ в Git?
Когда я указываю объект коммитов предка в Git, я путаюсь между HEAD^
а также HEAD~
,
Оба имеют "нумерованную" версию, как HEAD^3
а также HEAD~2
,
Они кажутся мне очень похожими или одинаковыми, но есть ли различия между тильдой и каретой?
17 ответов
HEAD^
означает первого родителя кончика текущей ветви.
Помните, что коммиты git могут иметь более одного родителя. HEAD^
коротка для HEAD^1
, и вы также можете обратиться HEAD^2
и так далее по мере необходимости.
Вы можете получить к родителям любой коммит, а не только HEAD
, Вы также можете вернуться назад через поколения: например, master~2
означает прародителя верхушки ветки master, отдавая предпочтение первому родителю в случаях двусмысленности. Эти спецификаторы могут быть связаны произвольно, например, topic~3^2
,
Для получения полной информации см. "Указание ревизий" в git rev-parse
документация
Чтобы иметь визуальное представление идеи, давайте процитируем часть документации:
Вот иллюстрация, Джон Лоелигер. Оба узла фиксации B и C являются родителями узла фиксации A. Родительские коммиты располагаются слева направо.
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
Разница между HEAD^
а также HEAD~
хорошо описывается иллюстрацией (Джон Лоелигер), найденной на http://www.kernel.org/pub/software/scm/git/docs/git-rev-parse.html.
Эта документация может быть немного неясной для начинающих, поэтому я воспроизвел эту иллюстрацию ниже:
G H I J
\ / \ /
D E F
\ | / \
\ | / |
\|/ |
B C
\ /
\ /
A
A = = A^0
B = A^ = A^1 = A~1
C = A^2 = A^2
D = A^^ = A^1^1 = A~2
E = B^2 = A^^2
F = B^3 = A^^3
G = A^^^ = A^1^1^1 = A~3
H = D^2 = B^^2 = A^^^2 = A~2^2
I = F^ = B^3^ = A^^3^
J = F^2 = B^3^2 = A^^3^2
И то и другое ~
а также ^
самостоятельно обратиться к родителю коммита (~~
а также ^^
оба ссылаются на коммит деда и т. д.) Но они отличаются по значению, когда используются с числами:
~2
означает два уровня в иерархии, через первого родителя, если коммит имеет более одного родителя^2
означает второго родителя, где коммит имеет более одного родителя (т. е. потому что это слияние)
Их можно комбинировать, поэтому HEAD~2^3
средства HEAD
дедушка совершает третий родительский коммит.
Вот очень хорошее объяснение, взятое дословно с http://www.paulboxley.com/blog/2011/06/git-caret-and-tilde:
ref~
это сокращение дляref~1
и означает первый родительский коммит.ref~2
означает первого родителя коммита.ref~3
означает первого родителя первого родителя коммита. И так далее.
ref^
это сокращение дляref^1
и означает первый родительский коммит. Но где два отличаются тем, чтоref^2
означает второго родителя коммита (помните, что коммиты могут иметь двух родителей при слиянии).
^
а также~
операторы могут быть объединены.
Упрощенно:
~
указывает на предков^
указывает на родителей
Вы можете указать одну или несколько веток при объединении. Затем коммит имеет двух или более родителей, а затем ^
полезно указывать родителям.
Предположим, что вы находитесь на ветви A, и у вас есть еще две ветви: B и C.
На каждой ветке три последних коммита:
- A: A1, A2, A3
- B: B1, B2, B3
- С: С1, С3, С3
Если сейчас на ветке А вы выполняете команду:
git merge B C
тогда вы объединяете три ветви (здесь у вашего коммита слияния три родителя)
а также
~
указывает на n-го предка в первой ветви, поэтому
HEAD~
указывает на А3HEAD~2
указывает на А2HEAD~3
указывает А1
^
указывает на n-го родителя, так
HEAD^
указывает на А3HEAD^2
указывает на B3HEAD^3
указывает на C3
Следующее использование ~
или же ^
рядом друг с другом находится в контексте фиксации, обозначенной предыдущими символами.
Обратите внимание 1:
HEAD~3
всегда равно:HEAD~~~
и чтобы:HEAD^^^
(каждый указывает А1),
и вообще:
HEAD~n
всегда равно:HEAD~...~
(п раз~
) и к:HEAD^...^
(п раз^
).
Примечание 2:
HEAD^3
это не то же самое, чтоHEAD^^^
(первое указывает на C3, а второе указывает на A1),
и вообще:
HEAD^1
такой же какHEAD^
,- но для n > 1:
HEAD^n
всегда не то же самое, чтоHEAD^...^
(п раз~
).
^<n>
Формат позволяет выбрать n-го родителя коммита (актуально при слиянии). ~<n>
Формат позволяет выбрать фиксацию n-го предка, всегда следуя за первым родителем. Посмотрите документацию git-rev-parse для некоторых примеров.
Стоит отметить, что git также имеет синтаксис для отслеживания "откуда ты пришел"/"хочу вернуться назад" - например, HEAD@{1}
будет ссылаться на место, откуда вы прыгнули на новое место фиксации.
В принципе HEAD@{}
Переменные фиксируют историю движения HEAD, и вы можете решить использовать конкретную голову, просматривая reflogs git с помощью команды git reflog
,
Пример:
0aee51f HEAD@{0}: reset: moving to HEAD@{5}
290e035 HEAD@{1}: reset: moving to HEAD@{7}
0aee51f HEAD@{2}: reset: moving to HEAD@{3}
290e035 HEAD@{3}: reset: moving to HEAD@{3}
9e77426 HEAD@{4}: reset: moving to HEAD@{3}
290e035 HEAD@{5}: reset: moving to HEAD@{3}
0aee51f HEAD@{6}: reset: moving to HEAD@{3}
290e035 HEAD@{7}: reset: moving to HEAD@{3}
9e77426 HEAD@{8}: reset: moving to HEAD@{3}
290e035 HEAD@{9}: reset: moving to HEAD@{1}
0aee51f HEAD@{10}: reset: moving to HEAD@{4}
290e035 HEAD@{11}: reset: moving to HEAD^
9e77426 HEAD@{12}: reset: moving to HEAD^
eb48179 HEAD@{13}: reset: moving to HEAD~
f916d93 HEAD@{14}: reset: moving to HEAD~
0aee51f HEAD@{15}: reset: moving to HEAD@{5}
f19fd9b HEAD@{16}: reset: moving to HEAD~1
290e035 HEAD@{17}: reset: moving to HEAD~2
eb48179 HEAD@{18}: reset: moving to HEAD~2
0aee51f HEAD@{19}: reset: moving to HEAD@{5}
eb48179 HEAD@{20}: reset: moving to HEAD~2
0aee51f HEAD@{21}: reset: moving to HEAD@{1}
f916d93 HEAD@{22}: reset: moving to HEAD@{1}
0aee51f HEAD@{23}: reset: moving to HEAD@{1}
f916d93 HEAD@{24}: reset: moving to HEAD^
0aee51f HEAD@{25}: commit (amend): 3rd commmit
35a7332 HEAD@{26}: checkout: moving from temp2_new_br to temp2_new_br
35a7332 HEAD@{27}: commit (amend): 3rd commmit
72c0be8 HEAD@{28}: commit (amend): 3rd commmit
Примером может быть то, что я выполнил локальные коммиты a->b->c->d, а затем вернулся к 2 коммитам, чтобы проверить мой код - git reset HEAD~2
- а затем после этого я хочу переместить мою ГОЛОВКУ обратно в г - git reset HEAD@{1}
,
TLDR
~ это то, что вы хотите большую часть времени, оно ссылается на прошлые коммиты на текущую ветку
^ ссылается на родителей (git-merge создает второго или более родителей)
A ~ всегда совпадает с A ^
~~ всегда совпадает с A ^^ и т. Д.
A ~ 2 не то же самое, что A ^ 2, однако,
потому что ~ 2 это сокращение от ~~
в то время как ^ 2 не является сокращением для чего-либо, это означает, что 2-й родитель
HEAD^^^ такой же, как HEAD~3, выбирая третий коммит перед HEAD
HEAD ^ 2 указывает второй заголовок в коммите слияния
ОП: Когда я указываю объект фиксации предка в Git, я путаюсь между HEAD^ и HEAD~.
В чем разница между HEAD^ и HEAD~ в Git?
Разница между
HEAD^
(Карет) и
HEAD~
(тильда) — это то, как они проходят историю в обратном направлении от указанной начальной точки, в данном конкретном случае.
Тильда ~
<rev>~[<n>]
= выбрать предка поколения, следуя только первым* родителям
Каре ^
<rev>^[<n>]
= выбрать
<n>th
родитель предков первого поколения
*Первый родитель всегда находится слева от слияния, например, фиксация ветки, с которой произошло слияние.
Соединение ~ и ^ вместе
Как видно на иллюстрации ниже, два селектора ~ и ^ можно использовать в комбинации. Также обратите внимание, что вместо использования
HEAD
в качестве отправной точки можно использовать любую обычную ссылку, такую как ветка , тег или даже хэш коммита .
Кроме того, в зависимости от того, какой предок должен быть выбран, ^ и ~ могут использоваться взаимозаменяемо, как показано ниже в таблице.
Источник: подробное изложение можно найти в этом сообщении в блоге по этому вопросу.
HEAD~ указывает первого родителя на "ветке"
HEAD ^ позволяет выбрать конкретного родителя коммита
Пример:
Если вы хотите следовать боковой ветви, вы должны указать что-то вроде
master~209^2~15
^ BRANCH Selector
git checkout HEAD^2
Выбирает вторую ветвь коммита (слияния), переходя на выбранную ветвь (один шаг назад по дереву коммитов)
~ COMMIT Selector
git checkout HEAD~2
Перемещает 2 коммита назад в ветке по умолчанию / выбранной
Определение как ~, так и ^ относительных ссылок в качестве селекторов PARENT - это доминирующее определение, опубликованное повсюду в Интернете, с которым я сталкивался до сих пор, включая официальную книгу Git. Да, это селекторы PARENT, но проблема с этим "объяснением" в том, что оно полностью противоречит нашей цели: как различать эти два...:)
Другая проблема заключается в том, что нам предлагается использовать селектор ^ BRANCH для выбора COMMIT (он же HEAD^ === HEAD~).
Опять же, да, вы можете использовать его таким образом, но это не предназначено для этого. Обратное перемещение селектора ^ BRANCH является побочным эффектом, а не его целью.
Только при объединенных фиксациях селектору ^ BRANCH можно присвоить номер. Таким образом, его полная мощность может быть использована только там, где есть необходимость выбора между филиалами. И самый простой способ выразить выделение в вилке - перейти на выбранный путь / ветку - это на один шаг назад по дереву фиксации. Это только побочный эффект, а не его основная цель.
~
это означает родитель.
^
если у него есть родители из двух или более, например, при слиянии, мы можем выбрать второго из родителей или другой.
так что если только что-то вроде (HEAD~ или HEAD^), результат будет таким же.
Если вам интересно, набирать ли HEAD^
или HEAD~
в вашей команде просто используйте:
Они оба являются именами одного и того же коммита - первого родителя текущего коммита.
Аналогично с master~
а также master^
- оба имени для первого родителя мастера.
Так же, как 2 + 2
а также 2 x 2
оба 4
- это разные способы добраться туда, но ответ один и тот же.
Это отвечает на вопрос: в чем разница между HEAD^ и HEAD~ в Git?
Если вы только что выполнили слияние (значит, у вашего текущего коммита более одного родителя) или вам все еще интересно, как работают каретка и тильда, см. Другие ответы (которые я не буду дублировать здесь) для более подробного объяснение, а также как использовать их повторно (например,HEAD~~~
) или с числами (например,HEAD^2
). В противном случае я надеюсь, что этот ответ сэкономит вам время.
Проще говоря, для первого уровня происхождения (происхождение, наследование, происхождение и т. Д.) HEAD^ и HEAD~ оба указывают на один и тот же коммит, который (находится) на одного родителя выше HEAD (коммит).
Кроме того, ГОЛОВА ^ = ГОЛОВА ^1 = ГОЛОВА ~ = ГОЛОВА ~1. Но ГОЛОВА ^^!= ГОЛОВА ^2!= ГОЛОВА ~2. Еще ГОЛОВА ^^ = ГОЛОВА ~2. Читать дальше.
Помимо первого уровня происхождения, все становится сложнее, особенно если в рабочей ветви / главной ветви были слияния (из других ветвей). Существует также вопрос синтаксиса с кареткой, HEAD^^ = HEAD~2 (они эквивалентны), НО HEAD^^!= HEAD^2 (это совершенно разные вещи).
Каждый / символ каретки относится к первому родителю HEAD, поэтому знаки, объединенные в строку, эквивалентны выражениям тильды, потому что они относятся к первым родителям первого родителя (первого родителя) и т. Д. И т. Д. И т. Д., Строго основываясь на количестве подключенных кареток. или на число после тильды (так или иначе, они оба означают одно и то же), то есть остаются с первым родителем и идут вверх на x поколений.
HEAD~ 2 (или HEAD^^) относится к коммиту, который является двумя уровнями происхождения выше / выше текущего коммита (HEAD) в иерархии, что означает коммит деда и дедушки HEAD.
HEAD ^ 2, с другой стороны, ссылается не на коммит второго родителя первого родителя, а просто на коммит второго родителя. Это связано с тем, что символ каретки означает родителя коммита, а следующий за ним номер обозначает, на какой / какой родительский коммит ссылается (первый родитель в случае, когда за кареткой не следует число [потому что это сокращение для номера). будучи 1, означая первого родителя]). В отличие от каретки, число, которое следует после, не подразумевает другого уровня иерархии вверх, а скорее означает, сколько уровней вбок, в иерархии, нужно найти правильного родителя (commit). В отличие от числа в выражении тильды, это только один родительский элемент в иерархии, независимо от числа (непосредственно), идущего за кареткой. Вместо восходящего, конечный номер каретки учитывается вбок для родителей по всей иерархии [на уровне родителей вверх, что эквивалентно количеству последовательных карет).
Таким образом, HEAD^3 равен третьему родителю коммита HEAD (НЕ пра-пра-прародитель, который будет HEAD^^^ AND HEAD~3...).