Техника и логика Git, стоящие за "git status"

Что именно происходит, когда git status ищет, есть ли какие-либо изменения в локальной папке?

Насколько я понимаю, каждый файл "регистрируется" через хеш-код (а точнее: sha1) и git status "просто" пытается сопоставить до сих пор зарегистрированные хэши с вычисленными на лету, и если есть что-то другое, это считается изменением статуса. Я не очень уверен в этом, если честно, если я ошибаюсь, я бы хотел исправить. В любом случае возникают вопросы:

  1. Где можно найти какие хеши? Есть много хэшей для репо определенных вещей, но где именно я могу найти зарегистрированный хэш для каждого файла?
  2. Что происходит с этими хэшами, если выполняется одна из следующих команд: git add, git commit -am, git gc

2 ответа

Решение

Чтобы понять это, вам сначала нужно разобраться с объектами git store, все они идентифицируются по их хэшу SHA1. Это коммиты, деревья и капли.

Коммит содержит сообщение о коммите, коммитер, дату, SHA1 родительского коммита (ов) и SHA1 дерева (плюс некоторая дополнительная информация).

Дерево представляет собой каталог. Он содержит имена (и другие метаданные) файлов и каталогов, которые он содержит. Для каждого файла он также содержит SHA1 соответствующего большого двоичного объекта, а для каждого подкаталога он содержит SHA1 другого дерева.

Blob представляет содержимое файла без имени или каких-либо других метаданных.

Сейчас, git status сравнивает три дерева:

  1. Тот, который принадлежит текущему коммиту (HEADобычно последний коммит в текущей ветке).
  2. Тот, что в области постановки. Это где файлы идут после вас git add их и используется для подготовки коммита до того, как вы его на самом деле делаете.
  3. Ваше рабочее дерево. Так выглядит каталог на вашем диске.

Вот почему, если вы редактируете файл (скажем, a.txt), git add это, отредактируйте его еще немного, а затем используйте git status, вы получите вывод, как это:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   a.txt
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   a.txt
#

Теперь к вашим актуальным вопросам:

Где можно найти какие хеши? Есть много хэшей для репо определенных вещей, но где именно я могу найти зарегистрированный хэш для каждого файла?

Они хранятся в дереве объектов. Например, чтобы увидеть объект дерева текущего коммита (HEAD), используйте git ls-tree HEAD:

$ git ls-tree HEAD
100644 blob 9c59e24b8393179a5d712de4f990178df5734d99    a.txt

Вы можете видеть, что корневой каталог репо содержит один файл (blob) под названием a.txt с SHA1 9c59e24b8393179a5d712de4f990178df5734d99.

Вы можете использовать эту же команду для просмотра SHA1 подкаталогов и файлов в этих подкаталогах, подробности см. В документации к команде.

Чтобы вычислить SHA1 некоторого файла на диске, вы можете использовать git hash-object,

Что происходит с этими хэшами, если выполняется одна из следующих команд

Вы должны помнить, что SHA1 основаны на содержимом объекта. И каждый объект полностью неизменен, поэтому SHA1 какого-либо объекта никогда не изменяется. Но многие операции могут создавать новые объекты, и они могут, например, также переходить на какой-либо объект.

  • git add берет дерево в промежуточной области, модифицирует его, добавляя или изменяя некоторые файлы в соответствии с параметрами команды, и сохраняет измененное дерево обратно в промежуточную область.
  • git commit берет дерево в области подготовки и создает коммит, который указывает на это дерево. Новый коммит также имеет текущую дату, вы как коммитер и текущий коммит как его родитель. Затем команда изменяет текущую ветвь так, чтобы она указывала на новый коммит.
  • git commit -a это просто ярлык для git add с последующим git commit,
  • git gc просматривает все объекты, которые он хранит, и удаляет те, которые недоступны. Доступные объекты - это подсказки всех ветвей, тегов или текущего коммита, а также всех объектов, на которые они ссылаются, рекурсивно. Недавно использованные коммиты (и объекты, на которые они ссылаются) также не удаляются, потому что они доступны через reflog.

Перейдите к главе 9.2 электронной книги Progit.

Вся электронная книга стоит того, чтобы ее прочитать.

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