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

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

4b825dc642cb6eb9a060e54bf8d69288fbee4904

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

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

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

Мне интересно,

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

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

Ответы [ 3 ]

90 голосов
/ 19 марта 2012

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

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

git hash-object -t tree /dev/null

Или, как Сиро Сантилли предлагает в комментариях :

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

Или, как здесь , из Колин Шиммельфинг :

git hash-object -t tree --stdin < /dev/null

Так что, я думаю, безопаснее определить переменную с результатом этой команды как пустое дерево 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'

Даст вам:

Empty tree 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 в 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? "

3 голосов
/ 01 марта 2019

Вот ответ, как создать пустой древовидный коммит даже в том случае, если репозиторий уже не пуст.https://stackoverflow.com/a/14623458/9361507

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

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

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

git diff --name-only empty

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

git diff --stat empty

Все файлы как diff:

git diff empty

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

git diff --check empty
3 голосов
/ 06 октября 2013

Я написал сообщение в блоге с двумя различными способами поиска хеша: 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.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...