¿Cuál es la diferencia entre HEAD, el árbol de trabajo y el índice, en Git?

488

¿Alguien puede decirme la diferencia entre HEAD, árbol de trabajo e índice, en Git?

Por lo que entiendo, todos son nombres para diferentes ramas. ¿Es correcta mi suposición?


Editar

encontré esto

Un único repositorio de git puede rastrear un número arbitrario de ramas, pero su árbol de trabajo está asociado con solo una de ellas (la rama "actual" o "extraída"), y HEAD apunta a esa rama.

¿Significa esto que HEAD y el árbol de trabajo son siempre iguales?

Joyce Babu
fuente
26
Con respecto a su edición: absolutamente no. HEADes el commit en la punta de la rama actual. Si acaba de retirar la rama, es decir, no tiene archivos modificados, entonces su contenido coincide con el árbol de trabajo. Tan pronto como modifiques algo, ya no coincidirá.
Cascabel
66
Creo que tienes que leer esto: think-like-a-git.net
Andrzej Duś
55
También agregaría un Staging Areaa esa lista. Lo que es HEAD, Working Tree, IndexyStaging Area
Verde
2
La última oración de @Jefromi's sería más clara como:> Tan pronto como modifiques algo, el árbol de trabajo ya no coincide con la confirmación HEAD
starscream_disco_party
3
Para cualquier lectura de esto en el futuro, la mejor manera de comprender realmente algunas de estas respuestas es ver y sentir y conceptualizar visualmente lo que está sucediendo: esta es la mejor herramienta para aprender git: onlywei.github.io/explain-git-with -d3 / # fetchrebase
BKSpurgeon

Respuestas:

579

Algunas otras buenas referencias sobre esos temas:

texto alternativo

Yo uso el índice como punto de control .

Cuando estoy a punto de hacer un cambio que podría salir mal, cuando quiero explorar alguna dirección en la que no estoy seguro si puedo seguir adelante o incluso si es una buena idea, como una refactorización o cambio conceptual exigente tipo de representación: controlo mi trabajo en el índice. Si este es el primer cambio que he realizado desde mi última confirmación, entonces puedo usar el repositorio local como punto de control, pero a menudo tengo un cambio conceptual que estoy implementando como un conjunto de pequeños pasos. Quiero hacer un punto de control después de cada paso, pero guarde el commit hasta que haya vuelto a trabajar, código probado.

Notas:

  1. el espacio de trabajo es el árbol de directorios de los archivos (de origen) que ve y edita.

  2. El índice es un archivo binario único, grande, <baseOfRepo>/.git/indexque enumera todos los archivos de la rama actual, sus sumas de comprobación sha1 , marcas de tiempo y el nombre del archivo; no es otro directorio con una copia de los archivos.

  3. El repositorio local es un directorio oculto ( .git) que incluye un objectsdirectorio que contiene todas las versiones de cada archivo en el repositorio (ramas locales y copias de ramas remotas) como un archivo comprimido "blob".

No piense en los cuatro 'discos' representados en la imagen de arriba como copias separadas de los archivos repos.

texto alternativo

Básicamente son referencias nombradas para las confirmaciones de Git. Hay dos tipos principales de referencias: etiquetas y cabezas.

  • Las etiquetas son referencias fijas que marcan un punto específico en la historia, por ejemplo v2.6.29.
  • Por el contrario, las cabezas siempre se mueven para reflejar la posición actual del desarrollo del proyecto.

texto alternativo

(nota: como se ha comentado por Timo Huovinen , esas flechas no lo que los compromete señalan son, que es el fin del flujo de trabajo , básicamente mostrando flechas como 1 -> 2 -> 3 -> 4donde 1se cometen la primera y 4es la última)

Ahora sabemos lo que está sucediendo en el proyecto.
Pero para saber qué está sucediendo aquí, en este momento hay una referencia especial llamada HEAD. Tiene dos propósitos principales:

  • le dice a Git qué compromiso tomar archivos de cuando realiza el pago, y
  • le dice a Git dónde poner nuevas confirmaciones cuando se compromete.

Cuando lo ejecuta git checkout ref, apunta HEADa la referencia que ha designado y extrae archivos de ella. Cuando lo ejecuta git commit, crea un nuevo objeto de confirmación, que se convierte en hijo de current HEAD. Normalmente HEADapunta a una de las cabezas, por lo que todo funciona bien.

texto alternativo

VonC
fuente
20
Después de leer muchas veces sobre git lot, nunca lo entiendo completamente. Me sentí realmente frustrado. Quiero usar la palabra f; Pero estoy en comunidad! ¿Has mencionado cabezas pero en las imágenes de arriba siempre hay una sola CABEZA donde están las cabezas f ** ng restantes? "Normalmente HEAD apunta a una de las cabezas, por lo que todo funciona bien". Te ruego que expliques esto, declaración de Ur.
2014
12
@neckTwi HEAD es la confirmación actual con la que está trabajando ( stackoverflow.com/a/964927/6309 ). Por lo general, es una de las "cabezas de rama" (una de las confirmaciones a las que hacen referencia las ramas, que representa la punta de dichas ramas). Pero puede pagar (y trabajar) cualquier confirmación. Si comprueba un commit que no es uno de los encabezados (rama), está en modo "HEAD separado": stackoverflow.com/a/3965714/6309
VonC
1
@Imray, estoy de acuerdo, pero así es como encontré esas fotos hace 5 años ( hades.name/blog/2010/01/28/… )
VonC
11
Con respecto al índice, creo que lo más útil que se puede decir es "El índice es solo otro nombre para el área de preparación", como dijo @ ashraf-alam. Siento que la mayor parte del tiempo en discusión se conoce como el área de preparación, por lo que no hice automáticamente la conexión de que era lo mismo que el índice.
Pete
1
@Pete, estoy de acuerdo. Para obtener más información sobre la diferencia entre caché e índice, consulte mi otra respuesta stackoverflow.com/a/6718135/6309
VonC
137

La diferencia entre HEAD (rama actual o último estado confirmado en la rama actual), índice (también conocido como área de preparación) y árbol de trabajo (el estado de los archivos en la caja) se describe en la sección "Los tres estados" de los "1.3 Conceptos básicos de Git " capítulo del libro Pro Git de Scott Chacon (licencia Creative Commons).

Aquí está la imagen que lo ilustra de este capítulo:

Operaciones locales: directorio de trabajo vs. área de preparación (índice) vs repositorio git (HEAD)

En la imagen de arriba, "directorio de trabajo" es lo mismo que "árbol de trabajo", el "área de ensayo" es un nombre alternativo para git "index", y HEAD apunta a la rama actualmente desprotegida, que apunta a la última confirmación en el " directorio git (repositorio) "

Tenga en cuenta que git commit -aorganizaría los cambios y se comprometería en un solo paso.

Jakub Narębski
fuente
1
"Una imagen vale mas que mil palabras". Gracias Jakub .. Y gracias por el enlace.
Joyce Babu
55
Nota: working treeparece ser preferido a working directoryhoy en día. Ver github.com/git/git/commit/…
VonC
3
Esta imagen no es exactamente precisa porque el Área de ensayo está contenida en un solo archivo llamado "índice", y ese archivo de índice está en la raíz del directorio .git. Entonces, si define el repositorio como el directorio .git, el área de preparación está técnicamente dentro del repositorio. La tercera columna estaría mejor etiquetada como "Objeto de árbol raíz de HEAD" para indicar que los archivos extraídos provienen de un objeto de confirmación y que la confirmación escribe un nuevo árbol en un objeto de confirmación: HEAD señala ambos objetos de confirmación.
Jazimov
@Jazimov Probablemente tengas razón, pero como él escribió, tomó esa foto del conocido libro Pro Git, y proporcionó un enlace. Por lo tanto, si la imagen se puede mejorar o incluso está mal, alguien debería decirle a los autores de ese libro ... En general, estaría dispuesto a hacerlo, pero para ser honesto, todavía soy un principiante y aún no lo he hecho. entendí lo que dijiste, así que definitivamente soy la persona equivocada en ese caso.
Binarus
@Binarus: El peligro en la reproducción generalizada de imágenes como esta es que sirve para propagar una "tergiversación" hecha por un autor / libro. Creo que este es un caso de interpretaciones literales versus funcionales aquí: en el sentido literal, el índice de hecho está contenido en el repositorio si define el repositorio como todo en la carpeta .git. Sin embargo, en el sentido funcional, el índice ayuda a Git a mantener el DAG en el repositorio y puede considerarse un ser externo al mismo.
Jazimov
64

Su árbol de trabajo es lo que está realmente en los archivos en los que está trabajando actualmente.

HEADes un puntero a la bifurcación o confirmación que verificó por última vez, y que será el padre de una nueva confirmación si la realiza. Por ejemplo, si está en la masterrama, entonces HEADseñalará master, y cuando se comprometa, esa nueva confirmación será un descendiente de la revisión que masterseñaló, y masterse actualizará para apuntar a la nueva confirmación.

El índice es un área de preparación donde se prepara la nueva confirmación. Esencialmente, el contenido del índice es lo que irá en la nueva confirmación (aunque si lo hace git commit -a, esto agregará automáticamente todos los cambios a los archivos que Git conoce en el índice antes de confirmar, por lo que confirmará el contenido actual de su árbol de trabajo ) git addagregará o actualizará archivos del árbol de trabajo a su índice.

Brian Campbell
fuente
Muchas gracias por la explicación Brian. Entonces, el árbol de trabajo contiene todos los cambios no confirmados. Si confirmo mis cambios con git commit -a, en ese momento específico mi Árbol de trabajo e Índice serán los mismos. Cuando llegue a mi repositorio central, los tres serán lo mismo. ¿Estoy en lo correcto?
Joyce Babu
3
@Vinod Bastante. Puede tener archivos en su árbol de trabajo que Git no conoce, y con los que no se comprometerá git commit -a(debe agregarlos git add), por lo que su árbol de trabajo puede tener archivos adicionales que su índice, su repositorio local o su repositorio remoto no tiene.
Brian Campbell
2
@Vinod: el árbol de trabajo y el índice pueden volverse iguales sin comprometerse (git add actualiza el índice del árbol de trabajo, y git checkout <path> actualiza el árbol de trabajo del índice). HEADse refiere a la confirmación más reciente, por lo que cuando se compromete, se actualiza HEADa su nueva confirmación, que coincide con el índice. Empujar no tiene mucho que ver con eso: crea ramas en las ramas de coincidencia remota en su repositorio local.
Cascabel
45

Árbol de trabajo

Su árbol de trabajo son los archivos en los que está trabajando actualmente.

Índice de Git

  • El "índice" de git es donde coloca los archivos que desea comprometer en el repositorio de git.

  • El índice también se conoce como caché , caché de directorio , caché de directorio actual , área de ensayo , archivos etapas .

  • Antes de "confirmar" (registrar) archivos en el repositorio de git, primero debe colocar los archivos en el "índice" de git.

  • El índice no es el directorio de trabajo: puede escribir un comando como git status, y git le dirá qué archivos en su directorio de trabajo se han agregado al índice git (por ejemplo, usando el git add filenamecomando).

  • El índice no es el repositorio de git: los archivos en el índice de git son archivos que git confirmaría en el repositorio de git si usara el comando git commit.

Ashraf Alam
fuente
1
Tenga en cuenta que Git 2.5 traerá múltiples árboles de trabajo ( stackoverflow.com/a/30185564/6309 ). +1
VonC
3
No estoy seguro de que "El índice no sea el directorio de trabajo" es 100% correcto. Debería ser "El índice no es el directorio de trabajo, pero incluye todo el directorio de trabajo + los cambios que desea confirmar después". ¿Prueba? vaya a un repositorio git, reset --hard HEADpara asegurarse de que su índice == su árbol de trabajo. y luego: mkdir history && git checkout-index --prefix history/ -aEl resultado es una duplicación de todo su árbol de trabajo en su history/directorio. Ergo git index> = directorio de trabajo git
Adam Kurkiewicz
3
Index no es el directorio de trabajo y no tiene que incluir el directorio de trabajo. Index es solo un archivo dentro del repositorio de git que almacena información de lo que desea confirmar.
Boon
3
"El" índice "contiene una instantánea del contenido del árbol de trabajo, y es esta instantánea la que se toma como el contenido de la próxima confirmación. Por lo tanto, después de realizar cualquier cambio en el directorio de trabajo y antes de ejecutar el comando de confirmación, debe utilizar el comando add para añadir los archivos nuevos o modificados con el índice"( git-scm.com/docs/git-add )
anth
3
@AdamKurkiewicz: la prueba falla si primero echo untracked-data > untracked-file, antes o después de los pasos git reset --HARDy git checkout-index. Encontrará que el archivo no rastreado no está en el historydirectorio. También puede modificar tanto el índice como el árbol de trabajo de forma independiente, aunque modificar el índice sin tocar primero el árbol de trabajo es difícil (requiere usar git update-index --index-info).
torek