¿Cuál es la diferencia entre git reset --mixed, --soft y --hard?
Estoy buscando dividir una confirmación y no estoy seguro de qué opción de reinicio usar.
Estaba mirando la página En inglés sencillo, ¿qué hace "git reset"? , pero me di cuenta de que realmente no entiendo qué es el índice de git o el área de preparación y, por lo tanto, las explicaciones no ayudaron.
Además, los casos de uso de --mixed
y --soft
me parecen iguales en esa respuesta (cuando desea corregir y volver a confirmar). ¿Alguien puede desglosarlo aún más? Me doy cuenta de que --mixed
probablemente sea la opción a seguir, pero quiero saber por qué . Por último, ¿qué pasa --hard
?
¿Alguien puede darme un ejemplo de flujo de trabajo de cómo se seleccionarían las 3 opciones?
Cuando modifica un archivo en su repositorio, el cambio inicialmente no se realiza. Para confirmarlo, debe prepararlo (es decir, agregarlo al índice) usando git add
. Cuando realiza una confirmación, los cambios que se confirman son aquellos que se han agregado al índice.
git reset
cambia, como mínimo, hacia dónde HEAD
apunta la rama actual ( ). La diferencia entre --mixed
y --soft
es si su índice también se modifica o no. Entonces, si estamos en rama master
con esta serie de confirmaciones:
- A - B - C (master)
HEAD
apunta C
y el índice coincide C
.
Cuando ejecutamos git reset --soft B
, master
(y por lo tanto HEAD
) ahora apunta a B
, pero el índice todavía tiene los cambios de C
; git status
Los mostraremos en escena. Entonces, si ejecutamos git commit
en este punto, obtendremos una nueva confirmación con los mismos cambios que C
.
Bien, empezando desde aquí de nuevo:
- A - B - C (master)
Ahora hagámoslo git reset --mixed B
. (Nota: --mixed
es la opción predeterminada). Una vez más, master
señale HEAD
B, pero esta vez el índice también se modifica para que coincida B
. Si ejecutamos git commit
en este punto no pasará nada ya que el índice coincide HEAD
. Todavía tenemos los cambios en el directorio de trabajo, pero como no están en el índice, git status
los muestra como no preparados. Para cometerlos, deberías git add
hacerlo como de costumbre.
Y finalmente, --hard
es lo mismo que --mixed
(cambia tu HEAD
índice), excepto que --hard
también modifica tu directorio de trabajo. Si estamos en C
y ejecutamos git reset --hard B
, los cambios agregados en C
, así como cualquier cambio no confirmado que tenga, se eliminarán y los archivos en su copia de trabajo coincidirán con commit B
. Dado que de esta manera puede perder cambios permanentemente, siempre debe ejecutar git status
antes de realizar un restablecimiento completo para asegurarse de que su directorio de trabajo esté limpio o que esté de acuerdo con perder los cambios no confirmados.
Y finalmente, una visualización:
En los términos más simples:
--soft
: cancelar la confirmación de los cambios, los cambios se dejan preparados ( índice ).--mixed
(predeterminado) : cancelar la confirmación + cambios sin preparar, los cambios se dejan en el árbol de trabajo .--hard
: cancelar la confirmación + cancelar la etapa + eliminar cambios, no queda nada.
Tres tipos de arrepentimiento
Muchas de las respuestas existentes no parecen responder a la pregunta real. Se trata de lo que hacen los comandos, no de lo que usted (el usuario) desea: el caso de uso . ¡Pero eso es lo que preguntó el OP!
Podría ser más útil formular la descripción en términos de qué es precisamente de lo que te arrepientes en el momento de dar una git reset
orden. Digamos que tenemos esto:
A - B - C - D <- HEAD
Aquí hay algunos posibles arrepentimientos y qué hacer al respecto:
1. Lamento que B, C y D no sean un solo compromiso.
git reset --soft A
. Ahora puedo confirmar inmediatamente y listo, todos los cambios desde A son una confirmación.
2. Lamento que B, C y D no sean dos confirmaciones (o diez confirmaciones, o lo que sea).
git reset --mixed A
. Las confirmaciones desaparecieron y el índice volvió a A, pero el área de trabajo todavía se ve como tenía después de D. Así que ahora puedo agregar y confirmar en una agrupación completamente diferente.
3. Lamento que B, C y D hayan ocurrido en esta rama ; Ojalá me hubiera bifurcado después de A y hubieran sucedido en esa otra rama.
Haga una nueva rama otherbranch
y luego git reset --hard A
. La rama actual ahora termina en A, otherbranch
saliendo de ella y conteniendo B, C y D.
(Por supuesto, también podrías usar un restablecimiento completo porque desearías que B, C y D nunca hubieran sucedido).
Tenga en cuenta que esta es una explicación simplificada que pretende ser un primer paso para intentar comprender esta compleja funcionalidad.
Puede resultar útil para los estudiantes visuales que quieran visualizar cómo se ve el estado de su proyecto después de cada uno de estos comandos:
Dado:- A - B - C (master)
Para aquellos que usan Terminal con el color activado (git config --global color.ui auto):
git reset --soft A
y verás las cosas de B y C en verde (preparadas y listas para enviarse)
git reset --mixed A
(o git reset A
) y verá el material de B y C en rojo (sin preparar y listo para ser preparado (verde) y luego comprometido)
git reset --hard A
y ya no verás los cambios de B y C por ningún lado (será como si nunca hubieran existido)
O para aquellos que usan un programa GUI como 'Tower' o 'SourceTree'
git reset --soft A
y verás el material de B y C en el área de 'archivos preparados' listos para confirmar
git reset --mixed A
(o git reset A
) y verá el material de B y C en el área de 'archivos no preparados' listos para ser movidos a preparados y luego confirmados.
git reset --hard A
y ya no verás los cambios de B y C por ningún lado (será como si nunca hubieran existido)
Todas las demás respuestas son geniales, pero creo que es mejor comprenderlas dividiendo los archivos en tres categorías: unstaged
, staged
, commit
:
--hard
debe ser fácil de entender, restaura todo--mixed
(por defecto) :unstaged
archivos: no cambiarstaged
archivos: mover aunstaged
commit
archivos: mover aunstaged
--soft
:unstaged
archivos: no cambiarstaged
archivos: no cambiarcommit
archivos: mover astaged
En resumen:
--soft
La opción moverá todo (exceptounstaged
los archivos) astaging area
--mixed
La opción moverá todo aunstaged area