¿Cuál es la diferencia entre “git checkout” y “git restore” para revertir cambios de archivos no confirmados?

4 minutos de lectura

Avatar de usuario de Al Sweigart
Al Sweigart

Digamos que tengo un repositorio git con un archivo modificado llamado Léame.txt, y quiero deshacer las modificaciones que hice y volver a establecer el estado de la confirmación más reciente. Parece que hay dos comandos para hacer esto:

git checkout -- readme.txt

y

git restore readme.txt

¿Hay alguna diferencia entre estos dos comandos? me he dado cuenta de que git status ofrece el consejo “(use "git restore <file>..." to discard changes in working directory)“. ¿Es esta la forma canónica de deshacer modificaciones no confirmadas? ¿Son ambas formas igualmente válidas y populares?

avatar de usuario de axiac
axiac

git restore es un comando introducido en Git 2.23 (agosto de 2019) junto con git switch. Sus propósitos son simplificar y separar los casos de uso de git checkout que hace demasiadas cosas.

git checkout se puede usar para cambiar de rama (y también para crear una nueva rama antes de cambiar a ella). Esta funcionalidad ha sido extraída en git switch.

git checkout también se puede usar para restaurar archivos al estado en el que se encontraban en una confirmación específica. Esta funcionalidad ha sido extraída en git restore.

Todavía pueden ser realizados por git checkout pero los nuevos comandos son más fáciles de usar y menos confusos.

Para resumir,

git restore readme.txt

es una nueva forma de hacer lo que solías hacer con:

git checkout -- readme.txt

Lea también la respuesta de torek. Analiza la seguridad de git checkoutoperaciones de y proporciona un ejemplo cuando git checkout produce resultados inesperados en versiones anteriores de Git.

Me gustan las dos respuestas sobre esto en el momento en que escribo la mía, tanto la respuesta de axiac como la de kapsiR, pero la forma en que lo expresaría es esta:

  • git checkout combina demasiados comandos en una interfaz. Algunos de estos comandos son “seguros”, ya que si tiene trabajo no comprometido, no destruirlo, y algunos de estos son “inseguros”, en el sentido de que si tiene trabajo no comprometido y dígales destruir mi trabajo no comprometidoellos harán eso.

  • git switch implementa el subconjunto “seguro”.

  • git restore implementa el subconjunto “inseguro”.

Hasta ahora, no hay ninguna razón en particular para preferir el antiguo comando único o el nuevo par de comandos. Pero añadimos un elemento más:

  • git checkout name puede ejecutar cualquiera el inseguro uno o el seguro uno, ¡dependiendo de algo en lo que quizás ni siquiera estés pensando!

Ahora, este último punto está corregido en las últimas versiones de Git. Supongamos que tiene un seguimiento remoto origin/dev nombre y te gustaría crear una rama dev respectivamente. Normalmente, podría simplemente ejecutar:

git checkout dev

Sin embargo, suponga que su actual (probablemente master) la caja tiene un directorio llamado dev, y en ese directorio, ha realizado un montón de trabajo y aún no lo ha confirmado. Acabas de recordar: Debería comprometer todo este trabajo que acabo de hacer en el dev rama, no la master rama.

Ahora, no existe dev rama en absoluto, pero hay son dev/ archivos. Esto es lo que hace un viejo Git:

sh-3.2$ git --version
git version 2.20.1
sh-3.2$ git branch -r
  origin/dev

(eso es, origin/dev existe; rama dev no lo hace y estoy en master aquí)

sh-3.2$ git status --short
 M dev/file
sh-3.2$ git diff
diff --git a/dev/file b/dev/file
index e69de29..c238a0b 100644
--- a/dev/file
+++ b/dev/file
@@ -0,0 +1 @@
+look at all this work I did

Agregar esa línea tomó semanas de trabajo duro! 🙂

sh-3.2$ git checkout dev

UH oh. ¿Por qué no me dijo acerca de la creación de una rama llamada dev configurado para rastrear origin/dev?

sh-3.2$ git status
On branch master
nothing to commit, working tree clean

¡Gah! ¡Mi trabajo duro se ha ido!

El problema aquí es que git checkout corrió el inseguro dominio. Podría haber esperado que usara el seguro… pero no lo hizo.

Un Git más moderno (2.24.0) me dirá que git checkout dev es ambiguo, lo cual es bueno: no solo destruye mi archivo. (No he probado Git 2.23 en sí, donde entraron por primera vez los comandos de división en dos).

De todos modos, usando el nuevo comandos, al menos sabe, justo cuando escribe el comando, si obtendrá el modo seguro o el inseguro. Si tus hábitos están establecidos y sigues usando git checkouto le preocupa la nota que dice que estos nuevos comandos aún son experimentales, aún puede usar el anterior, y ya no solo elimina el trabajo, en el caso ambiguo.

Avatar de usuario de kapsiR
KapsiR

Como se indica en los documentos:

o puede restaurar tanto el índice como el árbol de trabajo (es lo mismo que usar git-checkout1)

Es una manera conveniente de hacer lo mismo. (primera versión en Git 2.23)

Publicación de blog de GitHub sobre aspectos destacados de Git 2.23:

Git 2.23 trae un nuevo par de comandos experimentales al conjunto de comandos existentes: git switch y git restore. Estos dos están destinados a proporcionar eventualmente una mejor interfaz para el conocido git checkout. Los nuevos mandos pretenden que cada uno tenga una separación clara, repartiendo ordenadamente cuáles son las muchas responsabilidades de git checkoutcomo mostraremos a continuación.

¿Ha sido útil esta solución?