Git'in yarı gizli boş ağaç nesnesi güvenilir midir ve neden bunun için sembolik bir isim yok?


125

Git'in iyi bilinen veya en azından bir çeşit iyi bilinen boş bir ağacı vardır ve SHA1:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(bunu herhangi bir depoda, hatta yeni oluşturulmuş bir depoda git cat-file -tve ile görebilirsiniz git cat-file -p).

Çok çalışırsanız ve çok dikkatli olursanız, bu boş ağacı dosya içermeyen bir dizini depolamak için kullanabilirsiniz ( git deposuna nasıl boş bir dizin ekleyebilirim sorusuna bakın ), ancak bu gerçekten harika bir fikir değildir.

git diff-treeÖrnek kancalardan birinin yaptığı bir argüman olarak daha kullanışlıdır .

Merak ettiğim şey,

  1. bu ne kadar güvenilir - yani, git'in gelecekteki bazı sürümlerinde numaralı bir git nesnesi olmayacak 4b825dc642cb6eb9a060e54bf8d69288fbee4904mı?
  2. Neden boş ağaç için sembolik bir isim yok (veya var mı?).

(Sembolik bir ad oluşturmanın hızlı ve kirli bir yolu, örneğin SHA1'i koymaktır .git/Nulltree. Maalesef bunu her depo için yapmanız gerekiyor. Sihirli sayıyı komut dosyalarına koymak daha iyi görünüyor, vb. Sadece genel bir tiksintim var. sihirli sayılara.)


3
hash'i hatırlamak için ;-) SHA1 ("ağaç 0 \ 0") = 4b825dc642cb6eb9a060e54bf8d69288fbee4904 (\ 0 NUL karakteridir) kullanın
Thomas

4
@Thomas: git hash-object -t tree /dev/nullYöntem ( VonC'nin aşağıdaki cevabına göre), örneğin git'in gelecekteki bir sürümünün SHA-2'ye geçmesi durumunda, SHA-1'i sabit kodlamama avantajına sahiptir. (Bunun ne zaman olabileceğini tahmin etmeye çalışmayacağım. :-) Mercurial'ı SHA-2'ye geçirmek daha kolay olurdu, çünkü buna yer
bıraktılar

haklısınız, ancak bu "Yararsız Bilgi" nin iyi bir parçasıdır ve her durumda başka birine yardımcı olabilir mi ?!
Thomas

2
@Thomas: Karma algoritma değişimi beklenenden daha erken gerçekleşebilir gibi görünüyor . :-)
torek

"Git'in gelecekteki bir sürümünden" bahsetmişken, 2012 cevabım için son (Aralık 2017) düzenlememle ilgileneceğinizi düşünüyorum: stackoverflow.com/revisions/9766506/7
VonC

Yanıtlar:


104

Bu ileti dizisi şunlardan bahsediyor:

Boş sha1 ağacını hatırlamıyorsanız, onu her zaman şu şekilde türetebilirsiniz:

git hash-object -t tree /dev/null

Veya Ciro Santilli'nin yorumlarda önerdiği gibi :

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

Veya, burada görüldüğü gibi , Colin Schimmelfing'den :

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

Bu nedenle, bu komutun sonucu olan bir değişkeni boş sha1 ağacınız olarak tanımlamak daha güvenlidir ("iyi bilinen bir değere" güvenmek yerine).

Not: Git 2.25.1 (Şubat 2020), 9c8a294 işleminde önerir :

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

Ve ekler:

Tarihsel bir not olarak, şu anda bilinen işlev 346245a1bb'derepo_read_object_file() boş ağaca öğretilmişti ("boş ağaç nesnesini sabit kodla", 2008-02-13, Git v1.5.5-rc0 - birleştirme ) ve artık bilinen işlev c4d9986f5f'deoid_object_info() boş ağaç öğretildiği gibi (" : depoyu da inceleyin ", 2011-02-07, Git v1.7.4.1). sha1_object_infocached_object


Not, yazar ilk işleminin boş olmasını istediğinde SHA1'in bazı GitHub deposunda açıldığını göreceksiniz (" Git depolarımı nasıl başlatırım " blog gönderisine bakın ):

$ 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'

Sana vereceğim:

Boş ağaç SHA1

(SHA1 ağacına bakın?)

Hatta mevcut geçmişinizi bu boş kesinleştirmenin üzerine yeniden düzenleyebilirsiniz (bkz. " Git: ilk olarak bir commit nasıl eklenir, diğerlerini kaydırarak? ")

Her iki durumda da, bu boş ağacın tam SHA1 değerine güvenmezsiniz.
En iyi uygulamayı takip ederek repo'nuzu ilk boş commit ile başlatırsınız .


Bunu yapmak için:

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"

Bu, deponuza, kullanıcı adınıza, e-postanıza, oluşturma tarihinize özel bir SHA1 ile bir commit oluşturacaktır (yani commit'in SHA1'i her seferinde farklı olacaktır).
Ancak bu kaydetme tarafından başvurulan ağaç 4b825dc642cb6eb9a060e54bf8d69288fbee4904, boş SHA1 ağacı olacaktır .

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

Yalnızca bir işlemenin ağacını göstermek için (SHA1 işleme ağacını görüntüleyin):

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

Boş bir ağaca başvuran bu kaydetme gerçekten ilk işlemenizse, boş SHA1 ağacını şununla gösterebilirsiniz:

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

(ve bu, Windows'ta Gnu On Windows komutlarıyla bile çalışır )


Gibi , aşağıda yorumladı kullanarak git diff <commit> HEAD, bu mevcut şube HEAD tüm dosya gösterecektir:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

Not: bu boş ağaç değeri resmi olarak içinde tanımlanmıştır cache.h.

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Git 2.16'dan (Q1 2018) bu yana, eb0ccfd commit'de görüldüğü gibi artık (yalnızca) SHA1'e bağlı olmayan bir yapıda kullanılıyor :

Karma soyutlamayı kullanmak için boş ağaç ve blob aramalarını değiştirin

Kullanımlarını geçin empty_tree_oidve empty_blob_oidkullanımı current_hashKullanılan geçerli karma algoritması temsil soyutlama.

Daha fazlasını görmek için " Git neden daha modern SHA kullanmıyor? ": Git 2.19'dan beri (Q3 2018) SHA-2.


Git 2.25 (Q1 2020) ile testler SHA-2 geçişine hazırlanıyor ve boş ağacı içeriyor.

Bkz fa26d5e işlemek , cf02be8 işlemek , 38ee26b işlemek , işlemek 37ab8eb , 0370b35 taahhüt , 0253e12 taahhüt , 45e2ef2 taahhüt , 79b0edc işlemek , 840624f taahhüt , 32a6707 taahhüt , 440bf91 taahhüt , 0b408ca işlemek , 2eabd38 taahhüt (2019 28 Eki) ve 1bcef51 taahhüt , taahhüt ecde49b (05 Eki 2019), yazan brian m. carlson ( bk2204) .
(Göre Birleştirilmiş Junio Cı Hamano - gitster- içinde 28014c1 tamamlama, 10 Kasım 2019)

t/oid-info: boş ağaç ve boş blob değerleri ekle

İmza: Brian m. carlson

Testsuite sonunda SHA-1 dışında bir algoritma kullanarak nasıl çalıştırılacağını öğrenecektir. Bunun için hazırlanırken test_oid, işlev ailesine boş blob ve boş ağaç değerlerine nasıl bakılacağını öğretin .

Yani t/oid-info/hash-infoşimdi içerir:

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" yeni SHA1 " 4b825dc642cb6eb9a060e54bf8d69288fbee4904" boş ağaçtır.


@torek: Bu boş SHA1 ağacını göstermek için ilk boş commit en iyi uygulamasına bazı örnekler ekledim.
VonC

Hedeflerden biri, git diff-treeyazdığım bazı betiklerde "boş ağaç" hashini bir argüman olarak kullanmaktır . Depoda başlangıçta boş bir taahhüt olacağının garantisi yoktur. Bu yüzden bu senaryoların bir gün bozulup kalmayacağını merak ediyorum.
torek

1
Eğer geçerseniz -wiçin git hash-object, bunun karşı çalıştırılır depoda nesne oluşturmak olacak ve size karşı çalıştırıyorsanız depoda boş ağaç hiç gelecekte gitmesini idi tekrar oluşturacaktır.
javawizard

Rebase kullanarak ilk commitden önce gitmek istiyorsanız git rebase --root
GergelyPolonkai

1
Ya da /dev/nullprintf '' | git hash-object --stdin -t tree
şunun

3

Hash'i bulmanın iki farklı yolunu içeren bir blog yazısı yazdım: http://colinschimmelfing.com/blog/gits-empty-tree/

Herhangi bir nedenle değişecek olsaydı, onu bulmak için aşağıdaki iki yolu kullanabilirsiniz. Bununla birlikte, .bashrc takma adlarında vb. Hash kullandığım için kendimi oldukça rahat hissederim ve yakın zamanda değişeceğini düşünmüyorum. En azından muhtemelen git'in büyük bir sürümü olacaktı.

İki yol:

  1. Yukarıdaki cevap: git hash-object -t tree --stdin < /dev/null
  2. Basitçe boş bir depoyu başlatmak ve sonra git write-treebu yeni depoda çalıştırmak - hash git write-tree tarafından çıkarılacaktır.

Komutu ile çalıştırmak –-stdinbana fatal: Cannot open '–-stdin': No such file or directorygit 2.7.2 veriyor . Ancak, --stdin
VonC'nin

Bu cevap, blog yazısı artık çok kullanışlı değil. Bu nedenle, SO'da bu cevapları genellikle onaylamıyoruz.
Philip Whitehouse

1
@PhilipWhitehouse blog yazısı ölmedi, ancak herhangi bir durumda cevabıma iki yolu dahil ettim - bu iki yolu dahil etmeden iyi bir cevap olmayacağını kabul ediyorum.
schimmy

3

Depo zaten boş olmadığında bile boş ağaç işlemenin nasıl oluşturulacağının cevabı burada. https://stackoverflow.com/a/14623458/9361507

Ama ben "boş" un etiket olmasını tercih ediyorum, ama bir dalı değil. Basit yol:

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

Çünkü etiket, commit olmaksızın doğrudan ağaç-benzeri bir şeyi işaret edebilir. Şimdi çalışma ağacındaki tüm dosyaları almak için:

git diff --name-only empty

Veya stat ile aynı:

git diff --stat empty

Fark olarak tüm dosyalar:

git diff empty

Tüm dosyalardaki boşlukları kontrol edin:

git diff --check empty

... ama etiketi oluşturulmasında sihirli numarayı kullanarak sadece çok madde sorunun halının altına fırçalıyor ( değil sihirli sayı SHA-1 kullanılarak)
RomainValeri

Doğru değil. Ağaç benzeri nesneyi işaret etmek için etiket kullandım. Şimdiye kadar bu ağaç-benzeri SHA-1 tarafından tanımlanmıştır, gelecekte örneğin SHA-256 olarak değiştirilebilir (havuz geçişi ile). Ancak etiket aynı olacaktır. :) Bir etiketin ana özelliği nesneye işaret etmektir. Bir etiket dahili olarak SHA-1'i veya başka bir şeyi kullanabilir, bu yalnızca Git'in iç kısımları ile ilgilidir.
Olleg

Ben anladım. (Veya bunu okuyan herkes) (veya Ama eğer senaryo , daha da kötüsü) yeni bir hash algoritmasına başarısız olabilir daha sonraki bir noktada (ilk satır) uygulamaya çalışan bir idam ifade ile ilk satırı yerine nerede, (üreten bu hash) başarılı olmaya devam edecektir.
RomainValeri

Bunu, boş ağaç hashini otomatik olarak oluşturma yöntemlerinden biriyle birleştirirseniz, bunu ileride kanıtlayabilirsiniz (@RomainValeri'nin önerdiği gibi). Bununla birlikte, bana git rev-parsekalsaydı, (a) boş ağaç hashini ve (b) null-commit hashini üretmek için yeni bayraklar veya anahtar sözcükler veya bu satırlar boyunca bir şey olurdu. Bunların her ikisi de komut dosyalarında yararlı olacak ve önerilen SHA-256 değişikliklerine karşı koruma sağlayacaktır.
torek

Tamam, değişti. Ancak bu "en basit yol" olmayacak. :)
Olleg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.