Close

Reescritura del historial

git commit --amend y otros métodos para reescribir el historial


Introducción


En este tutorial se explicarán varios métodos para reescribir y alterar el historial de Git. Git usa distintos métodos para registrar los cambios. Se comentarán las ventajas e inconvenientes de cada uno y se darán ejemplos sobre cómo trabajar con ellos. El tutorial abarca algunas de las razones más habituales para sobrescribir instantáneas confirmadas y muestra cómo evitar los peligros de hacer tal cosa.

El trabajo principal de Git es garantizar que nunca pierdas un cambio confirmado. Pero también está diseñado para otorgarte un control total sobre tu workflow de desarrollo. Por tanto, te permite definir exactamente el aspecto de tu proyecto; sin embargo, también crea el potencial de perder commits. Git proporciona sus comandos de reescritura del historial sin hacerse responsable del contenido que se pueda perder al usarlos.

Git cuenta con varios mecanismos para almacenar el historial y guardar los cambios: commit --amend, git rebase y git reflog. Estos comandos te proporcionan potentes opciones de personalización del workflow. Al terminar este tutorial, te habrás familiarizado con los comandos que te permiten reestructurar los commits de Git y sabrás cómo evitar los peligros habituales de reescribir el historial.

Logotipo de Git
Material relacionado

Chuleta de Git

Logotipo de Bitbucket
VER LA SOLUCIÓN

Aprende a usar Git con Bitbucket Cloud

Modificación del último commit: git commit --amend


El comando git commit --amend es una manera práctica de modificar el commit más reciente. Te permite combinar los cambios preparados con el commit anterior en lugar de crear un commit nuevo. También puede usarse para editar el anterior mensaje del commit sin cambiar la instantánea. Sin embargo, el comando no se limita a alterar el commit más reciente, sino que lo reemplaza por completo, por lo que el commit corregido será una entidad nueva con su propia referencia. Para Git, se verá como un commit nuevo, el cual se distingue con un asterisco (*) en el siguiente diagrama. Hay unos cuantos casos habituales en los que se usa el comando git commit --amend; los cubriremos en los apartados siguientes.

git commit amend

Modificación del mensaje del commit de Git más reciente

git commit --amend

Digamos que acabas de realizar un commmit y te das cuenta de que hay un error en el mensaje de registro. Ejecutar este comando cuando no hay nada preparado te permite editar el mensaje del commit sin alterar su instantánea.

Los commits prematuros ocurren cada dos por tres durante el curso del desarrollo. Es fácil olvidarse de preparar un archivo o dar el formato incorrecto al mensaje del commit. La marca --amend es una manera cómoda de arreglar estos pequeños fallos.

git commit --amend -m "an updated commit message"

Añadir la opción -m te permite escribir un nuevo mensaje desde la línea de comandos sin tener que abrir un editor.

Modificación de archivos confirmados

El ejemplo siguiente muestra una situación habitual en el desarrollo basado en Git. Supongamos que hemos editado algunos archivos que queremos confirmar en una sola instantánea, pero que nos olvidamos de añadir uno. Arreglar este error tan solo es cuestión de preparar el otro archivo y confirmar con la marca --amend:

# Edit hello.py and main.py
git add hello.py
git commit 
# Realize you forgot to add the changes from main.py 
git add main.py 
git commit --amend --no-edit

La marca --no-edit te permite hacer las correcciones en el commit sin cambiar el mensaje. El commit resultante reemplazará al incompleto y parecerá que hemos confirmado los cambios a hello.py y main.py en una sola instantánea.

No modifiques commits públicos

Los commits corregidos son, de hecho, commits totalmente nuevos y el commit anterior ya no estará disponible en tu rama actual. Esto tiene las mismas consecuencias que restablecer una instantánea pública. Procura no corregir un commit en el que otros desarrolladores hayan basado su trabajo, ya que crea una situación confusa para ellos de la cual es complicado recuperarse.

Resumen

Repasemos: git commit --amend te permite añadir los nuevos cambios preparados al commit más reciente. Puedes añadir o eliminar cambios del área de preparación de Git con un commit --amend. Si no hay ningún cambio preparado, --amend seguirá pidiéndote que modifiques el mensaje de registro del último commit. Ten cuidado al usar --amend en commits compartidos con otros miembros del equipo. Puede que modificar un commit compartido con otro usuario conlleve confusas y largas soluciones del conflicto de fusión.

Modificar commits más antiguos o varios commits al mismo tiempo


Si quieres modificar commits más antiguos o varios commits a la vez, puedes usar git rebase para combinar una secuencia de commits en un nuevo commit base. En el modo estándar, git rebase te permite literalmente reescribir el historial, aplicando de forma automática los commits de tu rama de trabajo actual a la rama head anterior. Dado que los nuevos commits reemplazarán a los antiguos, es importante que no uses git rebase en commits que se han hecho públicos, o parecerá que el historial de tu proyecto ha desaparecido.

En estos casos u otros similares en los que sea importante mantener limpio el historial del proyecto, añadir la opción -i al comando git rebase te permitirá ejecutar rebase interactive (reorganización interactiva). Esta opción te da la oportunidad de alterar commits individuales durante el proceso, en lugar de mover todos los commits. Puedes aprender más sobre la reorganización interactiva y conocer comandos de reorganización adicionales en la página sobre git rebase.

Modificación de archivos confirmados

Durante esta operación, el comando de edición o e detendrá la reorganización en ese commit y te permitirá hacer cambios adicionales con git commit --amend. Git interrumpirá la reproducción y mostrará el siguiente mensaje:

Stopped at 5d025d1... formatting
You can amend the commit now, with



 git commit --amend



Once you are satisfied with your changes, run



 git rebase --continue

Varios mensajes

Cada commit de Git contará con un mensaje de registro que explique lo ocurrido en el commit. Estos mensajes proporcionan información valiosa sobre el historial del proyecto. Durante la reorganización, puedes ejecutar distintos comandos en los commits para modificar esos mensajes.

Combinación de commits para un historial limpio

El comando s nos permite ver la verdadera utilidad de la reorganización. Este comando de combinación te permite especificar qué commits quieres fusionar con los commits anteriores. Así, el historial se mantendrá limpio. Durante la reorganización, Git ejecutará los comandos especificados para cada commit. En el caso de los commits squash, Git abrirá el editor de texto configurado y te pedirá que combines los mensajes de commit especificados. Este proceso se puede representar de la siguiente forma:

Tutorial de Git: ejemplo de git rebase -i

Ten en cuenta que los commits modificados con el comando rebase tienen un ID distinto del de los commits originales. Los commits marcados con pick tendrán un nuevo ID si los commits anteriores se han reescrito.

Las soluciones de almacenamiento de Git modernas, como Bitbucket, ahora ofrecen funcionalidades de "autocombinación" al fusionar. Estas funcionalidades llevarán a cabo una reorganización y combinarán los commits de una rama por ti y de forma automática cuando utilices la interfaz de usuario de las soluciones alojadas. Para obtener más información, consulta el artículo de combinación de commits al fusionar una rama de Git con Bitbucket.

Resumen

El comando git rebase te permite modificar el historial y, con la reorganización interactiva puedes hacerlo todo sin dejar un rastro desordenado. De este modo, tienes libertad para cometer y corregir errores y pulir tu trabajo mientras que el historial del proyecto se mantiene limpio y lineal.

La red de seguridad: git reflog


Los registros de referencia ("reflogs") son un mecanismo que Git utiliza para registrar las actualizaciones aplicadas a los extremos de las ramas y otras referencias de commits. El comando reflog te permite ir a un commit aunque no se haga referencia a este en ninguna rama o etiqueta. Después de reescribir el historial, el registro de referencia contiene información sobre el antiguo estado de las ramas y te permite volver a ese estado, si es necesario. Cada vez que la punta de tu rama se actualiza por cualquier motivo (intercambio de ramas, adición de cambios, reescritura del historial o adición de nuevos commits), se añade una nueva entrada al registro. En esta sección echaremos un vistazo al comando git reflog y exploraremos algunos de sus usos más frecuentes.

Uso

git reflog

Este comando muestra el registro de referencia del repositorio local.

git reflog --relative-date

Así se muestra el registro de referencia con información de fecha relativa (por ejemplo, hace dos semanas).

Ejemplo

Para comprender el comando git reflog, vamos a ver un ejemplo.

0a2e358 HEAD@{0}: reset: moving to HEAD~2
0254ea7 HEAD@{1}: checkout: moving from 2.2 to main
c10f740 HEAD@{2}: checkout: moving from main to 2.2

El registro de referencias anterior muestra que se ha cambiado de la rama principal a la 2.2 y luego se ha vuelto a cambiar a la principal. Luego, se ha aplicado un restablecimiento completo (hard reset) a una confirmación anterior. La actividad más reciente, denominada HEAD@{0}, aparece en la parte superior.

Si resulta que has vuelto para atrás sin querer, el registro de referencias contendrá la rama principal de confirmación apuntando a (0254ea7), antes de que perdieras accidentalmente dos confirmaciones.

git reset --hard 0254ea7

Con el comando git reset, ahora es posible cambiar la rama principal a la confirmación anterior. Esto proporciona una especie de red de seguridad en caso de que se haya modificado el historial por error.

Es importante tener en cuenta que el registro de referencia solo proporciona esta "red de seguridad" si los cambios se han confirmado en tu repositorio local y que solo realiza el seguimiento de los movimientos del extremo de la rama del repositorio. Además, las entradas del registro tienen una fecha de vencimiento. El periodo de tiempo por defecto antes del vencimiento de una entrada es de 90 días.

Si quieres más información, consulta la página sobre git reflog.

Resumen


En este artículo se han comentado distintos métodos para modificar el historial de Git y deshacer los cambios realizados. Asimismo, hemos visto el proceso git rebase en general. Algunas de las ideas fundamentales son las siguientes:

  • Hay muchas maneras de reescribir el historial con Git.
  • Usa git commit --amend para modificar el mensaje de registro más reciente.
  • Usa git commit --amend para hacer cambios al commit más reciente.
  • Usa git rebase para combinar commits y modificar el historial de una rama.
  • El comando git rebase -i proporciona un control mucho más exhaustivo sobre las modificaciones del historial que el git rebase estándar.

Aprende más sobre estos comandos en sus páginas individuales:


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.

Gente que colabora utilizando un muro lleno de herramientas

Blog de Bitbucket

Ilustración de Devops

Ruta de aprendizaje de DevOps

Demostraciones de funciones con expertos de Atlassian del Centro de demostraciones

Cómo funciona Bitbucket Cloud con Atlassian Open DevOps

Suscríbete para recibir el boletín de DevOps

Thank you for signing up