В чем разница между 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~ указывает на А3
  • HEAD~2 указывает на А2
  • HEAD~3 указывает А1

^ указывает на n-го родителя, так

  • HEAD^ указывает на А3
  • HEAD^2 указывает на B3
  • HEAD^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},

фактический пример разницы между HEAD~ и HEAD^

ГОЛОВА ^ VS ГОЛОВА

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...).

Другие вопросы по тегам