Является ли полусекретный пустой объект дерева git надежным, и почему для него нет символического имени?

У Git есть хорошо известное или, по крайней мере, некое известное пустое дерево с SHA1:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(Вы можете увидеть это в любом репо, даже недавно созданном, с git cat-file -t а также git cat-file -p).

Если вы много работаете и очень осторожны, вы можете использовать это пустое дерево для хранения каталога, в котором нет файлов (см. Ответ "Как добавить пустой каталог в репозиторий git"), хотя это не очень хорошая идея.

Это более полезно в качестве одного аргумента git diff-treeчто делает один из примеров хуков.

Что мне интересно, так это

  1. насколько это надежно, т. е. в будущей версии git не будет нумерованного объекта git 4b825dc642cb6eb9a060e54bf8d69288fbee4904?
  2. Почему для пустого дерева нет символического имени (или оно есть?).

(Быстрый и грязный способ создать символическое имя - поместить SHA1 в, например, .git/Nulltree, К сожалению, вы должны сделать это для каждого репо. Кажется, лучше просто ввести магическое число в сценарии и т. Д. У меня просто есть общее отвращение к магическим числам.)

2 ответа

Решение

В этой теме упоминается:

Если вы не помните пустое дерево sha1, вы всегда можете получить его с помощью:

git hash-object -t tree /dev/null

Или, как Ciro Santilli 新疆改造中心 六四事件 法轮功 предлагает в комментариях:

printf '' | git hash-object --stdin -t tree

Поэтому я думаю, что безопаснее определить переменную с результатом этой команды как пустое дерево sha1 (вместо того, чтобы полагаться на "общеизвестное значение").


Обратите внимание, вы увидите, что SHA1 появляется в каком-либо репозитории GitHub, когда автор хочет, чтобы его первый коммит был пустым (см. Сообщение в блоге " Как я инициализирую свои репозитории Git "):

$ GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000" GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000" git commit --allow-empty -m 'Initial commit'

Дам тебе:

Пустое дерево SHA1

(Видите дерево SHA1?)

Вы даже можете перебазировать существующую историю поверх этого пустого коммита (см. " Git: как вставить коммит в качестве первого, сдвинув все остальные? ")

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


Для этого:

git init my_new_repo
cd my_new_repo
git config user.name username
git config user.email email@com

git commit --allow-empty -m "initial empty commit"

Это создаст коммит с SHA1, специфичным для вашего репо, имени пользователя, адреса электронной почты, даты создания (то есть SHA1 самого коммита будет отличаться каждый раз).
Но дерево, на которое ссылается этот коммит, будет 4b825dc642cb6eb9a060e54bf8d69288fbee4904 Пустое дерево SHA1.

git log --pretty=raw

commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <vonc@laposte.net> 1381232247 +0200
committer VonC <vonc@laposte.net> 1381232247 +0200

    initial empty commit

Чтобы показать только дерево коммита (отобразить дерево коммитов SHA1):

git show --pretty=format:%T 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
4b825dc642cb6eb9a060e54bf8d69288fbee4904

Если этот коммит, ссылающийся на пустое дерево, действительно является вашим первым коммитом, вы можете показать это пустое дерево SHA1 с помощью:

git log --pretty=format:%h --reverse | head -1 | xargs git show --pretty=format:%T
4b825dc642cb6eb9a060e54bf8d69288fbee4904

(и это работает даже в Windows с командами Gnu On Windows)


Как прокомментировано ниже, используя git diff <commit> HEAD, это покажет все ваши файлы в текущей ветке HEAD:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

Примечание: это пустое значение дерева формально определено в cache.h,

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Теперь (Git 2.16, Q1 2018) используется в структуре, которая больше не привязана (только) к SHA1, как видно из commit eb0ccfd:

Переключите поиск пустого дерева и блобов, чтобы использовать хэш-абстракцию

Переключите использование empty_tree_oid а также empty_blob_oid использовать current_hash абстракция, представляющая текущий используемый алгоритм хеширования.

Подробнее на " Почему Git не использует более современные SHA? "

Вот ответ, как создать пустое дерево коммитов даже в том случае, если репозиторий уже не пуст. /questions/25494017/sozdanie-git-diff-iz-nichego/25494036#25494036

Но я предпочитаю "пустой" быть тегом, а не веткой. Простой способ это:

git tag empty $(git hash-object -t tree /dev/null)

Потому что тег может указывать на tree-ish напрямую, без коммита. Теперь чтобы получить все файлы в рабочем дереве:

git diff --name-only empty

Или то же самое с stat:

git diff --stat empty

Все файлы в формате diff:

git diff empty

Проверьте пробелы во всех файлах:

git diff --check empty

Я написал сообщение в блоге с двумя различными способами поиска хеша: http://colinschimmelfing.com/blog/gits-empty-tree/

Если бы это когда-либо изменилось по какой-то причине, вы можете использовать два способа ниже, чтобы найти его. Однако я чувствовал бы себя довольно уверенно, используя хэш в псевдонимах.bashrc и т. Д., И я не думаю, что он скоро изменится. По крайней мере, это, вероятно, основной выпуск git.

Два способа:

  1. Ответ выше: git hash-object -t tree --stdin < /dev/null
  2. Просто запустив пустой репо, а затем запустив git write-tree в этом новом репо хеш будет выведен git write-tree.
Другие вопросы по тегам