¿Cómo puede un repo de git de una input estar en estado de cabeza separada?

Mi entendimiento de HEAD separado en git: Has comprobado una versión anterior de tu código sin hacer una twig. Si intentas asignar un nuevo código, crearás una nueva confirmación con un enlace a la versión anterior, y esa será tu cabeza por el momento. La parte "separada" se refiere al hecho de que ha perdido cambios porque no hay una twig que indique la existencia de las confirmaciones más recientes. Si compromete algo nuevo, los nuevos cambios aparecerán en el logging, pero los cambios nuevos no lo harán. Uf, estoy confundido. Ilustrado:

A->B(HEAD) 'git checkout A' A (DETACHED HEAD) 'write a video game' 'git commit' A->C(HEAD) /// And B is lost unless you know how to scour the raw git objects for trees 

Ahora aquí está el estado de mi repository:

 🤖 ? git log --all --oneline --graph --decorate * 3c43b31 (HEAD, master) Original site files 🤖 ? git status HEAD detached at 3c43b31 Untracked files: (use "git add <file>..." to include in what will be committed) page.html page.css 

Confesión: este es el estado justo después de intentar revertir todos mis cambios a la única confirmación existente usando 'pago y envío'. y luego usando 'checkout 3c43b31', ninguno de los cuales funcionó.

Pregunta: ¿Por qué HEAD se separa? Solo hay un compromiso, y estamos sentados en él.

Pregunta: ¿Por qué mis cajas no funcionan?

Mi entendimiento de HEAD separado en git: Has comprobado una versión anterior de tu código sin hacer una twig.

Esto es de tipo correcto. Está mal en los detalles técnicos, que comienza a importar en su propia situación.

La definición precisa del estado "HEAD separado" es que el nombre HEAD convierte en un puntero a una ID de confirmación específica, en lugar de contener un nombre de twig .

El nombre de una twig siempre es un puntero a una identificación de confirmación específica. Este nombre apunta a la confirmación de sugerencia en esa twig (lo cual es un poco tonto ya que esta es solo la definición de la confirmación de punta: es a la que apunta el nombre de la twig). Es decir:

 A->B(HEAD) 

está cerca, pero no del todo bien. Lo que tenemos es en cambio:

  HEAD | v A <- B <-- master 

Es decir, HEAD apunta a master y master puntos a B (no a A ). Y, aunque parezca al revés (y la mayoría de las veces no necesita preocuparse de ninguna manera), el segundo compromiso B señala el primer compromiso A , en lugar de viceversa.

Con un HEAD separado, simplemente señalamos HEAD directamente a la confirmación:

  HEAD | v A <- B <-- master 

así que esto puede ocurrir siempre que haya al less una confirmación (debe haber alguna confirmación para que todos estos nombres apunten).

El command de git checkout es el que establece HEAD . Cuando lo pides:

 git checkout master 

establece HEAD para apuntar a master , sin cambiar el master en absoluto. Pero cuando le da una identificación de compromiso sin procesar (como al retirar una confirmación anterior), o la bandera de --detach , establece que HEAD apunte directamente a la confirmación, en lugar de señalar a HEAD con el nombre de la twig.

 A (DETACHED HEAD) 'write a video game' 'git commit' A->C(HEAD) /// And B is lost unless you know how to scour the raw git objects for trees 

De nuevo, esto está bastante cerca de ser correcto, pero las flechas apuntan hacia el otro lado (lo cual es bastante menor), y B no se pierde en absoluto (lo cual es bastante importante), porque el master todavía lo señala:

  B <-- master / A \ C <-- HEAD 

El problema ahora es que si usas git checkout master , la confirmación C se pierde. (El lugar secreto para encontrarlo está en el reflog para HEAD , pero esto sigue siendo un problema en el keister).

Cuando se encuentre en este estado, al usar git checkout -b newname , o git branch newname , se creará una nueva twig llamada newname , apuntando a commit C :

  B <-- master / A \ C <-- newname 

La diferencia entre usar git checkout -b y git branch tiene, por supuesto, que ver con HEAD :

 git checkout -b newname 

cambia a HEAD para que apunte a la nueva twig:

  B <-- master / A \ C <-- newname ^ | HEAD 

El uso de git branch para crear el nombre deja HEAD separado:

  B <-- master / A \ C <-- newname ^ | HEAD 

Entonces, de nuevo, "HEAD separada" solo significa "HEAD apunta directamente a un commit, sin desviarse a través de un nombre de twig primero".

En general, git checkout <sha1> un HEAD separado. Podrías considerar una CABEZA separada como una twig sin nombre. Otros commands como git rebase --onto <sha1> <sha1A> <sha1B> pueden dar como resultado un HEAD separado porque este command ejecuta git checkout <sha1B> internamente.

En tu caso, B no está perdido. Si estuviera en una sucursal, podría ejecutar git checkout <branch> para restaurar. Un HEAD separado es una twig sin nombre y tu twig anterior que apunta a B todavía está allí, por lo que puedes usar git checkout para alternar entre estas 2 twigs. Si estuvieras en un HEAD separado, podrías ejecutar git reflog o git log -g para encontrar el sha1 de B