¿Verificando una confirmación anterior y manteniendo la cabeza en la rama maestra?

85

Actualmente, para cambiar a otro git commit (en la misma rama ... en realidad, ¡en la rama maestra!), Estoy ejecutando el comando

git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

Ahora, cada vez que hago esto, git me dice que ahora tengo la cabeza separada. ¿Cómo voy a una confirmación anterior y sigo manteniendo el encabezado en la misma rama?

elisio devorado
fuente
1
Después de ejecutar ese comando, su referencia HEAD cambia a esa confirmación. No tiene sentido querer que HEAD también apunte a otra parte.
Greg Hewgill
Por lo que entiendo del mensaje de git, no apunta a ninguna parte , lo cual no es deseable.
Devoró elisio
1
El mensaje que muestra Git cuando revisa una confirmación específica como la que dice "HEAD ahora está en ea3d5ed ...", lo que le dice que HEAD está apuntando a alguna parte. Simplemente está apuntando a algún lugar que no tiene ningún otro nombre excepto HEAD (por el momento, ya que un git checkouta otro compromiso o nombre de rama moverá HEAD a ese nuevo lugar).
Greg Hewgill
¿Las respuestas dadas explican esto adecuadamente, o hay algo en lo que podríamos ser más claros? Me complacerá aclararle mi respuesta si no responde a su pregunta.
Brian Campbell
Si vino aquí buscando una forma de verificar otra confirmación mientras mantiene el HEAD completamente sin cambios (por ejemplo, para volver a una confirmación anterior): git revert --no-commit 0766c053..HEADhará esto, dónde 0766c053está la confirmación que desea verificar. Esto es de stackoverflow.com/a/21718540/525872 .
Jo Liss

Respuestas:

193

La mayoría de las veces, cuando hago esto, realizo el pago en una rama temporal:

git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

Luego, cuando termine, elimino la rama

Nick Canzoneri
fuente
80

Depende de lo que quieras hacer cuando revises esa confirmación. Si todo lo que está haciendo es verificarlo para poder construir o probar esa revisión, entonces no hay nada de malo en trabajar con un cabezal separado. Solo recuerde verificar una rama real antes de realizar cualquier confirmación ( git checkout masterpor ejemplo), para que no cree confirmaciones que no estén incluidas en ninguna rama.

Sin embargo, si desea realizar más confirmaciones a partir de ese punto, debe crear una rama. Si realiza confirmaciones a las que no hace referencia una rama, pueden perderse fácilmente y, finalmente, el recolector de basura de git las limpiará, ya que nada se refiere a ellas. Puede crear una nueva rama ejecutando:

git checkout -b newbranch ea3d5ed

Para ayudar a visualizar, aquí hay algunos diagramas que demuestran cómo trabajar en una cabeza separada difiere de trabajar en una rama.

Comencemos con 3 confirmaciones en master, A, B y C. masteres la rama actual, por lo que HEADapunta a master, que apunta a confirmar C.

A B C
* - * - * <- maestro <- HEAD

Ahora, si nos comprometemos, git creará una confirmación que tiene C como padre (porque esa es la confirmación actual, apuntada desde HEADvia master), y se actualizará masterpara apuntar a esa nueva confirmación. Todas nuestras confirmaciones están ahora mastery HEADapuntan a la nueva confirmación master.

A B C D
* - * - * - * <- maestro <- HEAD

Ahora echemos un vistazo a B, dándonos un desapegado HEAD.

A B C D
* - * - * - * <- maestro
   ^
    \ - CABEZA

Todo funciona bien aquí; podemos mirar todos los archivos, construir nuestro programa, probarlo, etc. Incluso podemos crear nuevas confirmaciones; pero si lo hacemos, no hay ninguna rama en la que estemos, por lo que no podemos apuntar ninguna rama a esa nueva confirmación. Lo único que lo señala es HEAD:

A B C D
* - * - * - * <- maestro
    \
     * <- CABEZA
     mi

Si más tarde decidimos mastervolver a pagar, no habrá nada que se refiera a E.

A B C D
* - * - * - * <- maestro <- HEAD
    \
     *
     mi

Dado que no hay nada que se refiera a él, puede ser difícil de encontrar, y git considera que las confirmaciones sin referencias deben ser abandonadas (ocurren con bastante frecuencia si realizas una nueva base, o aplastes parches, o realizas otra manipulación divertida del historial; generalmente representan parches abandonados que ya no te importa). Después de una cierta cantidad de tiempo, git lo considerará basura, para ser descartado la próxima vez que se ejecute la recolección de basura.

Entonces, en lugar de verificar una revisión simple y obtener un encabezado separado, si siente que va a realizar más confirmaciones, debe usar git checkout -b branch Bpara crear una rama y verificarla. Ahora sus confirmaciones no se perderán, ya que se incluirán en una rama, a la que puede consultar fácilmente y fusionar más adelante.

A B C D
* - * - * - * <- maestro
   ^
    \ - rama <- HEAD

Si olvida hacer esto y crea confirmaciones desde una rama, no hay necesidad de preocuparse. Puede crear una rama que haga referencia a la revisión del cabezal con git checkout -b branch. Si ya ha vuelto a la masterrama y se da cuenta de que olvidó una confirmación perdida, puede encontrarla usando git reflog, que le mostrará un historial de lo que las confirmaciones HEADhan señalado durante los últimos días. Todo lo que todavía esté en el reflog no se recolectará como basura y, por lo general, las referencias se guardan en el reflog durante al menos 30 días.

Brian Campbell
fuente
No me queda del todo claro por qué cuando revisas un compromiso antiguo, la cabeza se desprende . ¿Quizás el problema está en lo que significa una cabeza separada ? Por otro lado, si comprobar un compromiso antiguo con una cabeza separada solo lo perderá, ¿por qué alguien lo haría? ¿Solo para perder el tiempo y probar cosas? ¿Por qué git lo permite, en primer lugar?
Devoró elisio
5
@devoured elysium "cabeza separada" significa que tienes una HEADreferencia que apunta directamente a un SHA-1 de una confirmación, en lugar de apuntar a una rama que, a su vez, apunta a una confirmación. Debido a que su cabeza no hace referencia a una rama, Git no sabe qué rama actualizar cuando agrega nuevas confirmaciones. Como expliqué al comienzo de mi respuesta, está perfectamente bien tener una cabeza separada si está volviendo a una versión anterior solo para compilar o probar el código; siempre puede volver a una sucursal con git checkout mastero similar. Solo es un problema si te comprometes mientras tienes la cabeza separada.
Brian Campbell
@BrianCampbell: después de realizar confirmaciones en la rama (donde se encuentra actualmente la cabeza), fusiona la rama en B y fusiona B en el maestro. ¿Que deberías hacer después?
amey1908
Tu explicación hizo que un montón de otras cosas hicieran clic para mí. Gracias. Por fin podría haber entendido git ...
Joe
8

Si simplemente desea volver a un compromiso anterior para jugar con él sin realizar ningún cambio, puede hacer

git co <previous-commit-id>

estará en una rama llamada "(sin rama)" después de este comando.

Confirma esto por

git br

Después de haber jugado con este código previamente comprometido, puede cambiar a la rama en la que estaba

git co <the-branch-you-were-on>

El "(sin rama)" se eliminará automáticamente. De esta manera, no es necesario crear una rama temporal.

Zack Xu
fuente
5

HEAD de Git es simplemente un puntero que dice lo que hay en el directorio de trabajo. Si desea verificar una confirmación que no es el encabezado de una rama, simplemente tiene que redirigir su HEAD para que apunte a esa confirmación. No hay forma de evitarlo. Puede crear una rama temporal en esa confirmación, pero HEAD se desviará del maestro de todos modos.

Esa es la breve explicación. Con suerte, la verbosidad a continuación ayudará a comprender en qué se diferencian HEAD y master:

Normalmente, las cosas se ven así:

C ← refs/heads/master ← HEAD 
↓
B
↓
A

Es decir: “El padre de C es B y el padre de B es A. El maestro de la rama apunta a C, y actualmente he verificado el contenido del maestro. Además, cuando me comprometa, el maestro se actualizará ".

Algunas suposiciones están implícitas en esto que son necesarias para una comprensión completa del gráfico de confirmación. Es decir, las confirmaciones se refieren solo a sus padres, y el contenido de una rama son las confirmaciones (y solo las confirmaciones) a las que se puede acceder siguiendo los enlaces principales. El contenido (sin modificar) del árbol de trabajo y el índice deben corresponder al compromiso nombrado por HEAD, ya sea indirectamente ("simbólico") o directamente ("separado").

Por lo tanto, si desea verificar una confirmación anterior, el HEAD debe actualizarse para que apunte a la confirmación deseada. git-checkouthace precisamente eso:

C ← refs/heads/master 
↓
B ← HEAD
↓
A

Ahora, ha dejado su rama detrás de usted, ya que está viendo algo viejo. Eso está perfectamente bien, como el consejo de la "cabeza desprendida" te dice con calma (énfasis mío):

Puede mirar a su alrededor, realizar cambios experimentales y confirmarlos, y puede descartar cualquier confirmación que realice en este estado sin afectar ninguna rama al realizar otra verificación.

Por otro lado, si bien el restablecimiento de la rama también coloca HEAD donde debe estar, ¡tendría un efecto muy diferente!

C
↓
B ← refs/heads/master ← HEAD
↓
A

La confirmación C se convertirá en basura, ya que ha declarado que ya no desea que forme parte de la rama maestra.

En resumen, todo lo que tienes que hacer es entender qué significa git con "HEAD": es dónde estás , no dónde está una rama determinada. Y si donde se encuentra no es el mismo que cuando una rama es, no hay más remedio que utilizar una cabeza separada.

(Quizás también busque en GitHub, gitk o gitweb para navegar por el historial de confirmaciones, si descarrilar su HEAD continúa molestándolo).

Josh Lee
fuente
1

La pregunta es un poco vaga, pero si solo desea cambiar archivos en su árbol de trabajo, simplemente puede hacer esto:

git checkout [commit|branch] -- .

A continuación, puede organizar los cambios y crear una nueva confirmación si lo desea. Esto es muy útil a veces.

Lari Hotari
fuente
0

Creo que entiendo tus preguntas. Esto es lo que encontré para solucionarlo. y no hay una solución GUI, solo puede usar el comando para resolverlo, y es realmente simple.

Paso 1: crea una etiqueta de la confirmación anterior a la que quieras volver.

como etiqueta v2.0

paso 2: git checkout v2.0

aquí está, ahora su HEAD apunta a la confirmación 'v2.0', pero el maestro sigue apuntando a la última confirmación.

C:\Program Files\Git\doc\git\html\git-checkout.html este documento puede ayudarlo

o escriba git help <pago>

León Lai
fuente