Что такое Git Diff^? - PullRequest
       65

Что такое Git Diff^?

0 голосов
/ 01 февраля 2019

Я обычно проверяю содержимое коммита "git diff commit ^!".Однако, когда я применяю его к первоначальному коммиту, я вижу смесь изменений от разных коммитов впоследствии, хотя я предполагаю, что это должна быть начальная копия коммита.Может ли кто-нибудь помочь мне понять это с точки зрения семантики?

Кстати, я знаю, что есть хорошие ответы, как показать разницу в init commit из stackoverflow вопрос 40883798 .

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Я обычно проверяю содержимое коммита с помощью "git diff commit ^!".

(Почему? Обычная команда: git show <commit>.)

Однако, когда я применяю его к начальному коммиту, я вижу [что-то менее полезное]

Место, где можно найти (краткое) объяснение любого синтаксиса ревизий, - документация gitrevisons, который говорит это о суффиксе ^!:

Запись r1 ^! включает в себя фиксацию r1 , но исключает всеего родители.Само по себе это обозначение обозначает единственный коммит r1 .

К сожалению, это объяснение слишком короткое .В этом случае более полезна подача ревизии на git rev-parse:

$ git rev-parse HEAD
b5101f929789889c2e536d915698f58d5c5c6b7a
$ git rev-parse HEAD^1
a562a119833b7202d5c9b9069d1abb40c1f9b59a

Из этих двух выходных данных видно, что HEAD представляет идентификатор хеша b5101f929789889c2e536d915698f58d5c5c6b7a, а его первым родителем является a562a119833b7202d5c9b9069d1abb40c1f9b59a,Вот что нам нужно для понимания:

$ git rev-parse HEAD^!
b5101f929789889c2e536d915698f58d5c5c6b7a
^a562a119833b7202d5c9b9069d1abb40c1f9b59a

Вывод здесь означает, по сути:

  • начало в b5101f929789889c2e536d915698f58d5c5c6b7a ...
  • но остановитесь на a562a119833b7202d5c9b9069d1abb40c1f9b59a.

(^ перед хеш-идентификатором означает «не»: коммит B, но не коммит A.)

Сравните это с:

$ git rev-parse HEAD^..HEAD
b5101f929789889c2e536d915698f58d5c5c6b7a
^a562a119833b7202d5c9b9069d1abb40c1f9b59a

Это тот же вывод!

Что это значит для git diff немного хитро и тонко, потому что мы говорим о git rev-parse здесь, а не git diff,Но на самом деле, когда вы запускаете:

git diff <something>

Git внутренне передает <something> на git rev-parse.Поэтому, если вы введете:

git diff HEAD^..HEAD

git diff, то внутренне передаст всю строку HEAD^..HEAD внутренней версии git rev-parse и получите идентификаторы "stop at" и "start at".Если вы наберете:

git diff HEAD^!

git diff внутренне передает всю строку HEAD^! во внутреннюю версию git rev-parse и получит такие же «stop at» и «start»at "IDs.

То же самое происходит, когда вы используете хеш коммита для любого коммита, у которого есть один родитель: суффикс ^! генерирует" not "для родительского хэша и" use "для хэша.

Но когда вы найдете root commit - в моем Git-репозитории для Git есть куча, так что я просто возьму первый:

$ git rev-list --max-parents=0 HEAD | head -1
0ca71b3737cbb26fbf037aa15b3f58735785e6e3

- когда мы дадим этот идентификатор хэша с суффиксом хет-бэнг для git rev-parse, мы получим:

$ git rev-parse 0ca71b3737cbb26fbf037aa15b3f58735785e6e3^!
0ca71b3737cbb26fbf037aa15b3f58735785e6e3

То есть git rev-parse сказал да для коммита, иНет всем его родителям, но родителей нет, поэтому он вообще сказал «нет»!

Если вы кормите этим git diff - просто один хеш коммитов -команда git diff думает: ах, вы хотите сравнить данный коммит с тем, что сейчас находится в вашем рабочем дереве .Итак, вот разница, которую вы получите.


Обратите внимание, что суффикс ^! производит "not" для всех родителей коммита.Для фиксации слияния существует как минимум два (и обычно ровно два) родителя:

$ git show -s a562a11983
commit a562a119833b7202d5c9b9069d1abb40c1f9b59a
Merge: 7fa92ba40a ad6f028f06
Author: Junio C Hamano ...

Итак:

$ $ git rev-parse a562a11983^!
a562a119833b7202d5c9b9069d1abb40c1f9b59a
^7fa92ba40abbe4236226e7d91e664bbeab8c43f2
^ad6f028f067673cadadbc2219fcb0bb864300a6c

Когда вы задаете git diff спецификатор ревизии, который расширяется до три или более фиксирует, иногда делает что-то другое.В этом конкретном случае, однако, он просто сравнивает коммит с первым родителем.Команда git show вместо этого создаст комбинированный diff по умолчанию, который в этом случае вообще ничего не показывает, потому что комбинированные diff разработаны, чтобы показать вам, где слияния могли конфликтовать.

0 голосов
/ 01 февраля 2019

Когда вы запустите git diff и передадите коммит, git отобразит изменения в вашем текущем рабочем дереве относительно этого коммита

Из документации git

git diff [] [-] […] Эта форма предназначена для просмотра изменений, внесенных в ваше рабочее дерево относительно именованных.Вы можете использовать HEAD, чтобы сравнить его с последним коммитом, или имя ветви, чтобы сравнить с кончиком другой ветви.

Символ каретки (^) является ссылкой на первого родителячто совершать.Подобным образом вы можете ссылаться на второе (^2), третье (^3) и т. Д.

Запустив git diff <firstCommit>^, вы семантически просите «Дайте мне изменения между моими текущимирабочий каталог и родительский родительский элемент первого коммита ".Родитель первого коммита не существует, поэтому семантически не имеет смысла.

В git 2.17.1 при запуске такой команды выдается ошибка:

$> git diff 9f3f6c8e4b1dea1de25febbb8248a6c430966236^
$> fatal: ambiguous argument '9f3f6c8e4b1dea1de25febbb8248a6c430966236^': unknown revision or path not in the working tree.
...