Чи надійний напівсекретний порожній деревній предмет git, і чому для нього не існує символічної назви?


125

Git має добре відоме або, принаймні, добре відоме, порожнє дерево, SHA1 якого:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(ви можете бачити це в будь-якому репо, навіть новоствореному, з git cat-file -tі git cat-file -p).

Якщо ви багато працюєте і дуже обережні, ви можете впорядкувати це порожнє дерево для зберігання каталогу, у якому немає файлів (див. Відповідь на тему Як додати порожній каталог у сховище git ), хоча це насправді не чудова ідея.

Це корисніше як один аргумент git diff-tree, який робить один із зразків гачків.

Що мені цікаво,

  1. наскільки це надійно, тобто чи не буде в майбутній версії git нумерований об'єкт git 4b825dc642cb6eb9a060e54bf8d69288fbee4904?
  2. Чому для порожнього дерева немає символічної назви (чи існує таке?).

(Швидкий і брудний спосіб створити символічну назву - це ввести SHA1, наприклад,. .git/NulltreeНа жаль, ви повинні робити це для кожного репо. до магічних чисел.)


3
просто пам’ятайте хеш ;-) використовуйте SHA1 ("дерево 0 \ 0") = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 (\ 0 - символ NUL)
Томас

4
@Thomas: git hash-object -t tree /dev/nullметод (з відповіді VonC нижче) має перевагу перед не жорстким кодуванням SHA-1, якщо, наприклад, якась майбутня версія git переходить на SHA-2. (Я не збираюся намагатися передбачити, коли це може статися. :-) Простіше було б перейти Mercurial на SHA-2, оскільки вони залишили для цього місце.)
torek

бо ви маєте рацію, але це хороший фрагмент "Марних знань", і він може бути корисним у будь-якому випадку для когось іншого ?!
Томас

2
@Thomas: схоже, зміна алгоритму хеш може відбутися раніше, ніж очікувалося . :-)
torek

Говорячи про «якусь - то майбутній версії Git», я думаю , вам буде цікаво в моїй останній (грудень 2017) редагувати на мою відповідь до: 2012 stackoverflow.com/revisions/9766506/7
VonC

Відповіді:


104

Ця нитка згадує:

Якщо ви не пам’ятаєте порожнє дерево sha1, ви завжди можете отримати це за допомогою:

git hash-object -t tree /dev/null

Або, як пропонує Ciro Santilli у коментарях :

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

Або, як видно тут , від Коліна Шіммельфінга :

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

Тому я думаю, що безпечніше визначити змінну з результатом цієї команди як ваше порожнє дерево sha1 (замість того, щоб покладатися на "добре відоме значення").

Примітка: Git 2.25.1 (лютий 2020 р.) Пропонує в команді 9c8a294 :

empty_tree=$(git mktree </dev/null)
# Windows:
git mktree <NUL

І додає:

Як історична примітка, тепер відома функція, repo_read_object_file()яку вчили порожнє дерево в 346245a1bb ("жорсткий код об'єкта порожнього дерева", 2008-02-13, Git v1.5.5-rc0 - злиття ), а тепер функція відома як oid_object_info()вчили порожнє дерево в c4d9986f5f (" sha1_object_info: також вивчити cached_objectмагазин", 2011-02-07, Git v1.7.4.1).


Зауважте, ви побачите, що 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, як це видно в команді eb0ccfd :

Переключіть порожні дерева та блобування, щоб використовувати хеш-абстракцію

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

Детальніше див. У розділі " Чому Git не використовує більш сучасний SHA? ": Це SHA-2 , оскільки Git 2.19 (Q3 2018)


З Git 2.25 (I квартал 2020 р.) Тести готуються до переходу SHA-2 і включають порожнє дерево.

Див здійснювати fa26d5e , здійснювати cf02be8 , здійснюють 38ee26b , здійснюють 37ab8eb , здійснюють 0370b35 , здійснюють 0253e12 , здійснюють 45e2ef2 , здійснюють 79b0edc , здійснюють 840624f , здійснюють 32a6707 , здійснюють 440bf91 , здійснюють 0b408ca , здійснюють 2eabd38 (28 окт 2019), а також здійснювати 1bcef51 , здійснюють ecde49b (05 жовтня 2019) від Брайана м. Карлсон ( bk2204) .
(Об'єднав Хуніо С Хамано - gitster- у комітеті 28014c1, 10 листопада 2019 р.)

t/oid-info: додайте значення порожнього дерева та порожнього блобу

Підписано: Брайан м. Карлсон

Зрештою тестовий комплект дізнається, як запустити алгоритм, відмінний від SHA-1. Готуючись до цього, навчіть test_oidсім'ю функцій, як шукати порожні крапки та порожні значення дерев, щоб їх можна було використовувати.

Тому t/oid-info/hash-infoтепер включає:

rawsz sha1:20
rawsz sha256:32

hexsz sha1:40
hexsz sha256:64

zero sha1:0000000000000000000000000000000000000000
zero sha256:0000000000000000000000000000000000000000000000000000000000000000

algo sha1:sha1
algo sha256:sha256

empty_blob sha1:e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813

empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

SHA2 " 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" - це нове 4b825dc642cb6eb9a060e54bf8d69288fbee4904порожнє дерево SHA1 .


@torek: Я додав кілька прикладів, щоб вперше зробити найкращу практику порожнього виконувати, щоб проілюструвати це порожнє дерево SHA1.
VonC

Ну, одна з цілей - використовувати хеш "порожнього дерева" як аргумент git diff-treeу деяких сценаріях, про які я пишу. Немає гарантії, що в РЕПО є початкові порожні комісії. Тож мені просто цікаво, чи можуть ці сценарії колись порушитися.
torek

1
Якщо ви перейдете -wдо цього git hash-object, він створить об’єкт у сховищі, проти якого він працює, і це відтворить порожнє дерево у сховищі, проти якого ви зіткнулися, якби воно коли-небудь відійде в майбутньому.
javawizard

Якщо ви хочете перейти до першої фіксації за допомогою rebase, ви можете використовувати git
rebase --root

1
Або якщо ви віддаєте перевагу магію труб замість магії /dev/null: printf '' | git hash-object --stdin -t tree:)
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

3

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

Якби колись чомусь змінилося, ви можете скористатися двома способами, наведеними нижче, щоб знайти його. Однак я відчував би себе впевнено, використовуючи хеш у .bashrc псевдонімах тощо, і я не думаю, що це зміниться незабаром. Принаймні, це було б, мабуть, великим випуском git.

Два способи:

  1. Відповідь вище: git hash-object -t tree --stdin < /dev/null
  2. Просто запросити порожнє репо, а потім запустити git write-treeнове репо - хеш буде виведено деревом git write.

Запуск команди з –-stdinдає мені fatal: Cannot open '–-stdin': No such file or directorygit 2.7.2. Однак запуск його без того, --stdinяк у відповіді VonC дає хеш-значення
підпишіться

Ця відповідь не дуже корисна, оскільки повідомлення в блозі мертве. Отже, чому ми взагалі не схвалюємо цих відповідей.
Філіп Уайтхаус

1
@PhilipWhitehouse публікація в блозі не мертва, але в будь-якому випадку я включив у свою відповідь два способи - я погоджуюся, що без включення цих двох способів це не буде гарною відповіддю.
schimmy

3

Ось відповідь про те, як створити порожнє дерево фіксації, навіть у тому випадку, коли сховище ще не порожнє. https://stackoverflow.com/a/14623458/9361507

Але я вважаю за краще "порожній" бути тегом, а не гілкою. Простий спосіб:

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

Оскільки тег може вказувати на дерево-ish безпосередньо, без комірок. Тепер, щоб отримати всі файли в робочому дереві:

git diff --name-only empty

Або те саме з stat:

git diff --stat empty

Усі файли як різні:

git diff empty

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

git diff --check empty

... але використання магічного номера у створенні вашого тегу - це просто чищення під килимом саме питання ( не використовуючи магічне число SHA-1)
RomainValeri

Неправда. Я використовував тег для вказівки на об’єкт дерева-ish. На сьогоднішній день це дерево-ish визначається SHA-1, у майбутньому воно може бути змінено, наприклад, на SHA-256 і так далі (з міграцією сховища). Але тег буде таким самим. :) Основна особливість тегу - вказувати на об’єкт. Тег може використовувати SHA-1 внутрішньо або щось інше, це лише внутрішні питання Git.
Олег

Я це розумію. Але якщо ви (або хтось, хто читає це) (або сценарій , ще гірше) намагаєтесь застосувати його (ваш перший рядок) у більш пізній момент, він може вийти з ладу за новим алгоритмом хешу, де замінити ваш перший рядок виконаним виразом (створюючи цей хеш) продовжував би бути успішним.
RomainValeri

Якщо ви поєднаєте це з одним із методів автоматичного генерування порожнього хешу, ви можете це підтвердити у майбутньому (як пропонує @RomainValeri). Однак, якби я не залежав від цього, git rev-parseмали б нові прапори або ключові слова або щось подібне, щоб створити (а) порожній хеш дерева та (б) нульовий хеш-коміт. І те і інше було б корисно в сценаріях і захистило б від запропонованих змін SHA-256.
Торека

Гаразд, змінено. Але це буде не "найпростішим способом". :)
Olleg
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.