¿Cómo puedo mover HEAD a una ubicación anterior? (Cabeza separada) y deshacer confirmaciones

179

En Git, estaba tratando de hacer una squash commitfusión en otra rama y luego restablecer HEADel lugar anterior a través de:

git reset origin/master

Pero necesito salir de esto. ¿Cómo puedo mover HEAD a la ubicación anterior?

Tengo el fragmento SHA-1 ( 23b6772) del commit al que necesito moverlo. ¿Cómo puedo volver a este commit?

timpone
fuente
12
HEAD es solo un puntero a su ubicación actual (o revisión para ser precisos). git checkout 23b6772debería hacer.
Yaroslav Admin
Posible duplicado de Revert Git repo a un commit anterior
Andrew C
1
@YaroslavAdmin No se debería no . La comprobación directa de una confirmación es la razón por la que se produjo el estado HEAD desconectado (ya que las ramas de seguimiento remoto no se pueden verificar por sí mismas y difieren automáticamente de la confirmación a la que apuntan cuando intenta hacerlo como lo hizo OP) También, lo siento por el nigromante comentario :-) Espero que el problema inicial ya esté resuelto ...
RomainValeri

Respuestas:

398

Antes de responder, agreguemos algunos antecedentes, explicando de qué se HEADtrata.

First of all what is HEAD?

HEADes simplemente una referencia a la confirmación actual (más reciente) en la rama actual.
Solo puede haber una sola HEADen un momento dado (excluyendo git worktree).

El contenido de HEADse almacena dentro .git/HEADy contiene los 40 bytes SHA-1 de la confirmación actual.


detached HEAD

Si no está en la última confirmación, lo que significa que HEADapunta a una confirmación previa en el historial se llama detached HEAD.

Ingrese la descripción de la imagen aquí

En la línea de comando, se verá así: SHA-1 en lugar del nombre de la rama ya HEADque no apunta a la punta de la rama actual:

Ingrese la descripción de la imagen aquí

Ingrese la descripción de la imagen aquí


Algunas opciones sobre cómo recuperarse de un HEAD separado:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Esto verificará la nueva rama que apunta a la confirmación deseada.
Este comando pagará a un commit dado.
En este punto, puede crear una rama y comenzar a trabajar a partir de este punto.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Siempre puedes usar el reflogtambién.
git reflog mostrará cualquier cambio que haya actualizado HEADy revisando la entrada de reflog deseada establecerá el HEADrespaldo de este commit.

Cada vez que se modifique el HEAD habrá una nueva entrada en el reflog

git reflog
git checkout HEAD@{...}

Esto lo llevará de regreso a su compromiso deseado

Ingrese la descripción de la imagen aquí


git reset --hard <commit_id>

"Mueva" su CABEZA de nuevo a la confirmación deseada.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Nota: ( desde Git 2.7 ) también puedes usar el git rebase --no-autostash.

git revert <sha-1>

"Deshacer" el compromiso o rango de compromiso dado.
El comando reset "deshacerá" cualquier cambio realizado en el commit dado.
Se confirmará una nueva confirmación con el parche de deshacer, mientras que la confirmación original también permanecerá en el historial.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Este esquema ilustra qué comando hace qué.
Como puede ver allí, reset && checkoutmodifique el HEAD.

Ingrese la descripción de la imagen aquí

CodeWizard
fuente
Si no está en la última confirmación, lo que significa que HEAD está apuntando a una confirmación previa en el historial, se llama HEAD separada, a menos que esa confirmación previa en el historial sea la punta de una rama diferente. En mi experiencia, podría decir que está desconectado si HEAD no está apuntando a una confirmación a la que también apunta cualquier rama. Esto no se aplica a las etiquetas.
Tim
Puede estar en HEAD independiente y al mismo tiempo tener una rama con el mismo commit que la HEAD de esta rama. No entiendo tu comentario
CodeWizard
3
Tengo problemas con el uso de marcado de código en línea para encabezados :)
jub0bs
No podría encontrar una mejor manera de enfatizarlo. siéntase libre de editar. eres más que bienvenido
CodeWizard
22

Hacer

git reset 23b6772

Para ver si estás en la posición correcta:

git status

Verás algo

En la rama maestra Su rama está detrás de 'origen / maestro' en 17 confirmaciones, y se puede reenviar rápidamente.

Luego, vuelva a escribir el historial en su control remoto para reflejar el cambio:

git push --force-with-lease // a useful command @oktober mentions in comments
amuliar
fuente
1
Sea EXTREMADAMENTE PRECAUTIVO con git push --force. En muchas situaciones, te convertirá en la persona menos popular del equipo por un tiempo ...
Kay V
para agregar a la nota anterior, acabo de encontrar esta cita en about.gitlab.com/blog/2014/11/26/keeping-your-code-protected y tuve que agregarla: "Un solo comando git push - force puede arruinar fácilmente el día para muchas personas: los repositorios [186 Jenkins] tienen sus cabezas de rama rebobinadas para señalar los compromisos más antiguos, y en efecto los compromisos más nuevos se extraviaron después del mal empujón ". - Desarrollador muy impopular ....
Kay V
2
@KayV eche un vistazo git push --force-with-lease(artículo de Thoughtbot : thoughtbot.com/blog/git-push-force-with-lease )
octubre
1
Indicador útil, @oktober, y un buen artículo. Gracias por agregarlo aquí y hacerme un comentario al respecto.
Kay V
1
¡gracias! Esto me ayudó a deshacer una mala fusión. revertComo las fusiones no reaccionan de la misma manera que los commits, me encontré en una situación increíblemente difícil. force-with-leaseme dio la confianza para reescribir la historia git de la sucursal sin afectar el trabajo de otras personas. ¡Bravo!
anon58192932
11

La solución más rápida posible (solo 1 paso)

Utilizar git checkout -

Ya veras Switched to branch <branch_name>. Confirme que es la rama que desea.


Breve explicación: este comando moverá HEAD nuevamente a su última posición. Ver nota sobre resultados al final de esta respuesta.


Mnemónico: este enfoque es muy similar a usar cd -para volver a su directorio visitado anteriormente. La sintaxis y los casos aplicables coinciden bastante bien (por ejemplo, es útil cuando realmente desea que HEAD regrese a donde estaba).


Solución más metódica (2 pasos, pero memorable)

El enfoque rápido resuelve la pregunta del OP. Pero qué pasa si su situación es ligeramente diferente: digamos que ha reiniciado Bash y luego se encontró con HEAD desconectado. En ese caso, aquí hay 2 pasos simples y fáciles de recordar.

1. Elige la rama que necesitas

Utilizar git branch -v

Verá una lista de sucursales locales existentes. Tome el nombre de la sucursal que se adapte a sus necesidades.

2. Mueva la CABEZA a ella

Utilizar git checkout <branch_name>

Ya veras Switched to branch <branch_name>. ¡Éxito!


Resultados

Con cualquiera de los métodos, ahora puede continuar agregando y comprometiendo su trabajo como antes: se realizará un seguimiento de sus próximos cambios <branch_name>.

Tenga en cuenta que ambos git checkout -y git checkout <branch_name>darán instrucciones adicionales si ha cometido cambios mientras HEAD estaba desconectado.

Kay V
fuente
Esto no está funcionando porque si lo hago (se supone que es el jefe 8acc968 ~ 2) git checkout 8acc968a continuación, git branch -vtiene MyBranchen la lista de abajo ... pero luego git checkout MyBranchborra mis comentarios.
amuliar el
Hola @amuliar: git checkout 8acc968verificará una confirmación, no una rama. Si MyBranchtiene los commits que desea, intente git checkout MyBranch. Si no contiene los cambios en commit 8acc968, deberá fusionar esos cambios después de verificar la rama.
Kay V
¡Gracias por la respuesta! Lo hice git checkoutpara ver una confirmación anterior y quería volver a la última confirmación. Pero sin el último hash de commit, estaba bastante perdido. ¡Esta solución es perfecta para mi situación!
zyy
4

La pregunta se puede leer como:

Estaba en estado separado con HEADat 23b6772y tecleado git reset origin/master(porque quería aplastar). Ahora que he cambiado de opinión, ¿cómo vuelvo a HEADestar en 23b6772?

La respuesta directa es: git reset 23b6772

Pero respondí a esta pregunta porque me cansé de escribir (copiar y pegar) hashes de confirmación o su abreviatura cada vez que quería hacer referencia a la anterior HEADy buscaba en Google para ver si había algún tipo de taquigrafía.

Resulta que hay!

git reset -(o en mi caso git cherry-pick -)

Que, por cierto, fue lo mismo cd -que volver al directorio actual anterior en * nix! Así que hurra, aprendí dos cosas de un tiro.

antak
fuente
0

Cuando ejecuta el comando git checkout commit_id, HEAD se desconecta 13ca5593d(say commit-id)y la rama estará disponible por más tiempo.

Vuelva a la ubicación anterior, ejecute el paso de comando sabio:

  1. git pull origin branch_name (decir maestro)
  2. git checkout branch_name
  3. git pull origin branch_name

Volverá a la ubicación anterior con una confirmación actualizada desde el repositorio remoto.

Deepak Kumar
fuente
0

Hoy, erróneamente verifiqué un commit y comencé a trabajar en él, haciendo algunos commits en un estado de HEAD separado. Luego empujé a la rama remota usando el siguiente comando:

git push origin HEAD: <My-remote-branch>

Luego

git checkout <My-remote-branch>

Luego

git pull

Finalmente obtuve todos mis cambios en mi rama que hice en separar HEAD.

Zaid Mirza
fuente
0

Puede que no sea una solución técnica, pero funciona. (si alguien de tu compañero de equipo tiene la misma sucursal en local)

Asumamos el nombre de su sucursal como branch-xxx .

Pasos para resolver:

  • No actualice ni tire - nada
  • Simplemente cree una nueva rama ( branch-aaa ) desde branch-xxx en su máquina
  • Eso es todo, todos sus cambios existentes estarán en esta nueva rama ( branch-aaa ). Puede continuar su trabajo con esta rama.

Nota: Nuevamente, esta no es una solución técnica, pero seguramente ayudará.

Sathish Kumar
fuente