¿Arreglar una cabeza separada de Git?

1455

Estaba trabajando en mi repositorio y noté que un archivo tenía cambios locales. Ya no los quería, así que eliminé el archivo, pensando que solo podía sacar una copia nueva. Quería hacer el equivalente Git de

svn up .

Usar git pullno parecía funcionar. Algunas búsquedas aleatorias me llevaron a un sitio donde alguien recomendaba hacer

git checkout HEAD^ src/

( srces el directorio que contiene el archivo eliminado).

Ahora descubro que tengo la cabeza separada. No tengo idea de qué es eso. ¿Cómo puedo deshacer?

Daniel
fuente
69
git checkout masterte llevará de vuelta a la rama maestra. Si desea borrar cualquier cambio de copia de trabajo, probablemente desea hacerlo git reset --hard.
Abe Voelker
si no te has comprometido, podrías haberlo hechogit checkout -- src/
thesummersign
Prueba esto: enlace . En resumencreate temp branch - checkout temp branch - checkout master - delete temp branch
fidev
@AbeVoelker ¿Qué quisiste decir en los comentarios de working copy changes? ¿Se refiere a los cambios que realizó en los archivos después de verificar otra confirmación (es decir, los cambios que realizó mientras estaba en un estado de cabeza separada)?
Minh Tran

Respuestas:

2149

Cabeza separada significa que ya no estás en una rama, has verificado una sola confirmación en el historial (en este caso, la confirmación anterior a HEAD, es decir, HEAD ^).

Si desea eliminar sus cambios asociados con el HEAD separado

Solo necesita verificar la sucursal en la que estaba, p. Ej.

git checkout master

La próxima vez que haya cambiado un archivo y desee restaurarlo al estado en que se encuentra en el índice, no elimine el archivo primero, solo hágalo

git checkout -- path/to/foo

Esto restaurará el archivo foo al estado en que se encuentra en el índice.

Si desea mantener sus cambios asociados con el HEAD separado

  1. Ejecutar git branch tmp: esto guardará sus cambios en una nueva rama llamada tmp.
  2. correr git checkout master
  3. Si desea incorporar los cambios que realizó master, ejecute git merge tmpdesde la masterrama. Deberías estar en la masterrama después de correr git checkout master.
ralphtheninja
fuente
66
"Esto restaurará el archivo foo al estado que tenía antes de que le hicieras cambios". -> lo restaurará al estado en que se encuentra en el índice - edite
Mr_and_Mrs_D
88
¿Por qué ocurre este error en primer lugar? Esta es una de las cosas por las que odio a git: comportamiento totalmente aleatorio a veces. Nunca tuve tales problemas con Mercurial.
Violet Giraffe
97
@VioletGiraffe No es un error ni algo aleatorio: es simplemente el estado en el que se encuentra su repositorio cuando finaliza una confirmación anterior. La "Cabeza separada" sirve como una advertencia de que también puede crear o señalar una rama si tiene la intención de hacer algún trabajo desde ese punto. Pero si simplemente desea ver esa etiqueta o confirmar, no hay nada de malo en estar en un estado de cabeza separada.
Neil Neyman
22
No haga esto si se ha comprometido con la cabeza desprendida, vea otras respuestas. Si lo hace, puede consultar las menciones anteriores de git en la cabezaPrevious HEAD position was 7426948...
KCD
99
@VioletGiraffe: tienes un modelo mental de lo que está sucediendo basado en Mercurial, pero estás usando Git. Si no está dispuesto a ajustar su modelo mental para que se ajuste al modelo de Git, las cosas seguirán pareciendo aleatorias. Es como si estuvieras caminando afuera con las gafas de realidad virtual puestas, y crees que estás volando un avión pero realmente estás cruzando la calle. Te atropellarán los autos.
iconoclasta
477

Si ha cambiado archivos que no desea perder, puede enviarlos. Los he comprometido en el modo separado y después de eso puedes pasar a una rama temporal para integrarlos más tarde en master.

git commit -m "....."
git branch my-temporary-work
git checkout master
git merge my-temporary-work

Extraído de:

Qué hacer con el compromiso realizado en una cabeza separada

Toni Gamez
fuente
27
Considero que esta es la solución preferida, especialmente si desea conservar los cambios que realizó cuando desprotegió la versión individual.
adswebwork
10
@adswebwork: estoy de acuerdo. Todas las otras respuestas sugieren volver a un estado anterior y perder los cambios realizados localmente en el estado de la cabeza separada.
Sk8erPeter
66
¿por qué no git stash? Como eso es lo primero que viene a mi mente. crear una nueva sucursal será una exageración.
thesummersign
2
también podría git rebase my-temporary-worky luego eliminar la rama git branch -d my-temporary-workpara que parezca que se comprometió con la rama correcta en primer lugar.
Zoltán
@geekay git stashsuena como la herramienta perfecta para este caso. ¿Podría por favor escribir una respuesta con los pasos sugeridos para lograr eso?
Zoltán
157

Una solución sin crear una rama temporal.

Cómo salir (“arreglar”) el estado HEAD separado cuando ya cambió algo en este modo y, opcionalmente, desea guardar sus cambios:

  1. Confirma los cambios que deseas conservar. Si desea hacerse cargo de cualquiera de los cambios que realizó en el estado HEAD separado, confírmalos. Me gusta:

    git commit -a -m "your commit message"
    
  2. Descarte los cambios que no desea conservar. El restablecimiento completo descartará cualquier cambio no confirmado que haya realizado en el estado HEAD separado:

    git reset --hard
    

    (Sin esto, el paso 3 fallaría, quejándose de los archivos no confirmados modificados en el HEAD separado).

  3. Mira tu sucursal. Salga del estado HEAD separado al verificar la rama en la que trabajó antes, por ejemplo:

    git checkout master
    
  4. Asume tus compromisos. Ahora puede hacerse cargo de los compromisos que realizó en el estado HEAD separado mediante la selección de cereza, como se muestra en mi respuesta a otra pregunta .

    git reflog
    git cherry-pick <hash1> <hash2> <hash3> …
    
Tanius
fuente
La git reset --hardexactitud se fue que necesitaba, porque quiero que el de aguas arriba, siendo la fuente y los cambios locales debe ser eliminado.
Markus Zeller
Gran respuesta, esto funcionó para mí
MGLondon
130

Cabeza separada significa:

  1. Ya no estás en una rama,
  2. Has verificado una sola confirmación en el historial

Si no tiene cambios: puede cambiar a maestro aplicando el siguiente comando

  git checkout master

Si tiene cambios que desea conservar:

En el caso de un HEAD desconectado, los commits funcionan de manera normal, excepto que no se actualiza ninguna rama con nombre. Para actualizar la rama maestra con sus cambios confirmados, haga una rama temporal donde se encuentre (de esta manera la rama temporal tendrá todos los cambios confirmados que ha realizado en el HEAD separado), luego cambie a la rama maestra y combine la rama temporal con el maestro.

git branch  temp
git checkout master
git merge temp
Razan Paul
fuente
2
perfecto, luego de quitar la temperatura de la rama
Davi Menezes
64

Esto es lo que acabo de hacer después de darme cuenta de que tenía la cabeza despegada y que ya había realizado algunos cambios.

Cometí los cambios.

$ git commit -m "..."
[detached HEAD 1fe56ad] ...

Recordé el hash (1fe56ad) de la confirmación. Luego revisé la rama en la que debería haber estado.

$ git checkout master
Switched to branch 'master'

Finalmente apliqué los cambios del commit a la rama.

$ git cherry-pick 1fe56ad
[master 0b05f1e] ...

Creo que esto es un poco más fácil que crear una rama temporal.

Philippe Gerber
fuente
2
Esta debería ser la respuesta. Recupera tus archivos nucleados.
BlindWanderer
2
Sí, esto es realmente lo más simple: lo suficientemente simple como para recordar sin buscar en la web la próxima vez que suceda. Comprometerse, anotar hash, regresar a la sucursal con la que desea comprometerse y git cherry-pick <hash>.
Mason
Gracias por la solucion. Esto ayudó También puedo agregar que tuve que hacer un "maestro de origen de git push" para que mi maestro y origen / maestro apuntaran a la misma confirmación.
turnip424
1
Esta es esencialmente la respuesta de Tanius (publicada más de un año antes).
Peter Mortensen
Gracias, esta alegre elección revierte los últimos cambios de cabeza de separación
Omega Cube
55

Si realizó algunos cambios y luego se dio cuenta de que está en una cabeza separada, hay una solución simple para eso: stash -> checkout master -> stash pop:

git stash
git checkout master   # Fix the detached head state
git stash pop         # Or for extra safety use 'stash apply' then later 
                      #   after fixing everything do 'stash drop'

Tendrá sus cambios no comprometidos y la CABEZA "adjunta" normal, como si nada hubiera pasado.

mojuba
fuente
2
He marcado este chico malo: ahorra haciendo una rama temporal. Trabajó un placer.
Tim Tyler
1
A menudo termino en un estado HEAD separado después de revisar un submódulo git y luego hacer cambios en él. Creo que esta es la mejor y más fácil solución para arreglar las cosas y poder preservar mis cambios.
user5359531
1
¿Esto no funciona si ya ha realizado cambios en un estado separado?
Danijel
40

Cuando revisas una confirmación específica git, terminas en una cabeza separada estado de ... es decir, su copia de trabajo ya no refleja el estado de una referencia con nombre (como "maestro"). Esto es útil para examinar el estado pasado del repositorio, pero no lo que desea si realmente está intentando revertir los cambios.

Si ha realizado cambios en un archivo en particular y simplemente desea descartarlos, puede usar el checkoutcomando de esta manera:

git checkout myfile

Esto descartará cualquier cambio no confirmado y revertirá el archivo a cualquier estado que tenga en la cabecera de su rama actual. Si desea descartar los cambios que ya ha confirmado, puede usar el resetcomando. Por ejemplo, esto restablecerá el repositorio al estado de la confirmación anterior, descartando cualquier cambio posterior:

git reset --hard HEAD^

Sin embargo, si está compartiendo el repositorio con otras personas, a git resetpuede ser perjudicial (porque borra una parte del historial del repositorio). Si ya ha compartido los cambios con otras personas, generalmente desea vergit revert verlos, lo que genera un "anticommite", es decir, crea una nueva confirmación que "deshace" los cambios en cuestión.

El Libro Git tiene más detalles.

larsks
fuente
1
Como dije en la respuesta de @ ralphtheninja, git checkout path/to/foopodría entrar en conflicto git checkout some-branch, por lo que sería mejor usarlo git checkout -- path/to/foopara evitar estos conflictos.
Diego Lago
30

HEAD está en un puntero y, como resultado, apunta, directa o indirectamente , a un commit particular:

  HEAD adjunto significa que está unido a alguna rama (es decir, apunta a una rama).
Independiente medios cabeza que se no conectado a ningún rama, es decir, que apunta directamente a algunos commit.

ingrese la descripción de la imagen aquí

En otras palabras:

  • Si apunta a una confirmación directamente , la CABEZA se separa .
  • Si apunta a un compromiso indirectamente (es decir, apunta a una rama, que a su vez apunta a un compromiso), la CABEZA se adjunta .

Para comprender mejor las situaciones con HEAD adjunto / desconectado, muestremos los pasos que conducen al cuadruplete de imágenes de arriba.

Comenzamos con el mismo estado del repositorio (las imágenes en todos los cuadrantes son las mismas):

ingrese la descripción de la imagen aquí


Ahora queremos realizar git checkout, con diferentes objetivos en las imágenes individuales (los comandos encima de ellos están atenuados para enfatizar que solo vamos a aplicar esos comandos):

ingrese la descripción de la imagen aquí


Esta es la situación después de ejecutar esos comandos:

ingrese la descripción de la imagen aquí

Como puede ver, HEAD apunta al objetivo del git checkoutcomando: a una rama (primeras 3 imágenes del cuadruplete) o (directamente) a un commit (la última imagen del cuadruplete).

El contenido del directorio de trabajo también se modifica para que esté de acuerdo con el compromiso apropiado (instantánea), es decir, con el compromiso señalado (directa o indirectamente) por el HEAD.


Así que ahora estamos en la misma situación que al comienzo de esta respuesta:

ingrese la descripción de la imagen aquí

MarianD
fuente
66
No lo leí, pero voté por las bonitas fotos que hiciste;).
Carlo Wood
@Carlo, gracias!
MarianD
22

Dado que el "estado de la cabeza separada" lo tiene en una rama temporal, simplemente use lo git checkout -que lo coloca en la última rama en la que estuvo.

Miguel
fuente
1
tenga cuidado, perderá cualquier compromiso que haya hecho cuando estaba en estado de cabeza separada.
Ajak6
@ Ajak6 Realmente no pierdes esos commits. Todavía están disponibles a través de git reflogy pueden transferirse a una nueva sucursal oa través de git cherry-pickuna sucursal existente. Ver esta pregunta .
tanius
7

Para aclarar aún más la respuesta de @Philippe Gerber, aquí está:

git cherry-pick

Antes cherry-pick, a git checkout masteres necesario en este caso. Además, sólo se necesita una commiten detached head.

Timo
fuente
6

Apéndice

Si la sucursal a la que desea regresar fue el último pago realizado, simplemente puede usar checkout @{-1}. Esto lo llevará de regreso a su pago anterior.

Además, puede alias este comando, por ejemplo, git global --config alias.prevpara que solo tenga que escribir git prevpara volver a la comprobación anterior.

David Brower
fuente
4

Estar en "cabeza separada" significa que HEAD se refiere a una confirmación específica sin nombre (como opuesta a una rama con nombre) (cf: https://git-scm.com/docs/git-checkout section Cabeza separada )

Para solucionar el problema, solo necesita seleccionar la rama seleccionada anteriormente por

git checkout @{-1}

Palmadita. ANDRIA
fuente
2

Cuando se encuentre en una situación de cabeza separada y cree nuevos archivos, primero asegúrese de que estos nuevos archivos se agreguen al índice, por ejemplo con:

git add .

Pero si solo ha cambiado o eliminado archivos existentes, puede agregar (-a) y confirmar con un mensaje (-m) al mismo tiempo a través de:

git commit -a -m "my adjustment message"

Luego, simplemente puede crear una nueva rama con su estado actual con:

git checkout -b new_branch_name

Tendrá una nueva sucursal y todos sus ajustes estarán allí en esa nueva sucursal. Luego puede continuar presionando hacia el control remoto y / o realizar el pago / extracción / fusión como lo desee.

DZet
fuente
1

Git me dijo cómo hacerlo.

si escribiste:

git checkout <some-commit_number>

Guardar el estado

git add .
git commit -m "some message"

Entonces:

 git push origin HEAD:<name-of-remote-branch>
Sterling Diaz
fuente
1

Quería mantener mis cambios, así que solucioné esto haciendo ...

git add .
git commit -m "Title" -m "Description"
(so i have a commit now example: 123abc)
git checkout YOURCURRENTBRANCH
git merge 123abc
git push TOYOURCURRENTBRANCH

ese trabajo para mi

CRLZXO
fuente
1

Normalmente HEADapunta a una rama. Cuando no está apuntando a una rama, en cambio, cuando apunta a un hash de confirmación 69e51, significa que tiene un HEAD separado. Debe señalar dos ramas para solucionar el problema. Puedes hacer dos cosas para arreglarlo.

  1. git checkout other_branch // No es posible cuando necesita el código en ese commit hash
  2. cree una nueva rama y apunte el hash de confirmación a la rama recién creada.

HEAD debe apuntar a una rama, no un hash de compromiso es la regla de oro.

Krishnadas PC
fuente
Es por eso que tuve este mismo error. Revisé una revisión y luego volví a revisar la revisión actual / más reciente en lugar de revisar la rama, que habría conectado la cabeza correctamente. Gracias por la ayuda.
Rahul Thakur
1

La cabeza separada significa que no ha desprotegido su sucursal correctamente o que ha desprotegido una sola confirmación.

Si encuentra un problema de este tipo, primero oculte los cambios locales para no perderlos.

Después de eso ... verifique la rama deseada con el comando:

Digamos que quieres ramificar MyOriginalBranch:

git checkout -b someName origin / MyOriginalBranch

Dhirendra Gautam
fuente
1

probablemente lo hiciste git reset --hard origin/your-branch .

Intenta solo git checkout your-branch

Johnny Cage
fuente
0
git pull origin master

trabajó para mi. Se trataba solo de dar explícitamente el nombre remoto y la rama.

Amjedonline
fuente
0

En mi caso, corro git status y vi que tenía algunos archivos sin seguimiento en mi directorio de trabajo.

Solo tenía que limpiarlos (ya que no los necesitaba) para ejecutar el rebase que quería realizar.

falsarella
fuente
0

Esto funciona para mí, asignará una nueva rama para la cabeza separada:

git checkout new_branch_name detached_head_garbage_name

Alok Gupta
fuente
0

El HEAD separado significa que actualmente no estás en ninguna rama. Si desea MANTENER sus cambios actuales y simplemente crear una nueva sucursal, esto es lo que debe hacer:

git commit -m "your commit message"
git checkout -b new_branch

Posteriormente, es posible que desee fusionar esta nueva rama con otras ramas. Siempre es útil el comando git "a dog" :

git log --all --decorate --oneline --graph
gebbissimo
fuente