¿Es confiable el objeto de árbol vacío semisecreto de git y por qué no tiene un nombre simbólico?

Resuelto torek asked hace 12 años • 3 respuestas

Git tiene un árbol vacío bien conocido, o al menos más o menos conocido, cuyo SHA1 es:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(Puedes ver esto en cualquier repositorio, incluso uno recién creado, con git cat-file -ty git cat-file -p). [ Edición realizada en 2020 : el ID de hash del árbol vacío SHA-256 es:

6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

como menciona VonC en su respuesta . Aparentemente mi pregunta fue unos 8 años antes. 😀]

Si trabaja duro y es muy cuidadoso, puede utilizar este árbol vacío para almacenar un directorio que no tiene archivos (consulte la respuesta a ¿Cómo agrego un directorio vacío a un repositorio git ?), aunque en realidad no es una gran idea.

Es más útil como argumento para git diff-treecuál de los ganchos de muestra hace.

Lo que me pregunto es,

  1. ¿Qué tan confiable es esto? Es decir, ¿alguna versión futura de git no tendrá un objeto git numerado 4b825dc642cb6eb9a060e54bf8d69288fbee4904?
  2. ¿Por qué no hay un nombre simbólico para el árbol vacío (o sí lo hay?).

(Una forma rápida y sucia de crear un nombre simbólico es poner el SHA1, por ejemplo, .git/Nulltree. Desafortunadamente, tienes que hacer esto para cada repositorio. Parece mejor simplemente poner el número mágico en los scripts, etc. Simplemente tengo una aversión general a números mágicos.)

torek avatar Mar 19 '12 12:03 torek
Aceptado

Este hilo menciona:

Si no recuerdas el árbol vacío sha1, siempre puedes derivarlo con:

git hash-object -t tree /dev/null

O, como propone Ciro Santilli en los comentarios :

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

O, como se ve aquí , de Colin Schimmelfing :

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

Así que supongo que es más seguro definir una variable con el resultado de ese comando como su árbol sha1 vacío (en lugar de depender de un "valor bien conocido").

Nota: Git 2.25.1 (febrero de 2020) propone en el compromiso 9c8a294 :

empty_tree=$(git mktree </dev/null)

# Windows (Command Prompt):
git mktree <NUL

# Windows (PowerShell):
$null | git mktree

Y agrega:

Como nota histórica, la función ahora conocida como repo_read_object_file()se enseñó al árbol vacío en 346245a1bb ("codificar el objeto del árbol vacío", 2008-02-13, Git v1.5.5-rc0 - merge ), y la función ahora conocida como oid_object_info()se enseñó al árbol vacío en c4d9986f5f (" sha1_object_info: examinar cached_objectla tienda también", 2011-02-07, Git v1.7.4.1).


Tenga en cuenta que verá que SHA1 aparece en algunos repositorios de GitHub cuando el autor quiere que su primera confirmación esté vacía (consulte la publicación del blog " Cómo inicializo mis repositorios de 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'

Te regalaré:

Árbol vacío SHA1

(¿Ves el árbol SHA1?)

Incluso puedes cambiar la base de tu historial existente encima de ese compromiso vacío (ver " git: ¿cómo insertar un compromiso como el primero, desplazando todos los demás? ")

En ambos casos, no confía en el valor SHA1 exacto de ese árbol vacío.
Simplemente sigue una de las mejores prácticas: inicializa tu repositorio con una primera confirmación vacía .


Para hacer eso:

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"

Eso generará una confirmación con un SHA1 específico para su repositorio, nombre de usuario, correo electrónico y fecha de creación (lo que significa que el SHA1 de la confirmación en sí será diferente cada vez).
Pero el árbol al que hace referencia esa confirmación será 4b825dc642cb6eb9a060e54bf8d69288fbee4904el árbol vacío SHA1.

git log --pretty=raw

commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <[email protected]> 1381232247 +0200
committer VonC <[email protected]> 1381232247 +0200

    initial empty commit

Para mostrar solo el árbol de una confirmación (muestre el árbol de confirmación SHA1):

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

Si esa confirmación, que hace referencia a un árbol vacío, es de hecho su primera confirmación, puede mostrar ese árbol vacío SHA1 con:

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

(y eso incluso funciona en Windows, con comandos de Gnu en Windows )


Como se comenta a continuación , al usar git diff <commit> HEAD, esto mostrará todos sus archivos en la rama actual HEAD:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

Nota: ese valor de árbol vacío se define formalmente en cache.h.

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Desde Git 2.16 (primer trimestre de 2018), se usa en una estructura que ya no está vinculada (solo) a SHA1, como se ve en la confirmación eb0ccfd :

Cambie las búsquedas de blobs y árboles vacíos para usar la abstracción de hash

Cambie los usos de empty_tree_oidy empty_blob_oidpara usar la current_hashabstracción que representa el algoritmo hash actual en uso.

Ver más en "¿ Por qué Git no usa SHA más moderno? ": es SHA-2 , desde Git 2.19 (tercer trimestre de 2018)


Con Git 2.25 (primer trimestre de 2020), las pruebas se están preparando para una transición SHA-2 y están involucrando el árbol vacío.

Ver compromiso fa26d5e , compromiso cf02be8 , compromiso 38ee26b , compromiso 37ab8eb , compromiso 0370b35 , compromiso 0253e12 , compromiso 45e2ef2 , compromiso 79b0edc , compromiso 840624f , compromiso 32a6707 , compromiso 440bf91 , compromiso 0b408ca , compromiso 2eabd38 (28 de octubre de 2019) y confirma 1bcef51 , confirma ecde49b (5 de octubre de 2019) por brian m. carlson ( bk2204) .
(Fusionado por Junio ​​C Hamano -- gitster-- en el compromiso 28014c1 , 10 de noviembre de 2019)

t/oid-info: agrega valores de árbol vacío y blob vacíos

Firmado por: brian m. carlson

El conjunto de pruebas eventualmente aprenderá a ejecutar utilizando un algoritmo distinto de SHA-1. Como preparación para esto, enseñe a la test_oidfamilia de funciones cómo buscar los valores del blob vacío y del árbol vacío para poder usarlos.

Así que t/oid-info/hash-infoahora incluye:

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

El SHA2 " 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" es el nuevo 4b825dc642cb6eb9a060e54bf8d69288fbee4904árbol vacío SHA1 " ".

VonC avatar Mar 19 '2012 07:03 VonC

Aquí está la respuesta sobre cómo crear un compromiso de árbol vacío incluso en el caso de que el repositorio aún no esté vacío. https://stackoverflow.com/a/14623458/9361507

Pero prefiero que "vacío" sea una etiqueta, pero no una rama. La forma sencilla es:

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

Porque la etiqueta puede apuntar directamente al árbol, sin compromiso. Ahora para obtener todos los archivos en el árbol de trabajo:

git diff --name-only empty

O lo mismo con las estadísticas:

git diff --stat empty

Todos los archivos como diferencias:

git diff empty

Verifique los espacios en blanco en todos los archivos:

git diff --check empty
Olleg avatar Mar 01 '2019 13:03 Olleg

Escribí una publicación de blog con dos formas diferentes de encontrar el hash: http://colinschimmelfing.com/blog/gits-empty-tree/

Si alguna vez cambiara por algún motivo, puede utilizar las dos formas siguientes para encontrarlo. Sin embargo, me sentiría bastante seguro al usar el hash en alias .bashrc, etc., y no creo que eso cambie pronto. Como mínimo, probablemente sería una versión importante de git.

Las dos formas son:

  1. La respuesta anterior:git hash-object -t tree --stdin < /dev/null
  2. Simplemente iniciando un repositorio vacío y luego ejecutándolo git write-treeen ese nuevo repositorio, el hash será generado por git write-tree.
schimmy avatar Oct 06 '2013 18:10 schimmy