Resetting, checking out & reverting
The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.
Como son muy similares, es muy fácil confundir qué comando se debe usar en una situación de desarrollo determinada. En este artículo, compararemos las configuraciones más comunes de git reset
, git checkout
y git revert
. Espero que puedas marcharte con la seguridad necesaria para navegar por tu repositorio con cualquiera de estos comandos.
It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.
Una extracción es una operación que mueve el puntero de referencia HEAD
a una confirmación especificada. Para hacer una demostración, vamos a analizar el siguiente ejemplo:
Material relacionado
Cómo mover un repositorio de Git completo
VER LA SOLUCIÓN
Aprende a usar Git con Bitbucket Cloud
En este ejemplo se muestra una secuencia de confirmaciones en la rama main
. La referencia HEAD
y la referencia de la rama main
en estos momentos apuntan a la confirmación d. Ahora vamos a ejecutar git checkout b
Esta es una actualización del árbol "Historial de confirmaciones". El comando git checkout
se puede usar en un alcance de confirmación o de nivel de archivo. Una extracción de nivel de archivo cambiará el contenido del archivo por el de la confirmación específica.
Una reversión es una operación que toma una confirmación especificada y crea una nueva confirmación que invierte dicha confirmación especificada. git revert
solo se puede ejecutar en un alcance de nivel de confirmación y no tiene funcionalidad de nivel de archivo.
El restablecimiento es una operación que toma una confirmación especificada y restablece los" tres árboles" para que coincidan con el estado del repositorio en esa confirmación especificada. El restablecimiento se puede invocar de tres maneras diferentes que corresponden a los tres árboles.
La extracción y el restablecimiento se utilizan generalmente para hacer operaciones de "deshacer" locales o privadas. Modifican el historial de un repositorio que puede provocar conflictos al ejecutar operaciones de envío a repositorios compartidos remotos. La reversión se considera una operación segura para "acciones de deshacer públicas", ya que crea un nuevo historial que se puede compartir de forma remota y no sobrescribe el historial del que pueden depender los miembros del equipo remoto.
Git reset vs revert vs checkout reference
En la siguiente tabla se resumen los casos de uso más comunes para todos estos comandos. Ten esta referencia a mano, ya que sin duda necesitarás usar al menos algunos de ellos durante tu trayectoria con Git.
Comando | Ámbito de aplicación | Casos de uso comunes |
---|---|---|
| Ámbito de aplicación Nivel de confirmación | Casos de uso comunes Discard commits in a private branch or throw away uncommitted changes |
| Ámbito de aplicación Nivel de archivo | Casos de uso comunes Deshacer la preparación de un archivo |
| Ámbito de aplicación Nivel de confirmación | Casos de uso comunes Cambiar entre ramas o inspeccionar instantáneas antiguas |
| Ámbito de aplicación Nivel de archivo | Casos de uso comunes Descartar los cambios en el directorio de trabajo |
| Ámbito de aplicación Nivel de confirmación | Casos de uso comunes Deshacer confirmaciones en una rama pública |
| Ámbito de aplicación Nivel de archivo | Casos de uso comunes (N/D) |
Commit level operations
Los parámetros que pasas a git reset
y git checkout
determinan su alcance. Cuando no incluyes una ruta de archivo como parámetro, funcionan en confirmaciones completas. Eso es lo que exploraremos en esta sección. Ten en cuenta que git revert
no tiene un equivalente de nivel de archivo.
Reset a specific commit
En el nivel de confirmación, el restablecimiento es una forma de mover la punta de una rama a una confirmación diferente. Se puede usar para eliminar confirmaciones de la rama actual. Por ejemplo, el siguiente comando mueve la rama de revisión
hacia atrás mediante dos confirmaciones.
git checkout hotfix git reset HEAD~2
Las dos confirmaciones que estaban al final de la revisión
ahora son confirmaciones suspendidas o huérfanas. Esto significa que se eliminarán la próxima vez que Git realice una recolección de basura. En otras palabras, estás diciendo que quieres desecharlas. Esto se puede visualizar de la siguiente manera:
Este uso de git reset
es una forma sencilla de deshacer los cambios que no se han compartido con nadie más. Es el comando preferido si has empezado a trabajar en una función y de repente piensas: "¡Madre mía!, ¿qué estoy haciendo? Debería empezar de nuevo".
Además de mover la rama actual, también puedes hacer que git reset
modifique la instantánea preparada o el directorio de trabajo pasándole una de las siguientes marcas:
—--soft
: la instantánea preparada y el directorio de trabajo no se modifican de ninguna manera.—mixed
: la instantánea preparada se actualiza para que coincida con la confirmación especificada, pero el directorio de trabajo no se ve afectado. Esta es la opción predeterminada.—hard
: la instantánea preparada y el directorio de trabajo se actualizan para que coincidan con la confirmación especificada.
It’s easier to think of these modes as defining the scope of a git reset
operation. For further detailed information visit the git reset page.
Extraer confirmaciones anteriores
El comando git checkout
se usa para actualizar el estado del repositorio a un punto específico del historial de proyectos. Cuando se transmite con un nombre de rama, permite cambiar entre ramas.
git checkout hotfix
Internamente, todo lo que hace el comando anterior es mover HEAD
a una rama diferente y actualizar el directorio de trabajo para que coincida. Como esto tiene el potencial de sobrescribir los cambios locales, Git te obliga a confirmar o guardar cualquier cambio en el directorio de trabajo que se perderá durante la operación de extracción. A diferencia de git reset
, git checkout
no mueve ninguna rama.
También puedes extraer las confirmaciones arbitrarias pasando la referencia de confirmación en lugar de una rama. Esta operación hace exactamente lo mismo que cuando se extrae una rama: mueve la referencia HEAD
a la confirmación especificada. Por ejemplo, el siguiente comando extraerá el elemento principal de la confirmación actual:
git checkout HEAD~2
Esto resulta útil para inspeccionar rápidamente una versión anterior del proyecto. Sin embargo, dado que no hay una referencia de rama al HEAD
actual, esto te pone en un estado HEAD
separado. Esto puede ser peligroso si empiezas a añadir nuevas confirmaciones, porque no habrá forma de volver a ellas después de cambiar a otra rama. Por esta razón, siempre debes crear una nueva rama antes de agregar confirmaciones a un HEAD
separado.
Undo public commits with revert
La reversión deshace una confirmación creando una nueva confirmación. Esta es una forma segura de deshacer los cambios, ya que no hay posibilidad de que se sobrescriba el historial de confirmaciones. Por ejemplo, el siguiente comando determinará los cambios incluidos en la penúltima confirmación, creará una nueva confirmación para deshacerlos y añadirá la nueva confirmación al proyecto existente.
git checkout hotfix git revert HEAD~2
Esto se puede visualizar de la siguiente manera:
Contrasta esto con git reset
, que modifica el historial de confirmaciones existente. Por este motivo, git revert
se debe usar para deshacer los cambios en una rama pública, mientras que git reset
se debe reservar para deshacer los cambios en una rama privada.
También puedes pensar en git revert
como una herramienta para deshacer cambios confirmados, mientras que git reset HEAD
es para deshacer cambios no confirmados.
Al igual que git checkout
, git revert
tiene el potencial de sobrescribir archivos en el directorio de trabajo, por lo que te pedirá que confirmes o guardes los cambios que se perderían durante la operación de reversión.
File-level operations
Los comandos git reset
y git checkout
también aceptan una ruta de archivo opcional como parámetro. Esto modifica considerablemente su comportamiento. En lugar de operar en instantáneas completas, esto los obliga a limitar sus operaciones a un solo archivo.
Git reset a specific file
Cuando se invoca con una ruta de archivo, git reset
actualiza la instantánea preparada para que coincida con la versión de la confirmación especificada. Por ejemplo, este comando buscará la versión de foo.py
en la penúltima confirmación y la preparará para la próxima confirmación:
git reset HEAD~2 foo.py
Al igual que con la versión de git reset
de nivel de confirmación, este se usa más habitualmente con HEAD
en lugar de con una confirmación arbitraria. La ejecución de git reset HEAD foo.py
deshará la preparación de foo.py
. Los cambios que contiene seguirán presentes en el directorio de trabajo.
Las marcas --soft
, --mixed
y --hard
no tienen ningún efecto en la versión de nivel de archivo de git reset
, ya que la instantánea preparada siempre se actualiza y el directorio de trabajo no lo hace nunca.
Git checkout file
Extraer un archivo es similar a usar git reset
con una ruta de archivo, salvo que se actualiza el directorio de trabajo en lugar del entorno de ensayo. A diferencia de la versión de nivel de confirmación de este comando, este no mueve la referencia HEAD
, lo que significa que no cambiarás de rama.
Por ejemplo, el siguiente comando hace que foo.py
en el directorio de trabajo coincida con el de la penúltima confirmación:
git checkout HEAD~2 foo.py
Al igual que la invocación de nivel de confirmación de git checkout
, se puede usar para inspeccionar versiones anteriores de un proyecto, pero el alcance se limita al archivo especificado.
Si preparas y confirmas el archivo extraído, la operación tiene el efecto de "revertir" a la versión anterior de ese archivo. Ten en cuenta que esto elimina todos los cambios posteriores en el archivo, mientras que el comando git revert
deshace solo los cambios introducidos por la confirmación especificada.
Al igual que git reset
, esto se usa habitualmente con HEAD
como referencia de confirmación. Por ejemplo, git checkout HEAD foo.py
tiene el efecto de descartar los cambios no preparados en foo.py
. Este es un comportamiento similar al de git reset HEAD --hard
, pero solo actúa en el archivo especificado.
Resumen
You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.
Compartir este artículo
Tema siguiente
Lecturas recomendadas
Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.