En general, git reset
la función es tomar la rama actual y restablecerla para que apunte a otro lugar, y posiblemente traer el índice y el árbol de trabajo. Más concretamente, si su rama maestra (actualmente desprotegida) es así:
- A - B - C (HEAD, master)
y te das cuenta de que quieres que el maestro apunte a B, no a C, lo usarás git reset B
para moverlo allí:
- A - B (HEAD, master) # - C is still here, but there's no branch pointing to it anymore
Digresión: esto es diferente de un pago. Si corrieras git checkout B
, obtendrías esto:
- A - B (HEAD) - C (master)
Has terminado en un estado HEAD separado. HEAD
, árbol de trabajo, indexar todas las coincidencias B
, pero la rama maestra se quedó atrás en C
. Si realiza una nueva confirmación D
en este momento, obtendrá esto, que probablemente no sea lo que desea:
- A - B - C (master)
\
D (HEAD)
Recuerde, reset no realiza confirmaciones, solo actualiza una rama (que es un puntero a una confirmación) para apuntar a una confirmación diferente. El resto son solo detalles de lo que sucede con su índice y árbol de trabajo.
Casos de uso
Cubro muchos de los principales casos de uso git reset
dentro de mis descripciones de las diversas opciones en la siguiente sección. Realmente se puede usar para una amplia variedad de cosas; El hilo común es que todos ellos implican restablecer la rama, el índice y / o el árbol de trabajo para apuntar / coincidir con una confirmación determinada.
Cosas a tener en cuenta
--hard
puede hacer que realmente pierdas el trabajo. Modifica tu árbol de trabajo.
git reset [options] commit
puede hacer que (tipo de) pierda confirmaciones. En el ejemplo de juguete anterior, perdimos el compromiso C
. Todavía está en el repositorio, y puede encontrarlo mirando git reflog show HEAD
o git reflog show master
, pero ya no es accesible desde ninguna rama.
Git elimina permanentemente tales confirmaciones después de 30 días, pero hasta entonces puede recuperar C al señalar una rama nuevamente ( git checkout C; git branch <new branch name>
).
Argumentos
Parafraseando la página de manual, el uso más común es el formulario git reset [<commit>] [paths...]
, que restablecerá las rutas dadas a su estado desde la confirmación dada. Si no se proporcionan las rutas, se restablece todo el árbol, y si no se proporciona la confirmación, se considera HEAD (la confirmación actual). Este es un patrón común en los comandos de git (por ejemplo, checkout, diff, log, aunque la semántica exacta varía), por lo que no debería ser demasiado sorprendente.
Por ejemplo, git reset other-branch path/to/foo
restablece todo en path / to / foo a su estado en otra rama, git reset -- .
restablece el directorio actual a su estado en HEAD, y un simple git reset
restablece todo a su estado en HEAD.
El árbol de trabajo principal y las opciones de índice
Hay cuatro opciones principales para controlar lo que le sucede a su árbol de trabajo e índice durante el reinicio.
Recuerde, el índice es el "área de preparación" de git: es donde van las cosas cuando usted dice git add
en preparación para comprometerse.
--hard
hace que todo coincida con la confirmación a la que ha restablecido. Este es el más fácil de entender, probablemente. Todos sus cambios locales se ven afectados. Un uso principal es volar su trabajo pero no cambiar commits: git reset --hard
significa git reset --hard HEAD
, es decir, no cambie la rama sino que elimine todos los cambios locales. El otro es simplemente mover una rama de un lugar a otro y mantener sincronizado el árbol de índice / trabajo. Este es el que realmente puede hacerte perder el trabajo, porque modifica tu árbol de trabajo. Asegúrese de que quiere tirar el trabajo local antes de ejecutarlo reset --hard
.
--mixed
es el valor predeterminado, es decir, git reset
significa git reset --mixed
. Restablece el índice, pero no el árbol de trabajo. Esto significa que todos sus archivos están intactos, pero cualquier diferencia entre el commit original y el que restablece se mostrará como modificaciones locales (o archivos sin seguimiento) con el estado de git. Úselo cuando se dé cuenta de que realizó algunas confirmaciones incorrectas, pero desea conservar todo el trabajo que ha realizado para poder arreglarlo y volver a comprometerse. Para confirmar, tendrá que agregar archivos al índice nuevamente ( git add ...
).
--soft
no toca el índice ni el árbol de trabajo. Todos sus archivos están intactos como con --mixed
, pero todos los cambios se muestran como changes to be committed
con el estado de git (es decir, registrado en preparación para la confirmación). Use esto cuando se dé cuenta de que ha cometido algunos errores, pero el trabajo es bueno, todo lo que necesita hacer es volver a comprometerse de manera diferente. El índice no se ha modificado, por lo que puede confirmar de inmediato si lo desea: la confirmación resultante tendrá el mismo contenido que antes de restablecer.
--merge
se agregó recientemente y está destinado a ayudarlo a cancelar una fusión fallida. Esto es necesario porque en git merge
realidad le permitirá intentar una fusión con un árbol de trabajo sucio (uno con modificaciones locales) siempre que esas modificaciones estén en archivos que no se vean afectados por la fusión. git reset --merge
restablece el índice (como --mixed
: todos los cambios se muestran como modificaciones locales) y restablece los archivos afectados por la fusión, pero deja a los demás solos. Con suerte, esto restaurará todo a como estaba antes de la mala fusión. Por lo general, lo usará como git reset --merge
(significado git reset --merge HEAD
) porque solo desea restablecer la fusión, no mover la rama. ( HEAD
no se ha actualizado todavía, ya que la fusión falló)
Para ser más concreto, suponga que ha modificado los archivos A y B, e intenta fusionarse en una rama que modificó los archivos C y D. La fusión falla por alguna razón, y decide cancelarla. Utiliza git reset --merge
. Devuelve a C y D a su estado original HEAD
, pero deja solo sus modificaciones en A y B, ya que no formaron parte del intento de fusión.
¿Quiere saber más?
Creo que man git reset
es realmente bastante bueno para esto, quizás necesites un poco de la forma en que funciona git para que realmente se hundan. En particular, si se toma el tiempo de leerlos cuidadosamente, esas tablas que detallan los estados de los archivos en el índice y el árbol de trabajo para todas las opciones y casos son muy útiles. (Pero sí, son muy densos: transmiten una gran cantidad de la información anterior en una forma muy concisa).
Notación extraña
La "notación extraña" ( HEAD^
y HEAD~1
) que usted menciona es simplemente una abreviatura para especificar confirmaciones, sin tener que usar un nombre hash como 3ebe3f6
. Está completamente documentado en la sección "especificando revisiones" de la página de manual para git-rev-parse, con muchos ejemplos y sintaxis relacionada. El caret y la tilde en realidad significan cosas diferentes :
HEAD~
es la abreviatura de HEAD~1
y significa el primer padre del commit. HEAD~2
significa el primer padre del primer padre del commit. Piense HEAD~n
en "n commits before HEAD" o "el ancestro de la enésima generación de HEAD".
HEAD^
(o HEAD^1
) también significa el primer padre del commit. HEAD^2
significa el segundo padre del commit . Recuerde, un commit de fusión normal tiene dos padres: el primer padre es el commit de fusión y el segundo padre es el commit que se fusionó. En general, las fusiones pueden tener arbitrariamente muchos padres (fusiones de pulpos).
- Los
^
y ~
los operadores pueden ser ensartados, como en HEAD~3^2
, la segunda matriz de la ancestro tercera generación de HEAD
, HEAD^^2
, la segunda matriz de la primera matriz de HEAD
, o incluso HEAD^^^
, lo que es equivalente a HEAD~3
.