software - git tutorial
¿Cómo puedo reconciliar HEAD desapegado con master/origen? (25)
Soy nuevo en las complejidades de ramificación de Git. Siempre trabajo en una sola sucursal y confirmo cambios, y luego presiono periódicamente a mi origen remoto.
En algún lugar recientemente, realicé un reinicio de algunos archivos para eliminarlos de la puesta en escena del commit, y luego hice un rebase -i
para deshacerme de un par de confirmaciones locales recientes. Ahora estoy en un estado que no entiendo muy bien.
En mi área de trabajo, el git log
muestra exactamente lo que esperaría: estoy en el tren correcto con los compromisos que no quería ir, y los nuevos allí, etc.
Pero acabo de ingresar al repositorio remoto, y lo que hay es diferente: un par de los compromisos que había matado en la rebase fueron empujados, y los nuevos cometidos localmente no están ahí.
Creo que "master / origin" está separado de HEAD, pero no estoy 100% claro en lo que significa, cómo visualizarlo con las herramientas de la línea de comandos y cómo solucionarlo.
Obtenga su compromiso separado en su propia rama
Simplemente ejecute git checkout -b mynewbranch
.
Luego ejecute git log
, y verá que commit ahora es HEAD
en esta nueva rama.
Acabo de encontrar este problema hoy y estoy bastante seguro de que lo resolví haciendo:
git branch temp
git checkout master
git merge temp
Estaba en la computadora de mi trabajo cuando me di cuenta de cómo hacerlo y ahora tengo el mismo problema en mi computadora personal. Así que tendré que esperar hasta el lunes cuando vuelva a la computadora del trabajo para ver exactamente cómo lo hice.
Como señaló Chris, tuve la siguiente situación.
git symbolic-ref HEAD
falla con fatal: ref HEAD is not a symbolic ref
Sin embargo, git rev-parse refs/heads/master
estaba apuntando a una buena confirmación desde donde podría recuperarme (en mi caso, la última confirmación y puede ver esa confirmación utilizando git show [SHA]
Hice muchas cosas desordenadas después de eso, pero lo que parece haberse solucionado es simplemente,
git symbolic-ref HEAD refs/heads/master
Y la cabeza se vuelve a colocar!
Cuando me encuentro personalmente en una situación, resulta que hice algunos cambios mientras no estoy en el master
(es decir, HEAD
está separado justo por encima del master
y no hay confirmaciones intermedias).
git stash # HEAD has same content as master, but we are still not in master
git checkout master # switch to master, okay because no changes and master
git stash apply # apply changes we had between HEAD and master in the first place
En lugar de hacer git checkout origin/master
solo haz git checkout master
entonces git branch
confirmará su rama.
En mi caso, ejecuté git status
y vi que tenía algunos archivos sin seguimiento en mi directorio de trabajo.
Para hacer que la rebase funcionara, solo tenía que limpiarlos (ya que no los necesitaba).
En palabras sencillas, el estado de HEAD desconectado significa que no está prestando atención a HEAD (o punta) de ninguna rama .
Entender con un ejemplo
Una rama en la mayoría de los casos es una secuencia de múltiples confirmaciones como:
Commit 1: master -> branch_HEAD (123be6a76168aca712aea16076e971c23835f8ca)
Commit 2: master -> 123be6a76168aca712aea16076e971c23835f8ca -> branch_HEAD (100644a76168aca712aea16076e971c23835f8ca)
Como puede ver arriba en el caso de una secuencia de confirmaciones, su rama apunta a su última confirmación. Entonces, en ese caso, si realiza un checkout para cometer 123be6a76168aca712aea16076e971c23835f8ca, entonces estaría en un estado de cabeza separada ya que HEAD de su sucursal apunta a 100644a76168aca712aea16076e971c23835f8ca y técnicamente está controlado en HEAD de no branch. Por lo tanto, estás en el estado HEAD desapegado.
Explicación teórica
En este Blog , se establece claramente que un repositorio Git es un árbol de confirmaciones, con cada confirmación apuntando a su antepasado con cada puntero de confirmación actualizado y estos punteros a cada rama se almacenan en los subdirectorios .git / refs. Las etiquetas se almacenan en .git / refs / tags y las ramas se almacenan en .git / refs / heads. Si observa alguno de los archivos, encontrará que cada etiqueta corresponde a un solo archivo, con un hash de confirmación de 40 caracteres y como se explicó anteriormente en @Chris Johnsen y @Yaroslav Nikitenko, puede consultar estas referencias.
Entré en un estado realmente tonto, dudo que alguien más lo encuentre útil ... pero por si acaso
git ls-remote origin
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b HEAD
6f96ad0f97ee832ee16007d865aac9af847c1ef6 refs/heads/HEAD
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b refs/heads/master
que eventualmente solucioné con
git push origin :HEAD
Esto funcionó perfectamente para mí:
1. git stash
para guardar sus modificaciones locales
Si quieres descartar los cambios.
git clean -df
git checkout -- .
git clean elimina todos los archivos sin seguimiento (advertencia: aunque no eliminará los archivos ignorados mencionados directamente en .gitignore, puede eliminar los archivos ignorados que residen en las carpetas) y git checkout borra todos los cambios no programados.
2. git checkout master
para cambiar a la rama principal (suponiendo que desee utilizar master)
3. git pull
to pull último commit de la rama master
4. git status
para comprobar que todo se ve bien
On branch master
Your branch is up-to-date with ''origin/master''.
Lo siguiente funcionó para mí (usando solo el maestro de sucursal):
git push origin HEAD:master
git checkout master
git pull
El primero empuja la CABEZA desprendida a un origen remoto.
El segundo se mueve al maestro de la rama.
El tercero recupera la CABEZA que se une al maestro de rama.
Pueden surgir problemas en el primer comando si se rechaza el empuje. Pero esto ya no sería un problema de cabeza separada, sino que se trata del hecho de que la CABEZA desconectada no tiene conocimiento de algunos cambios remotos.
Me encontré con este problema y cuando leí la respuesta más votada:
HEAD es el nombre simbólico de la confirmación actualmente verificada.
Pensé: ¡Ah-ha! Si HEAD
es el nombre simbólico de la confirmación de pago actual, puedo conciliarlo con el master
volviéndolo a basar con el master
:
git rebase HEAD master
Este comando:
- revisa
master
- identifica las confirmaciones de los padres de
HEAD
al puntoHEAD
divergido delmaster
- juega esos compromisos encima del
master
El resultado final es que todas las confirmaciones que estaban en HEAD
pero no master
están también en master
. master
permanece desprotegido.
Respecto al mando a distancia:
un par de los compromisos que había matado en la rebase fueron empujados, y los nuevos cometidos localmente no están ahí.
El historial remoto ya no puede avanzar más rápido usando su historial local. Tendrá que forzar-push ( git push -f
) para sobrescribir el historial remoto. Si tiene algún colaborador, generalmente tiene sentido coordinar esto con ellos para que todos estén en la misma página.
Después de empujar el master
al origin
remoto, se actualizará el origin/master
su rama de seguimiento remoto para que apunte a la misma confirmación que el master
.
Mira aquí para la explicación básica de la cabeza separada:
http://git-scm.com/docs/git-checkout
Línea de comando para visualizarla:
git branch
o
git branch -a
obtendrá salida como abajo:
* (no branch)
master
branch1
El * (no branch)
muestra que estás en cabeza separada.
Podría haber llegado a este estado haciendo un git checkout somecommit
etc., y le habría advertido lo siguiente:
Usted está en estado de ''cabeza desapegada''. Puede mirar a su alrededor, hacer cambios experimentales y confirmarlos, y puede descartar cualquier confirmación que realice en este estado sin afectar a las sucursales al realizar otra compra.
Si desea crear una nueva rama para retener las confirmaciones que cree, puede hacerlo (ahora o más adelante) utilizando de nuevo el comando -b con el comando de pago. Ejemplo:
git checkout -b new_branch_name
Ahora, para ponerlos en el maestro:
Haga un git reflog
o simplemente git log
y anote sus confirmaciones. Ahora git checkout master
y git merge
las confirmaciones.
git merge HEAD@{1}
Editar:
Para agregar, use git rebase -i
no solo para eliminar / eliminar los compromisos que no necesita, sino también para editarlos. Solo mencione "editar" en la lista de confirmación y podrá modificar su confirmación y luego emitir una git rebase --continue
para seguir adelante. Esto hubiera asegurado que nunca llegaste a una HEAD separada.
Para mí fue tan fácil como volver a eliminar la sucursal local, ya que no tenía ningún compromiso local que quisiera empujar:
Así que lo hice:
git branch -d branchname
Y luego revisando la rama de nuevo:
git checkout branchname
Primero, aclaremos qué es HEAD y qué significa cuando se separa.
HEAD es el nombre simbólico de la confirmación actualmente verificada. Cuando HEAD no está desconectado (la situación "normal" 1 : tiene una rama comprobada), HEAD en realidad apunta a la "referencia" de una rama y la rama apunta a la confirmación. HEAD es así "unido" a una rama. Cuando realiza una nueva confirmación, la rama a la que apunta HEAD se actualiza para indicar la nueva confirmación. HEAD sigue automáticamente ya que solo apunta a la rama.
-
git symbolic-ref HEAD
producerefs/heads/master
La rama llamada "maestro" está desprotegida. -
git rev-parse refs/heads/master
rendimiento17a02998078923f2d62811326d130de991d1a95a
Ese compromiso es la punta actual o "cabeza" de la rama maestra. -
git rev-parse HEAD
también produce17a02998078923f2d62811326d130de991d1a95a
Esto es lo que significa ser una "referencia simbólica". Apunta a un objeto a través de alguna otra referencia.
(Las referencias simbólicas se implementaron originalmente como enlaces simbólicos, pero luego se cambiaron a archivos simples con interpretación adicional para que puedan usarse en plataformas que no tienen enlaces simbólicos).
Tenemos HEAD
→ refs/heads/master
→ 17a02998078923f2d62811326d130de991d1a95a
Cuando HEAD se separa, apunta directamente a un compromiso, en lugar de apuntar indirectamente a uno a través de una rama. Puede pensar que una HEAD separada está en una rama sin nombre.
-
git symbolic-ref HEAD
falla confatal: ref HEAD is not a symbolic ref
-
git rev-parse HEAD
rinde17a02998078923f2d62811326d130de991d1a95a
Dado que no es una referencia simbólica, debe apuntar directamente a la propia confirmación.
Tenemos HEAD
→ 17a02998078923f2d62811326d130de991d1a95a
Lo importante para recordar con un HEAD desapegado es que si la confirmación a la que apunta no tiene ninguna referencia (ningún otro árbitro puede alcanzarlo), se convertirá en "colgado" cuando realice la verificación de otra confirmación. Eventualmente, tales compromisos pendientes se eliminarán mediante el proceso de recolección de basura (de forma predeterminada, se conservan durante al menos 2 semanas y pueden conservarse durante más tiempo al ser referenciados por el reflog de HEAD).
1 Está perfectamente bien hacer un trabajo "normal" con una CABEZA separada, solo tiene que hacer un seguimiento de lo que está haciendo para evitar tener que sacar el historial del reflog.
Los pasos intermedios de una rebase interactiva se realizan con un HEAD separado (parcialmente para evitar contaminar el reflog de la rama activa). Si finaliza la operación de rebase completa, actualizará su rama original con el resultado acumulativo de la operación de rebase y volverá a unir HEAD a la rama original. Mi conjetura es que nunca completaste completamente el proceso de rebase; esto lo dejará con un HEAD separado que apunta a la confirmación que fue procesada más recientemente por la operación de rebase.
Para recuperarse de su situación, debe crear una rama que apunte a la confirmación apuntada actualmente por su HEAD independiente:
git branch temp
git checkout temp
(estos dos comandos se pueden abreviar como git checkout -b temp
)
Esto volverá a unir tu CABEZA a la nueva rama temp
.
A continuación, debe comparar el compromiso actual (y su historial) con la rama normal en la que esperaba trabajar:
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp
(Probablemente querrá experimentar con las opciones de registro: agregar -p
, dejar de lado --pretty=…
para ver el mensaje de registro completo, etc.)
Si su nueva rama temp
se ve bien, es posible que desee actualizar (por ejemplo) el master
para que apunte a ella:
git branch -f master temp
git checkout master
(estos dos comandos se pueden abreviar como git checkout -B master temp
)
A continuación, puede eliminar la rama temporal:
git branch -d temp
Finalmente, probablemente querrás empujar la historia restablecida:
git push origin master
Es posible que deba agregar - --force
al final de este comando para empujar si la rama remota no puede ser "reenviada" a la nueva confirmación (es decir, eliminó o reescribió alguna confirmación existente, o reescribió un poco del historial). ).
Si estuvieras en medio de una operación de rebase, probablemente deberías limpiarlo. Puede verificar si un rebase estaba en proceso buscando el directorio .git/rebase-merge/
. Puede limpiar manualmente la rebase en curso simplemente eliminando ese directorio (por ejemplo, si ya no recuerda el propósito y el contexto de la operación de rebase activa). Por lo general, usaría git rebase --abort
, pero eso hace un restablecimiento adicional que probablemente desee evitar (mueve HEAD de nuevo a la rama original y lo restablece a la confirmación original, lo que deshará parte del trabajo que hicimos anteriormente ).
Si desea presionar su HEAD desconectado actual (verifique el git log
antes), intente:
git push origin HEAD:master
para enviar su CABEZA separada a la rama maestra en el origen. Si su empuje es rechazado, intente git pull origin master
primero para obtener los cambios desde el origen. Si no te importan los cambios desde el origen y se rechazan, porque hiciste una reorganización intencional y quieres reemplazar el origen / maestro con tu rama actualmente desconectada, entonces puedes forzarla ( -f
). En caso de que perdiera algún acceso a confirmaciones anteriores, siempre puede ejecutar git reflog
para ver el historial de todas las sucursales.
Para volver a una rama maestra, manteniendo los cambios, pruebe los siguientes comandos:
git rebase HEAD master
git checkout master
Ver: Git: "Actualmente no en ninguna rama". ¿Hay una manera fácil de volver a una sucursal, manteniendo los cambios?
Si está completamente seguro de que HEAD está en buen estado:
git branch -f master HEAD
git checkout master
Probablemente no puedas empujar al origen, ya que tu maestro se ha apartado del origen. Si está seguro de que nadie más está usando el repositorio, puede forzar el impulso:
git push -f
Más útil si estás en una rama de características que nadie más está usando.
Si está utilizando EGit en Eclipse: suponga que su maestro es su rama de desarrollo principal
- Confirmar cambios en una rama, normalmente una nueva.
- luego tire del control remoto
- luego haga clic con el botón derecho en el nodo del proyecto, elija el equipo y luego elija mostrar historial
- luego haga clic derecho en el maestro, elija retirar
- Si Eclipse le dice que hay dos maestros, uno local y remoto, elija el remoto
Después de esto, debería poder volver a unirse al maestro de origen.
Si hizo algunas confirmaciones en la parte superior del maestro y solo quiere "fusionar hacia atrás" el master
allí (es decir, quiere que el master
apunte a HEAD
), el de una sola línea sería:
git checkout -B master HEAD
- Eso crea una nueva rama llamada
master
, incluso si ya existe (lo cual es como movermaster
y eso es lo que queremos). - La nueva rama creada está configurada para apuntar a
HEAD
, que es donde estás. - La nueva rama está desprotegida, por lo que está en
master
después.
Encontré esto especialmente útil en el caso de los sub repositorios, que también se encuentran a menudo en un estado separado.
Si solo tienes una rama maestra y quieres volver a "desarrollar" o una característica, haz esto:
git checkout origin/develop
Nota: control de origen / desarrollo .
Te encuentras en estado HEAD separado . Puede mirar a su alrededor, realizar cambios experimentales y confirmarlos, y puede descartar cualquier confirmación que realice en este estado sin afectar a las sucursales al realizar otra compra ...
entonces
git checkout -b develop
Funciona :)
Solo haz esto:
git checkout master
O, si tiene cambios que desea mantener, haga esto:
git checkout -b temp
git checkout -B master temp
Todo lo que tiene que hacer es ''git checkout [nombre de la rama]'' donde [nombre de la rama] es el nombre de la rama original de la que obtuvo un estado principal separado. El (separado de asdfasdf) desaparecerá.
Así, por ejemplo, en la rama ''dev'' verifica el commit asdfasd14314 ->
''git checkout asdfasd14314''
ahora estás en un estado de cabeza separada
''git branch'' listará algo como ->
* (detached from asdfasdf)
dev
prod
stage
pero para salir del estado de cabeza separada y volver a dev ->
''git checkout dev''
y luego ''git branch'' listará ->
* dev
prod
stage
pero eso es, por supuesto, si no tiene la intención de mantener ningún cambio desde el estado principal desapegado pero me encuentro haciendo esto mucho sin tener la intención de hacer ningún cambio, sino solo para ver un compromiso anterior
Tuve el mismo problema y lo resolví siguiendo los siguientes pasos.
Si necesitas mantener tus cambios.
- Primero debe ejecutar el comando
git checkout master
para volver a la rama maestra. - Si necesita mantener sus cambios, simplemente ejecute
git checkout -b changes
ygit checkout -B master changes
Si no necesitas tus cambios.
Para eliminar todos los archivos sin seguimiento de su sucursal, ejecute
git clean -df
.Entonces necesita borrar todos los cambios sin etapas dentro de su repositorio. Para hacer eso tienes que ejecutar
git checkout --
Finalmente, debe devolver su rama a la rama maestra utilizando el comando
git checkout master
.
Tuve este problema hoy, donde había actualizado un submódulo, pero no estaba en ninguna rama. Ya me había comprometido, por lo que el almacenamiento, el pago y la limpieza no funcionaban. Terminé recogiendo el compromiso de la cabeza separada. Así que inmediatamente después de que cometí (cuando falló el empuje), hice:
git checkout master
git cherry-pick 99fe23ab
Mi pensamiento fue: estoy despreocupado, pero quiero ser maestro. Asumir que mi estado separado no es muy diferente del maestro, si pudiera aplicar mi compromiso al maestro, estaría establecido. Esto es exactamente lo que hace cherry-pick.
Yo tuve el mismo problema. Guardo mis cambios con git stash
y reinicio duro de la rama en local a un commit anterior (pensé que causó eso) luego hice un git pull
y no me estoy separando esa cabeza ahora. No olvides git stash apply
para tener tus cambios de nuevo.
git checkout checksum # You could use this to peek previous checkpoints
git status # You will see HEAD detached at checksum
git checkout master # This moves HEAD to master branch