Operaciones Avanzadas de Git Commit

GitBeginner
Practicar Ahora

Introducción

¡Bienvenido de nuevo, aventurero de Git! Ya has dado tus primeros pasos en el mundo del control de versiones y ahora es el momento de subir de nivel. En este laboratorio, exploraremos algunas de las operaciones de commit más avanzadas de Git. Estas técnicas te darán un control aún mayor sobre el historial de tu proyecto, permitiéndote corregir errores, reorganizar tu trabajo y colaborar de manera más efectiva.

Piensa en este laboratorio como una actualización para tu máquina del tiempo. No solo podrás viajar a través del tiempo, ¡sino que ahora aprenderás a alterar la línea temporal misma! No te preocupes si esto suena intimidante; te guiaremos en cada paso, explicando no solo cómo realizar estas operaciones, sino también por qué son útiles en escenarios del mundo real.

Al final de este laboratorio, serás capaz de enmendar commits, revertir cambios, realizar cherry-pick de commits específicos, ejecutar rebases interactivos y combinar (squash) commits. Estas son herramientas poderosas que los desarrolladores profesionales utilizan a diario para mantener historiales de proyectos limpios y organizados. ¡Sumerjámonos y llevemos tus habilidades de Git al siguiente nivel!

Este es un Laboratorio Guiado, que proporciona instrucciones paso a paso para ayudarte a aprender y practicar. Sigue las instrucciones cuidadosamente para completar cada paso y ganar experiencia práctica. Los datos históricos muestran que este es un laboratorio de nivel principiante con una tasa de finalización del 85%. Ha recibido una tasa de valoraciones positivas del 96% por parte de los alumnos.

Configuración de tu Espacio de Trabajo

Antes de comenzar con nuestras operaciones avanzadas, configuremos un nuevo espacio de trabajo. Crearemos un nuevo directorio e inicializaremos un repositorio de Git en él. Esto nos dará un espacio limpio para experimentar sin afectar ninguno de tus proyectos existentes.

Abre tu terminal y escribe estos comandos, presionando Enter después de cada línea:

cd ~/project
mkdir git-advanced-lab
cd git-advanced-lab
git init

Analicemos lo que hacen estos comandos paso a paso:

  1. cd ~/project: cd significa "change directory" (cambiar directorio). ~/project es una ruta que usualmente apunta a una carpeta de "proyectos" dentro de tu directorio personal (~). Este comando navega tu terminal hacia ese directorio. Si el directorio "project" no existe, podrías encontrar un error. Si es así, créalo primero usando mkdir ~/project y luego intenta cd ~/project de nuevo.
  2. mkdir git-advanced-lab: mkdir significa "make directory" (crear directorio). Este comando crea una nueva carpeta llamada "git-advanced-lab" dentro de tu directorio actual. Este nuevo directorio será la raíz de nuestro repositorio Git para este laboratorio.
  3. cd git-advanced-lab: Este comando cambia tu directorio actual nuevamente, esta vez moviéndote dentro del directorio "git-advanced-lab" recién creado. Ahora, cualquier comando que ejecutes se realizará dentro de este directorio.
  4. git init: Este es el comando crucial de Git para inicializar un repositorio. git init configura todas las estructuras necesarias de Git dentro del directorio actual, convirtiéndolo en un repositorio de Git. Verás que se crea una carpeta oculta llamada .git. Esta carpeta es el corazón de tu repositorio y almacena todo el historial de versiones y la configuración.

Ahora que tenemos un repositorio inicializado, creemos un archivo simple para trabajar y realicemos nuestro commit inicial:

echo "Hello, Advanced Git" > hello.txt
git add hello.txt
git commit -m "Initial commit"

Esto es lo que sucede con estos comandos:

  1. echo "Hello, Advanced Git" > hello.txt: echo es un comando que muestra texto. > es un operador de redirección. Toma la salida del comando echo y la redirige a un archivo llamado "hello.txt". Si el archivo no existe, se crea; si existe, se sobrescribe.
  2. git add hello.txt: Antes de que Git pueda rastrear los cambios en un archivo, debes indicárselo explícitamente. Este comando prepara (stages) el archivo "hello.txt". El área de preparación o staging area es como una zona de preparación para tu commit.
  3. git commit -m "Initial commit": git commit toma todos los cambios que están actualmente en el área de preparación y los guarda como un nuevo commit en el historial. El parámetro -m añade un mensaje descriptivo, lo cual es una buena práctica para entender qué se cambió.

¡Genial! Ahora tenemos un repositorio con un commit. Verifiquemos el estado para confirmar que todo esté configurado correctamente:

git status

Tras ejecutar git status, deberías ver un mensaje similar a este:

On branch master
nothing to commit, working tree clean

Este mensaje indica que tu árbol de trabajo está limpio, lo que significa que no hay cambios pendientes de confirmar. ¡Estamos listos para empezar!

Enmendar tu Último Commit

Imagina que acabas de hacer un commit, pero luego te das cuenta de que olvidaste incluir un cambio en un archivo o cometiste una pequeña errata en el mensaje del commit. En lugar de crear un commit completamente nuevo para un arreglo tan menor, Git te permite corregir el commit más reciente usando la opción --amend. Es como retroceder ligeramente en el tiempo para ajustar tu última acción.

Probémoslo. Primero, modifiquemos nuestro archivo hello.txt añadiendo otra línea:

echo "This is an important file." >> hello.txt

Este comando añade una nueva línea al final del archivo. El operador >> es clave aquí:

  • > sobrescribiría todo el archivo.
  • >> añade el contenido al final, preservando lo que ya existía.

Ahora, supongamos que queremos que esta nota de "archivo importante" forme parte de nuestro commit inicial. Podemos enmendar el commit anterior para incluir este cambio y actualizar el mensaje.

git add hello.txt
git commit --amend -m "Initial commit with important note"

Desglose de los comandos:

  1. git add hello.txt: Como modificamos el archivo, necesitamos prepararlo de nuevo para que Git sepa qué incluir.
  2. git commit --amend -m "Initial commit with important note": Aquí ocurre la magia.
    • --amend: Indica a Git que, en lugar de crear un nuevo commit, queremos modificar el último.
    • -m "...": Proporciona un nuevo mensaje. Si omites esto, Git abrirá tu editor de texto predeterminado para editar el mensaje original.

¿Qué acaba de suceder?

En lugar de tener dos commits, Git ha reemplazado efectivamente el "Initial commit" anterior por una versión nueva y mejorada. El commit antiguo ha desaparecido y el nuevo incorpora tanto el archivo original como la nueva línea, junto con el mensaje actualizado.

Verifiquemos esto revisando el registro de commits:

git log --oneline

Deberías ver solo un commit en la salida, pero con el mensaje actualizado.

<commit_hash> Initial commit with important note

Presiona q para salir de la vista del log si no se cierra automáticamente.

Consideraciones importantes al enmendar:

  • Solo enmienda commits no publicados: Solo debes usar --amend en commits que aún no hayas subido (pushed) a un repositorio remoto compartido (como GitHub). Enmendar un commit que otros ya tienen reescribe la historia y puede causar mucha confusión y conflictos.
  • Limpieza del historial local: Es ideal para pulir tu trabajo mientras estás en una rama local antes de compartirla.

Revertir un Commit

A veces, haces un commit y más tarde te das cuenta de que introdujo un error o simplemente quieres deshacer esos cambios. Podrías pensar en usar git reset para borrarlo, pero git reset puede ser destructivo, especialmente si ya compartiste tus cambios. Una forma más segura y colaborativa de deshacer cambios es usar git revert.

git revert crea un nuevo commit que aplica los cambios inversos de un commit específico. No borra el commit original del historial; en su lugar, añade una nueva entrada que neutraliza sus efectos. Esto preserva la integridad del historial y es mucho más seguro para repositorios compartidos.

Creemos un commit que luego revertiremos:

echo "This line will be reverted" >> hello.txt
git add hello.txt
git commit -m "Add line to be reverted"

Ahora, supongamos que decidimos que esa línea fue un error. Podemos revertir el último commit usando:

git revert HEAD

Analicemos el comando:

  • git revert: El comando para deshacer cambios mediante un nuevo commit.
  • HEAD: Es un puntero al commit actual en tu rama. Generalmente, es el más reciente. git revert HEAD significa "deshaz el commit más reciente".

Cuando ejecutas esto, Git hará lo siguiente:

  1. Analizar los cambios: Mira qué hizo el commit HEAD.
  2. Crear cambios inversos: Calcula cómo deshacerlo (en este caso, eliminando la línea añadida).
  3. Crear un nuevo commit: Genera automáticamente un commit con esos cambios inversos.
  4. Abrir el editor de texto: Git abrirá tu editor para que confirmes el mensaje del commit de reversión (por defecto suele ser algo como "Revert 'Add line to be reverted'").

Manejo del editor de texto:

Si se abre un editor como Vim y no estás familiarizado:

  • En Vim: Presiona Esc, escribe :wq y pulsa Enter.
  • En Nano: Presiona Ctrl + X, luego Y y Enter.

Revisemos el historial ahora:

git log --oneline

Deberías ver tres commits (del más nuevo al más antiguo):

  1. El commit de reversión ("Revert...").
  2. El commit que queríamos deshacer ("Add line to be reverted").
  3. El commit inicial.

¿Por qué preferir git revert sobre git reset?

  • Historial no destructivo: No reescribe el pasado, añade información nueva. Es seguro para colaborar.
  • Evita el "Force Push": No necesitas forzar la subida al servidor, ya que solo estás añadiendo un commit normal.
  • Rastro de auditoría claro: Permite ver exactamente cuándo se cometió un error y cuándo se corrigió.

Cherry-picking de Commits

Hacer cherry-pick en Git es como elegir una cereza de un árbol: seleccionas un commit específico de una rama y lo aplicas a tu rama actual. Esto es útil cuando quieres incorporar una funcionalidad o corrección específica de otra rama sin traer todos los cambios de esa rama.

Simulemos un escenario donde desarrollamos una función en una rama separada y queremos traer solo ese commit a nuestra rama principal.

Primero, creamos una rama y hacemos un commit en ella:

git checkout -b feature-branch
echo "This is a new feature" >> feature.txt
git add feature.txt
git commit -m "Add new feature"

Ahora, regresemos a la rama master:

git checkout master

Queremos aplicar el commit "Add new feature" de feature-branch a master. Usamos git cherry-pick:

git cherry-pick feature-branch

En este caso, usamos el nombre de la rama porque Git tomará el último commit de dicha rama. Si quisieras un commit específico de en medio de un historial, usarías su hash (ej. git cherry-pick a1b2c3d).

Al ejecutar esto, Git:

  1. Busca el commit especificado.
  2. Aplica los cambios en tu rama actual.
  3. Crea un nuevo commit con el mismo contenido y mensaje.

Si revisas el log en master (git log --oneline), verás el nuevo commit. Ten en cuenta que tendrá un hash diferente al original, ya que es un commit nuevo en esta rama.

Consideraciones sobre Cherry-picking:

  • Nuevo Commit: Siempre crea una copia; no mueve el original.
  • Posibles Conflictos: Si el código ha cambiado mucho entre ramas, Git podría pedirte que resuelvas conflictos manualmente.
  • Uso moderado: Es mejor usarlo para cambios aislados. Si necesitas traer muchos commits, un merge o un rebase suele ser más apropiado.

Rebase Interactivo

El rebase interactivo es una de las funciones más potentes de Git. Te permite reescribir tu historial de commits de forma flexible: puedes reordenar, combinar (squash), editar mensajes o incluso eliminar commits. Es como un editor de precisión para tu historial.

Advertencia: El rebase reescribe la historia. Nunca hagas rebase de commits que ya han sido subidos a un repositorio compartido, a menos que sepas exactamente lo que haces y lo hayas coordinado con tu equipo. Es ideal para limpiar tus commits locales antes de compartirlos.

Creemos una serie de commits para practicar:

echo "First change" >> hello.txt
git commit -am "First change"
echo "Second change" >> hello.txt
git commit -am "Second change"
echo "Third change" >> hello.txt
git commit -am "Third change"

(La opción -am es un atajo para añadir cambios de archivos rastreados y hacer el commit en un solo paso).

Ahora, supongamos que queremos combinar los dos primeros cambios en uno solo y mejorar el mensaje del tercero. Iniciamos el rebase interactivo:

git rebase -i HEAD~3
  • -i: Significa "interactivo".
  • HEAD~3: Indica que queremos trabajar con los últimos 3 commits.

Se abrirá tu editor con una lista similar a esta:

pick 63c95db First change
pick 68e7909 Second change
pick 5371424 Third change

Comandos comunes en el editor de rebase:

  • pick (p): Usar el commit tal cual.
  • reword (r): Usar el commit, pero cambiar su mensaje.
  • squash (s): Combinar este commit con el anterior (el de arriba).
  • drop (d): Eliminar el commit.

Nuestro plan:

  1. Combinar "Second change" en "First change".
  2. Cambiar el mensaje de "Third change".

Modifica el archivo para que se vea así:

pick abc1234 First change
squash def5678 Second change
reword ghi9101 Third change

Nota: No cambies los hashes, solo las palabras de la izquierda.

Si usas Vim:

  1. Presiona i para entrar en modo inserción.
  2. Realiza los cambios.
  3. Presiona Esc, escribe :wq y pulsa Enter.

Proceso de Rebase:

  1. Squash: Git abrirá el editor para que escribas un mensaje para el commit combinado. Puedes poner algo como: Combined first and second changes.
  2. Reword: Git abrirá el editor para que cambies el mensaje del tercer commit. Pon algo como: Improved third change.

Al terminar, verás el mensaje "Successfully rebased". Si revisas git log --oneline, verás que tu historial ahora es más limpio y profesional.

Si algo sale mal durante el proceso, siempre puedes volver al estado original con:

git rebase --abort

Rebase desde la Raíz

En el paso anterior usamos HEAD~3, pero Git permite ir más allá. git rebase -i --root te permite editar todo el historial desde el primerísimo commit que hiciste en el repositorio.

Precaución Extrema: Esto cambia los hashes de absolutamente todos los commits. En un proyecto real, esto rompería el trabajo de todos tus compañeros. Úsalo solo en proyectos locales o situaciones excepcionales.

Probémoslo en nuestro entorno seguro:

git rebase -i --root

Se abrirá el editor con todos los commits que hemos creado desde el inicio del laboratorio.

Nuestro plan para el rebase de raíz:

  1. Cambiar el mensaje del primer commit de todos.
  2. Combinar algún commit antiguo para simplificar.

Modifica las líneas según lo que desees practicar (usando reword o squash) y sigue el mismo proceso de guardar y cerrar el editor, y luego editar los mensajes cuando Git te lo pida.

Al finalizar, habrás reconstruido por completo la narrativa de tu proyecto. Esta es la herramienta definitiva para dejar un historial impecable antes de presentar un proyecto o realizar un Pull Request.

Resumen

¡Felicidades, maestro de Git! Has elevado tus habilidades de control de versiones a un nivel superior. Repasemos las potentes técnicas que has aprendido:

  1. Enmendar Commits: Ahora puedes corregir errores menores en el último commit sin ensuciar el historial.
  2. Revertir Commits: Aprendiste la forma segura y profesional de deshacer cambios en entornos colaborativos.
  3. Cherry-picking: Tienes la capacidad de elegir quirúrgicamente qué cambios traer de otras ramas.
  4. Rebase Interactivo: Dominaste el arte de reescribir la historia para mantener un historial de commits limpio, organizado y fácil de leer.
  5. Rebase de Raíz: Aprendiste a tomar el control total de la línea temporal de tu proyecto desde su origen.

Estas operaciones son fundamentales en el día a día de un desarrollador profesional. Un historial de commits bien mantenido no es solo una cuestión estética; facilita enormemente la revisión de código, la depuración de errores y la comprensión de la evolución del proyecto a largo plazo. ¡Sigue practicando estas herramientas para integrarlas en tu flujo de trabajo habitual!