¿Cuál es la diferencia entre git reset --mixed, --soft y --hard?

741

Estoy buscando dividir un commit y no estoy seguro de qué opción de reinicio usar.

Estaba mirando la página En inglés simple, ¿qué hace "git reset"? , pero me di cuenta de que realmente no entiendo cuál es el índice git o el área de preparación y, por lo tanto, las explicaciones no ayudaron.

Además, los casos de uso --mixedy me --softparecen iguales en esa respuesta (cuando desea corregir y volver a comprometerse). ¿Alguien puede descomponerlo aún más? Me doy cuenta de --mixedque probablemente sea la opción, pero quiero saber por qué . Por último, ¿qué pasa --hard?

¿Alguien puede darme un ejemplo de flujo de trabajo de cómo sucedería la selección de las 3 opciones?

Michael Chinen
fuente
1
Iré a editar mi respuesta en esa otra pregunta para intentar aclararlo un poco.
Cascabel
La respuesta de @mkarasek es bastante buena, pero uno puede estar interesado en echar un vistazo a esta pregunta también.
brandizzi 05 de
3
Nota mental: En general , soft: stage everything, mixed: unstage everything, hard: ignore everythinghasta el commit estoy restablecimiento de.
usuario1164937
otro buen artículo David Zychcon una explicación clara: davidzych.com/difference-between-git-reset-soft-mixed-and-hard
src3369

Respuestas:

1489

Cuando modifica un archivo en su repositorio, el cambio es inicialmente sin etapas. Para confirmarlo, debe organizarlo, es decir, agregarlo al índice, utilizando git add. Cuando realiza una confirmación, los cambios que se confirman son los que se han agregado al índice.

git resetcambia, como mínimo, hacia dónde HEADapunta la rama actual ( ). La diferencia entre --mixedy --softes si su índice también se modifica o no. Entonces, si estamos en la rama mastercon esta serie de confirmaciones:

- A - B - C (master)

HEADpuntos Cy el índice coincide C.

Cuando corremos git reset --soft B, master(y por lo tanto HEAD) ahora apunta a B, pero el índice todavía tiene los cambios desde C; git statuslos mostrará como escenificados. Entonces, si corremos git commiten este punto, obtendremos una nueva confirmación con los mismos cambios que C.


De acuerdo, así que a partir de aquí otra vez:

- A - B - C (master)

Ahora hagámoslo git reset --mixed B. (Nota: --mixedes la opción predeterminada). Una vez más, mastery HEADapunte a B, pero esta vez el índice también se modifica para que coincida B. Si corremos git commiten 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, los git statusmuestra como sin clasificar. Para cometerlos, lo haría git addy luego se comprometería como de costumbre.


Y finalmente, --hardes lo mismo que --mixed(cambia tu HEADe índice), excepto que --hardtambién modifica tu directorio de trabajo. Si estamos en Cejecución git reset --hard B, los cambios agregados 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 puede perder los cambios de esta manera de forma permanente, siempre debe ejecutar git statusantes de hacer un restablecimiento completo para asegurarse de que su directorio de trabajo esté limpio o que esté de acuerdo con perder sus cambios no confirmados.


Y finalmente, una visualización: ingrese la descripción de la imagen aquí

mkarasek
fuente
45
En otras palabras, --soft está descartando el último commit, --mix está descartando el último commit y add, --hard está descartando el último commit, add y cualquier cambio que haya realizado en los códigos, lo que es lo mismo con git checkout HEAD
James Wang
11
@eventualEntropy Puede recuperar cualquier cambio confirmado con el reflog; los cambios no confirmados que se eliminan reset --harddesaparecen para siempre.
mkarasek
2
@Robert ninguno de los dos; --mixedcambia su índice pero no su directorio de trabajo, por lo que cualquier modificación local no se ve afectada.
mkarasek
3
Puede ser útil para las personas visuales que usan git en la terminal con color: 1.'git reset --soft A 'y verá las cosas de B y C en verde (en etapas) 2.'git reset --mix A' y usted vea las cosas de B y C en rojo (sin escena) 3. 'reinicio de git - duro A' y ya no verá los cambios de B y C en ningún lado (será como si nunca hubieran existido)
timhc22
2
@ user1933930 1 y 3 lo dejarán con - A - B - C′, donde C 'contiene los mismos cambios que C (con diferente marca de tiempo y posiblemente mensaje de confirmación). 2 y 4 lo dejarán con - A - D, donde D contiene los cambios combinados de B y C.
mkarasek
216

En los términos más simples:

  • --soft: cambios no confirmados , los cambios se dejan en escena ( índice ).
  • --mixed (predeterminado) : sin confirmar + cambios en el escenario , los cambios se dejan en el árbol de trabajo .
  • --hard: descomprimir + unstage + eliminar cambios, no queda nada.
Mo Ali
fuente
8
mejor respuesta porque la respuesta usa términos técnicos para proporcionar una respuesta completa que también es la más concisa
Trevor Boyd Smith
1
Cuando he comprometido un archivo (sin empujar) y tengo un archivo sin seguimiento recién creado, entonces git reset --hard no hace nada? Solo cuando organizo el archivo sin seguimiento, lo elimina de mi directorio de trabajo.
Michael
1
@Nikhil ¿Puedes explicar dónde está mal esta respuesta?
Ned Batchelder
1
@NedBatchelder Ninguno de los puntos es correcto: ya que nunca se confirma cuando se utilizan estos comandos.
Nikhil
1
@Nikhil Quizás lo que quieres decir es que la confirmación original todavía existe, lo cual es cierto. Pero la rama se ha cambiado para que la confirmación ya no sea parte de la rama. ¿Estamos de acuerdo en eso?
Ned Batchelder
69

Tenga en cuenta que esta es una explicación simplificada que pretende ser un primer paso para tratar de comprender esta funcionalidad compleja.

Puede ser útil para los alumnos visuales que desean visualizar el estado de su proyecto después de cada uno de estos comandos:


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 (puesta en escena y lista para comprometerse)

git reset --mixed A(o git reset A) y verás las cosas de B y C en rojo (sin escena y listas para ser puestas en escena (verde) y luego confirmadas)

git reset --hard A y ya no verá los cambios de B y C en 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á las cosas de B y C en el área de 'archivos en escena' listas para comprometerse

git reset --mixed A(o git reset A) y verá las cosas de B y C en el área de 'archivos sin clasificar' listas para ser movidas a puesta en escena y luego confirmadas

git reset --hard A y ya no verá los cambios de B y C en ningún lado (será como si nunca hubieran existido)

timhc22
fuente
1
Esto es engañoso, en el mejor de los casos: su respuesta se lee como si git resetsolo cambiara el aspecto de git statusla salida.
jub0bs
3
Entiendo su punto de vista, pero no estoy de acuerdo porque, como aprendiz visual, ¡ver cómo se veía mi proyecto después de usar los 3 comandos finalmente me ayudó a comprender lo que estaban haciendo!
timhc22
Lo vi más como una idea de 'git for dummies' para ayudar a las personas a relajar lo que realmente está sucediendo. ¿Puedes pensar en cómo podría mejorarse para no ser engañoso
Timhc22
8
No, no necesitamos cambiar esta respuesta. Proporciona una práctica "hoja de trucos". ¡Piénselo: suave = verde, mixto = rojo, duro = nada (significa ido)! ¡Qué fácil de recordar! Para aquellos novatos que ni siquiera entienden lo que realmente significan esos colores, saben muy poco sobre git, y de todos modos van a tomar lecciones difíciles en el camino, ¡y eso NO es culpa de @unegma! Por cierto, acabo de votar esta respuesta para contrarrestar ese voto negativo anterior. Buen trabajo, @unegma!
RayLuo
55
Esto sirvió como un gran resumen complementario para comprender mejor el funcionamiento interno mientras los leía en otra parte. ¡Gracias!
spex
24

Todas las otras respuestas son grandes, pero me parece que lo mejor es entender que al descomponer los archivos en tres categorías: unstaged, staged, commit:

  • --hard debe ser fácil de entender, restaura todo
  • --mixed (predeterminado) :
    1. unstagedarchivos: no cambies
    2. staged archivos: mover a unstaged
    3. commit archivos: mover a unstaged
  • --soft:
    1. unstagedarchivos: no cambies
    2. stagedarchivos: no cambiar
    3. commit archivos: mover a staged

En resumen:

  • --softla opción moverá todo (excepto los unstagedarchivos) astaging area
  • --mixed la opción moverá todo a unstaged area
Hansen W
fuente
22

Aquí hay una explicación básica para los usuarios de TortoiseGit:

git reset --softy --mixeddeja tus archivos intactos.

git reset --harden realidad cambie sus archivos para que coincidan con el compromiso al que restablece.

En TortoiseGit, el concepto del índice está muy oculto por la GUI. Cuando modifica un archivo, no tiene que ejecutarlo git addpara agregar el cambio al área / índice de preparación. ¡Cuando se trata simplemente de modificaciones en los archivos existentes que no cambian los nombres de los archivos git reset --softy --mixedson lo mismo! Solo notará una diferencia si agregó nuevos archivos o renombró archivos. En este caso, si ejecuta git reset --mixed, tendrá que volver a agregar sus archivos desde la lista Archivos no versionados .

James Lawruk
fuente
Esta respuesta es muy poco clara con respecto a la diferencia entre suave y mixto. e incluso es desdeñoso al decirlo. La siguiente respuesta es más clara al respecto. stackoverflow.com/questions/2530060/…
barlop
2
Como usuario de Github Desktop, que también tiene el mismo comportamiento, esta respuesta me da una idea clara de por qué sigo confundido acerca de --mixedy --soft.
Chen Li Yong
20

En estos casos, me gusta una imagen que espero pueda explicar esto:

git reset --[hard/mixed/soft] :

ingrese la descripción de la imagen aquí

Entonces, cada efecto tiene diferentes alcances

  1. Difícil => WorkingDir + Index + HEAD
  2. Mixto => Índice + CABEZA
  3. Soft => HEAD only (índice y directorio de trabajo sin cambios).
Tomer Ben David
fuente
15

Tres tipos de arrepentimiento

Muchas de las respuestas existentes no parecen responder la pregunta real. Se trata de lo que hacen los comandos, no de lo que usted (el usuario) quiere: el caso de uso . ¡Pero eso es lo que preguntó el OP!

Puede ser más útil expresar la descripción en términos de qué es exactamente lo que lamentas en el momento en que das una git resetorden. Digamos que tenemos esto:

A - B - C - D <- HEAD

Aquí hay algunos posibles remordimientos y qué hacer al respecto:

1. Lamento que B, C y D no sean un commit.

git reset --soft A. Ahora puedo comprometer y presto de inmediato, todos los cambios ya que A son un compromiso.

2. Lamento que B, C y D no sean diez commits.

git reset --mixed A. Los commits se han ido y el índice está de regreso en A, pero el área de trabajo todavía se ve como lo hizo después de D. Así que ahora puedo agregar y commit en un grupo completamente diferente.

3. Lamento que B, C y D hayan sucedido en esta rama ; Desearía haberme ramificado después de A y haber sucedido en esa otra rama.

Haga una nueva rama otherbranch, y luego git reset --hard A. La rama actual ahora termina en A, y se otherbranchderiva de ella.

(Por supuesto, también podría usar un restablecimiento completo porque desearía que B, C y D nunca hubieran sucedido).

mate
fuente
5

No tiene que obligarse a recordar las diferencias entre ellos. Piensa en cómo hiciste un compromiso.

1. Hacer algunos cambios.

2.git agregar.

3.gc -m "Hice algo"

Soft, Mixed y Hard es la manera que le permite renunciar a las operaciones que realizó de 3 a 1.

Soft "fingió" nunca ver que has hecho "gc -m".

Mezclado "fingido" para nunca ver que has hecho "git add".

Es difícil "fingir" nunca ver que ha realizado cambios en los archivos.

qinmu2127
fuente
4

Antes de entrar en estas tres opciones, uno debe entender 3 cosas.

1) Historia / CABEZA

2) Etapa / índice

3) Directorio de trabajo

reset --soft: el historial cambió, HEAD cambió, el directorio de trabajo no cambió.

reset --mixed: historial cambiado, HEAD cambiado, directorio de trabajo cambiado con datos sin clasificar.

reset --hard: el historial cambió, HEAD cambió, el directorio de trabajo cambió con la pérdida de datos.

Siempre es seguro ir con Git --soft. Uno debería usar otra opción en requisitos complejos.

Suresh Sharma
fuente
3

Hay una serie de respuestas aquí con una idea errónea sobre git reset --soft. Si bien existe una condición específica en la que git reset --softsolo cambiará HEAD(a partir de un estado de cabezal separado), por lo general (y para el uso previsto), mueve la referencia de rama que actualmente ha desprotegido. Por supuesto, no puede hacer esto si no tiene una rama desprotegida (de ahí la condición específica donde git reset --softsolo cambiará HEAD).

He encontrado que esta es la mejor manera de pensar git reset. Que no sólo está en movimiento HEAD( todo lo que hace ), también se está moviendo la ref rama , por ejemplo, master. Esto es similar a lo que sucede cuando ejecuta git commit(la rama actual se mueve junto con HEAD), excepto que en lugar de crear (y pasar a) una nueva confirmación, pasa a una confirmación anterior .

Este es el punto de resetcambiar una rama a otra que no sea una nueva confirmación, no cambiar HEAD. Puede ver esto en el ejemplo de documentación:

Deshacer un commit, convirtiéndolo en una rama temática

          $ git branch topic/wip     (1)
          $ git reset --hard HEAD~3  (2)
          $ git checkout topic/wip   (3)
  1. Has realizado algunas confirmaciones, pero te das cuenta de que era prematuro estar en la rama "maestra". Desea continuar puliéndolos en una rama de tema, por lo tanto, cree la rama "tema / wip" fuera del HEAD actual.
  2. Rebobina la rama maestra para deshacerte de esos tres commits.
  3. Cambie a la rama "tema / wip" y siga trabajando.

¿Cuál es el punto de esta serie de comandos? Desea mover una rama , aquí master, así que mientras ha mastersalido, corregit reset .

La respuesta más votada aquí es generalmente buena, pero pensé en agregar esto para corregir las varias respuestas con conceptos erróneos.

Cambia tu sucursal

git reset --soft <ref>: Restablece el puntero rama de la rama actualmente desprotegido a la confirmación en la referencia especificada, <ref>. Los archivos en su directorio de trabajo e índice no cambian. Comprometerse desde esta etapa lo llevará de regreso a donde estaba antes del git resetcomando.

Cambia tu índice también

git reset --mixed <ref>

o equivalente

git reset <ref>:

Hace lo que --softhace Y también restablece el índice para que coincida con el compromiso en la referencia especificada. Mientras git reset --soft HEADno hace nada (porque dice mover la rama desprotegida a la rama desprotegida), git reset --mixed HEADo de manera equivalente git reset HEAD, es un comando común y útil porque restablece el índice al estado de su última confirmación.

Cambia tu directorio de trabajo también

git reset --hard <ref>: hace lo que --mixedhace Y también sobrescribe su directorio de trabajo. Este comando es similar a git checkout <ref>, excepto que (y este es el punto crucial sobre reset) todas las formas de git resetmovimiento a las que HEADapunta la referencia de la rama .

Una nota sobre "tal y tal comando mueve la CABEZA":

No es útil decir que un comando mueve el HEAD. Cualquier comando que cambie su ubicación en el historial de confirmación mueve el HEAD. Eso es lo que HEAD es , un puntero a donde quiera que estés. HEADeres tú , y así se moverá cuando lo hagas.

De Novo
fuente
2
"mover la rama ref": buen punto. Tuve que actualizar stackoverflow.com/a/5203843/6309 .
VonC
1

Una respuesta corta en qué contexto se utilizan las 3 opciones:

Para mantener los cambios actuales en el código pero para reescribir el historial de confirmación:

  • soft: Puede confirmar todo a la vez y crear una nueva confirmación con una nueva descripción (si usa torotise git o cualquier otra GUI, esta es la que debe usar, ya que aún puede marcar qué archivos desea en la confirmación y hacer múltiples se compromete de esa manera con diferentes archivos. En Sourcetree todos los archivos se organizarán para confirmar).
  • mixed: Tendrá que volver a agregar los archivos individuales al índice antes de realizar las confirmaciones (en Sourcetree todos los archivos modificados no se organizarán)

Para perder realmente sus cambios en el código también:

  • hard: no solo reescribes el historial, sino que también pierdes todos los cambios hasta el momento en que restableces
Nickpick
fuente
No me pongo suave y mezclado en este caso. Si tiene que comprometerse, ¿qué fue revertido? ¿Está comprometiendo la reversión o volviendo a comprometer los cambios (por lo tanto, volver al estado original?)
John Little
Reafirmando los cambios. No habrá confirmación inversa.
Nickpick el
1

La diferencia básica entre varias opciones del comando git reset es la siguiente.

  • --soft: solo restablece el HEAD a la confirmación que seleccione. Funciona básicamente igual que git checkout pero no crea un estado de cabeza separada.
  • --mixed (opción predeterminada): restablece HEAD a la confirmación seleccionada en el historial y deshace los cambios en el índice.
  • --hard: restablece el HEAD a la confirmación que selecciona en el historial, deshace los cambios en el índice y deshace los cambios en su directorio de trabajo.
Vishwas Abhyankar
fuente
1

--soft: Le dice a Git que restablezca HEAD a otra confirmación, por lo que el índice y el directorio de trabajo no se alterarán de ninguna manera. Todos los archivos cambiados entre el HEAD original y el commit serán organizados.

--mixed: Al igual que el software, esto restablecerá HEAD a otra confirmación. También restablecerá el índice para que coincida, mientras que no se tocará el directorio de trabajo. Todos los cambios permanecerán en el directorio de trabajo y aparecerán como modificados, pero no por etapas.

--hard: Esto restablece todo: restablece HEAD a otra confirmación, restablece el índice para que coincida y restablece el directorio de trabajo para que coincida también.

La principal diferencia entre --mixedy --softes si su índice también se modifica o no. Mira más sobre esto aquí .

Nesha Zoric
fuente
0

La respuesta de mkarasek es genial, en términos simples podemos decir ...

  • git reset --soft: establezca el HEADen el compromiso previsto pero mantenga sus cambios en etapas desde los últimos compromisos
  • git reset --mixed: es lo mismo git reset --softpero la única diferencia es que no realiza los cambios desde las últimas confirmaciones
  • git reset --hard: establezca HEADen la confirmación que especifique y restablezca todos sus cambios desde las últimas confirmaciones, incluidos los cambios no confirmados.
Vivek Maru
fuente