¿Cuál es la diferencia entre "git reset" y "git checkout"?

440

Siempre he pensado git reset, y git checkoutcomo el mismo, en el sentido de que ambos traen la parte posterior proyecto a un determinado comprometerse. Sin embargo, siento que no pueden ser exactamente lo mismo, ya que eso sería redundante. ¿Cuál es la diferencia real entre los dos? Estoy un poco confundido, ya que el svn solo tiene svn coque revertir el commit.

ADICIONAL

VonC y Charles explicaron las diferencias entre git resety git checkoutrealmente bien. Mi comprensión actual es que git resetrevierte todos los cambios a una confirmación específica, mientras que git checkoutmás o menos se prepara para una rama. Encontré los siguientes dos diagramas bastante útiles para llegar a este entendimiento:

http://a.imageshack.us/img651/1559/86421927.png http://a.imageshack.us/img801/1986/resetr.png

AGREGADO 3

Desde http://think-like-a-git.net/sections/rebase-from-the-ground-up/using-git-cherry-pick-to-simulate-git-rebase.html , el pago y el reinicio pueden emular El rebase.

ingrese la descripción de la imagen aquí

git checkout bar 
git reset --hard newbar 
git branch -d newbar 

ingrese la descripción de la imagen aquí

prosseek
fuente
eche un vistazo a git-scm.com/blog/2011/07/11/reset.html
pedrorijo91
Re: "¿Está mal o demasiado simplificado?" Sí, ese primer diagrama es engañoso con respecto a la diferencia entre pagar y restablecer. (Puede estar bien con respecto a las -- filesvariantes; no estoy seguro). Ese diagrama hace que parezca que la diferencia principal es si afectan el índice o el WD. Vea mi respuesta al respecto. Los diagramas segundo y tercero son muy útiles para ver la diferencia real. Los diagramas cuarto y quinto son útiles para verificar si comprende lo que hacen estos comandos, pero realmente no lo ayudará a llegar allí.
LarsH
Encontré la sección "Compruébelo" del "Restablecimiento de herramientas de Git desmitificado" para dar el resumen más útil.
Josiah Yoder
1
prosseek: Si está de acuerdo con @LarsH en que el primer diagrama es engañoso, ¿puede eliminarlo, por favor?
Josiah Yoder
Tenga en cuenta que el pago y el reinicio solo emulan la segunda parte de la nueva versión, y think-like-a-git.netse requieren pasos adicionales (proporcionados en el artículo vinculado ) para evitar la pérdida de datos.
cowlinator

Respuestas:

198
  • git resetse trata específicamente de actualizar el índice , mover el HEAD.
  • git checkoutse trata de actualizar el árbol de trabajo (al índice o al árbol especificado). Actualizará la CABEZA solo si realiza el pago de una rama (si no, termina con una CABEZA separada ).
    (en realidad, con Git 2.23 Q3 2019, esto será git restore, no necesariamente git checkout)

En comparación, dado que svn no tiene índice, solo un árbol de trabajo svn checkoutcopiará una revisión dada en un directorio separado.
El equivalente más cercano para git checkoutwould:

  • svn update (si está en la misma rama, es decir, la misma URL SVN)
  • svn switch (si paga, por ejemplo, la misma rama, pero desde otra URL de repositorio SVN)

Todas esas tres modificaciones árbol de trabajo ( svn checkout, update, switch) tienen sólo un comando en git: git checkout.
Pero dado que git también tiene la noción de índice (esa "área de ensayo" entre el repositorio y el árbol de trabajo), usted también tiene git reset.


Thinkeye menciona en los comentarios el artículo " Restablecer desmitificado ".

Por ejemplo, si tenemos dos ramas, ' master' y ' develop' apuntando a confirmaciones diferentes, y actualmente estamos en ' develop' (entonces HEAD lo señala) y ejecutamos git reset master, ' develop' ahora apuntará a la misma confirmación que ' master' hace.

Por otro lado, si en cambio corremos git checkout master, ' develop' no se moverá, HEADsí lo hará. HEADahora señalará a ' master'.

Entonces, en ambos casos nos estamos moviendo HEADpara apuntar a comprometernos A, pero cómo lo hacemos es muy diferente. resetmoverá los HEADpuntos de rama a, la caja se mueve HEADpara señalar a otra rama.

http://git-scm.com/images/reset/reset-checkout.png

En esos puntos, sin embargo:

LarsH agrega en los comentarios :

Sin embargo, el primer párrafo de esta respuesta es engañoso: " git checkout... actualizará la CABEZA solo si desprotege una rama (si no, termina con una CABEZA separada)".
No es cierto: git checkoutactualizará el HEAD incluso si comprueba un commit que no es una rama (y sí, termina con un HEAD separado, pero aún así se actualizó).

git checkout a839e8f updates HEAD to point to commit a839e8f.

De Novo coincide en los comentarios :

@LarsH es correcto.
La segunda viñeta tiene una idea errónea sobre el HEAD en el que se actualizará el HEAD solo si realiza el pago de una rama.
HEAD va donde quiera que estés, como una sombra.
Al revisar alguna referencia que no sea de sucursal (p. Ej., Una etiqueta) o un commit directamente, se moverá HEAD. Cabeza separada no significa que haya desprendido de la cabeza, esto significa que la cabeza se separa de una rama de referencia, que se puede ver en, por ejemplo, git log --pretty=format:"%d" -1.

  • Los estados principales adjuntos comenzarán con (HEAD ->,
  • separado aún se mostrará (HEAD, pero no tendrá una flecha a una referencia de rama.
VonC
fuente
77
Yo diría que git resetse trata de modificar la "etiqueta" de la rama y, opcionalmente, actualizar el índice o el árbol de trabajo como efecto secundario. git checkoutse trata de actualizar el árbol de trabajo y cambiar la rama actualmente "seleccionada" (la HEAD).
Mikko Rantalainen
2
@MikkoRantalainen no. git resetes 100% sobre el HEAD. Funciona incluso en un modo HEAD separado ( stackoverflow.com/a/3965714/6309 ), lo que significa que no hay rama (!). git checkout también funciona en un modo HEAD separado, o puede usarse para pagar un SHA1 en un modo HEAD separado: de nuevo, no hay rama involucrada en ese caso.
VonC
3
Lectura adicional para todas las almas perdidas enviadas aquí por un motor de búsqueda, creo que vale la pena: git-scm.com/blog/2011/07/11/reset.html
Thinkeye
2
@Thinkeye buena referencia. Lo he incluido, junto con un extracto relevante, en la respuesta para mayor visibilidad.
VonC
2
La explicación de Reset Demystified es excelente. Sin embargo, el primer párrafo de esta respuesta es engañoso: "git checkout ... actualizará el HEAD solo si desprotege una rama (si no, termina con un HEAD separado)". No es cierto ... git checkout actualizará el HEAD incluso si desprotege un commit que no es una rama (y sí, termina con un HEAD separado, pero aún así se actualizó). ¿Quizás estoy malinterpretando lo que quieres decir con "actualización"? git checkout a839e8factualiza HEAD para señalar el compromiso a839e8f.
LarsH
67

En su forma más simple, resetrestablece el índice sin tocar el árbol de trabajo, mientras que checkoutcambia el árbol de trabajo sin tocar el índice.

Restablece el índice para que coincida HEAD, el árbol de trabajo queda solo:

git reset

Conceptualmente, esto verifica el índice en el árbol de trabajo. Para hacer que realmente haga cualquier cosa, tendría que usar -fpara forzarlo a sobrescribir cualquier cambio local. Esta es una característica de seguridad para asegurarse de que la forma "sin argumento" no sea destructiva:

git checkout

Una vez que comience a agregar parámetros, es cierto que existe cierta superposición.

checkoutgeneralmente se usa con una rama, etiqueta o commit. En este caso, se restablecerá HEADy el índice a la confirmación dada, así como realizar la comprobación del índice en el árbol de trabajo.

Además, si se suministra --harda resetusted puede pedir resetpara sobrescribir el árbol de trabajo, así como restablecer el índice.

Si actualmente tiene una sucursal desprotegida, existe una diferencia crucial entre resety checkoutcuando proporciona una sucursal o compromiso alternativo. resetcambiará la rama actual para que apunte a la confirmación seleccionada, mientras checkoutque dejará sola la rama actual, pero en su lugar, pagará la rama o confirmación suministrada.

Otras formas resete commitimplican rutas de suministro.

Si proporciona rutas a resetno puede suministrar --hardy resetsolo cambiará la versión de índice de las rutas proporcionadas a la versión en el compromiso proporcionado (o HEADsi no especifica un compromiso).

Si proporciona rutas a checkout, al igual resetque actualizará la versión de índice de las rutas proporcionadas para que coincida con la confirmación proporcionada (o HEAD) pero siempre revisará la versión de índice de las rutas proporcionadas en el árbol de trabajo.

CB Bailey
fuente
2
No es cierto decir que "pagar" no cambia el índice: lo cambia cuando se usa para ir de una rama a otra.
wiki1000
En su forma más simple, restablecer restablece el índice sin tocar el árbol de trabajo, mientras que el pago cambia el árbol de trabajo sin tocar el índice. : Qué confuso es eso: |
Aditya Gupta
41

Un caso de uso simple al revertir el cambio:
1. Use reset si desea deshacer la puesta en escena de un archivo modificado.
2. Use la opción de pago si desea descartar los cambios en archivos sin clasificar.

John Doe
fuente
1
Respuesta perfecta. Gracias.
user358591
11

La diferencia clave en pocas palabras es que reset mueve la referencia de rama actual , mientras checkoutque no (mueve HEAD).

Como explica el libro Pro Git en Reset Demystified ,

Lo primero que resethará es mover a lo que apunta HEAD . Esto no es lo mismo que cambiar HEAD en sí (que es lo que checkouthace); reset mueve la rama a la que apunta HEAD. Esto significa que si CABEZA se establece en la masterrama (es decir, que está actualmente en la masterrama), corriendo git reset 9e5e6a4a empezar por hacer masterpunto a 9e5e6a4. [énfasis añadido]

Vea también la respuesta de VonC para un texto muy útil y un extracto del diagrama del mismo artículo, que no duplicaré aquí.

Por supuesto, hay muchos más detalles sobre qué efectos checkouty qué efectos resetpuede tener en el índice y el árbol de trabajo, según los parámetros que se utilicen. Puede haber muchas similitudes y diferencias entre los dos comandos. Pero como lo veo, la diferencia más crucial es si mueven la punta de la rama actual.

LarsH
fuente
2
Buena retroalimentación, además de mi respuesta anterior. +1
VonC
2

Los dos comandos (reinicio y pago) son completamente diferentes.

checkout X NO ES reset --hard X

Si X es un nombre de rama, checkout Xcambiará la rama actual mientras reset --hard Xque no lo hará.

wiki1000
fuente
2
Pero si X es un archivo o carpeta, entonces son lo mismo.
Ted Bigham
1

Breves mnemónicos:

git reset HEAD           :             index = HEAD
git checkout             : file_tree = index
git reset --hard HEAD    : file_tree = index = HEAD
Филя Усков
fuente