tutoriales.com

Git cherry-pick: Aplica Commits Específicos entre Ramas sin Fusionar Todo

Este tutorial te guiará a través del comando `git cherry-pick`, una herramienta poderosa para aplicar cambios específicos de un commit a otra rama, sin necesidad de fusionar todo el historial. Es ideal para trasladar hotfixes, funcionalidades concretas o para limpiar el historial de tu proyecto. Exploraremos su uso, casos de aplicación y mejores prácticas.

Intermedio15 min de lectura8 views
Reportar error

El ecosistema de Git ofrece una plétora de comandos que facilitan la gestión del control de versiones, desde los más comunes como git commit y git push hasta herramientas más especializadas que nos permiten manipular el historial con gran precisión. Entre estas últimas, se encuentra git cherry-pick, un comando que, aunque a menudo subestimado por los principiantes, es increíblemente potente y útil en situaciones muy específicas.

git cherry-pick nos permite seleccionar uno o más commits de una rama y aplicarlos en otra rama, creando nuevos commits con los mismos cambios. A diferencia de un git merge o git rebase, que mueven o integran un conjunto completo de commits, cherry-pick se enfoca en la granularidad, permitiéndonos elegir exactamente qué cambios queremos introducir.

🎯 ¿Qué es git cherry-pick y Por Qué lo Necesitas?

Imagina que estás trabajando en una rama de desarrollo para una nueva característica importante. De repente, surge un bug crítico en producción que necesita ser arreglado ya. Un desarrollador de tu equipo crea un hotfix en una rama temporal, lo prueba y lo fusiona rápidamente a la rama main (o master). Sin embargo, ese hotfix también afecta a la funcionalidad en la que estás trabajando en tu rama de desarrollo y necesitas tenerlo ahí sin esperar a la próxima fusión de main.

Aquí es donde git cherry-pick brilla. Puedes "recoger" (de ahí "cherry-pick") ese commit específico del hotfix de la rama main y aplicarlo directamente en tu rama de desarrollo, sin traer contigo todos los demás commits que no son relevantes para tu trabajo actual.

📖 Conceptos Clave

Antes de sumergirnos en los ejemplos, es crucial entender algunos conceptos:

  • Commit: Una instantánea de tu repositorio en un momento dado, junto con un mensaje que describe los cambios y un identificador único (SHA-1).
  • Rama (Branch): Una línea de desarrollo independiente. Permite a múltiples desarrolladores trabajar en diferentes características o correcciones sin interferir directamente con el código principal.
  • SHA-1 (Hash del Commit): Un identificador único de 40 caracteres que representa cada commit en Git. Es como el "nombre" o "huella digital" de un commit.
  • Historial de Git: La secuencia de commits que muestran la evolución del proyecto. cherry-pick manipula este historial creando nuevos commits.
💡 Consejo: `git cherry-pick` crea un *nuevo* commit con los mismos cambios, no mueve el commit original. Esto significa que el SHA-1 del commit original y el del commit creado por cherry-pick serán diferentes.

🛠️ Cómo Funciona git cherry-pick: Sintaxis Básica

La sintaxis básica de git cherry-pick es bastante sencilla. Necesitarás el SHA-1 (hash) del commit o commits que deseas aplicar.

git cherry-pick <hash-del-commit>

Si deseas aplicar múltiples commits, puedes listarlos uno tras otro:

git cherry-pick <hash-commit-1> <hash-commit-2> <hash-commit-3>

También puedes especificar un rango de commits. Es importante notar que, al especificar un rango, el primer commit del rango (el que está antes de ..) será excluido, mientras que el último será incluido.

git cherry-pick <hash-commit-inicio>..<hash-commit-fin>

Para incluir ambos commits en el rango, usa ^:

git cherry-pick <hash-commit-inicio>^..<hash-commit-fin>

🚀 Preparando Nuestro Entorno: Un Ejemplo Práctico

Para entender git cherry-pick a fondo, vamos a crear un pequeño repositorio y simular un escenario. Abre tu terminal y sigue estos pasos:

mkdir cherry-pick-example
cd cherry-pick-example
git init
echo "Inicialización del proyecto." > README.md
git add README.md
git commit -m "Initial commit"

# Crear una rama de desarrollo
git branch feature/nueva-funcionalidad
git checkout feature/nueva-funcionalidad

echo "Primera funcionalidad añadida." > feature.txt
git add feature.txt
git commit -m "feat: Añadida la primera parte de la funcionalidad X"

echo "Segunda funcionalidad añadida." >> feature.txt
git add feature.txt
git commit -m "feat: Completada la funcionalidad X"

git checkout main

echo "Un bug encontrado en producción." > bug.txt
git add bug.txt
git commit -m "fix: Corrección de bug crítico en producción"

echo "Otra funcionalidad para main." >> README.md
git add README.md
git commit -m "refactor: Mejoras de rendimiento en el README"


git log --oneline --graph --all

Ahora, tu historial de Git se verá algo similar a esto (los hashes serán diferentes):

C0 Initial commit RAMA: main C3 fix: Corrección de bug crítico... C4 refactor: Mejoras de rendimiento RAMA: feature/nueva-funcionalidad C1 feat: Añadida la primera parte... C2 feat: Completada la funcionalidad X HEAD
graph LR
    C0(Initial commit) --> C1(feat: Añadida la primera parte de la funcionalidad X)
    C0 --> C3(fix: Corrección de bug crítico en producción)
    C1 --> C2(feat: Completada la funcionalidad X)
    C3 --> C4(refactor: Mejoras de rendimiento en el README)

    subgraph Branch main
        C0 --- C3 --- C4
    end

    subgraph Branch feature/nueva-funcionalidad
        C0 --- C1 --- C2
    end

    C4 --HEAD--> main
    C2 --HEAD--> feature/nueva-funcionalidad

En este escenario, el commit fix: Corrección de bug crítico en producción (representado por C3 en el diagrama) es el que necesitamos llevar a la rama feature/nueva-funcionalidad.

➡️ Paso a Paso: Realizando un cherry-pick

  1. Identifica el commit a aplicar: Primero, necesitamos el hash del commit fix: Corrección de bug crítico en producción. Puedes obtenerlo usando git log --oneline main o git log --oneline --all.
git log --oneline main
# Ejemplo de salida:
# c1b2d3f refactor: Mejoras de rendimiento en el README
# a4b5c6d fix: Corrección de bug crítico en producción
# 1234567 Initial commit
Supongamos que el hash del commit del hotfix es `a4b5c6d`.

2. Cambia a la rama destino: Asegúrate de estar en la rama donde quieres aplicar el commit.

git checkout feature/nueva-funcionalidad
  1. Aplica el commit con cherry-pick:
git cherry-pick a4b5c6d
Si todo sale bien, Git te informará que el commit fue aplicado. Ahora, si revisas `git log --oneline`, verás que un nuevo commit con los cambios del hotfix ha sido añadido a tu rama `feature/nueva-funcionalidad`.
git log --oneline --graph --all
El historial se verá así:

main feature C0 Initial commit C3 fix: Bug crítico C4 refactor: README C1 feat: Parte 1 X C2 feat: Completada X C3' (Cherry-pick) fix: Bug crítico
graph LR
C0(Initial commit) --> C1(feat: Añadida la primera parte de la funcionalidad X)
C0 --> C3(fix: Corrección de bug crítico en producción)
C1 --> C2(feat: Completada la funcionalidad X)
C3 --> C4(refactor: Mejoras de rendimiento en el README)
C2 --> C3_prime(fix: Corrección de bug crítico en producción)

subgraph Branch main
C0 --- C3 --- C4
end

subgraph Branch feature/nueva-funcionalidad
C0 --- C1 --- C2 --- C3_prime
end

C4 --HEAD--> main
C3_prime --HEAD--> feature/nueva-funcionalidad
🔥 Importante: El commit `a4b5c6d` en `main` y el nuevo commit creado en `feature/nueva-funcionalidad` (que tendrá un SHA-1 diferente, digamos `e6f7g8h`) son *distintos* para Git, aunque contengan los mismos cambios. Esto puede ser relevante para herramientas de CI/CD o para la identificación de commits únicos.

🤯 Resolución de Conflictos durante cherry-pick

Es muy común que, al aplicar un commit de una rama a otra, surjan conflictos de fusión. Esto ocurre cuando los cambios del commit que estás aplicando chocan con los cambios ya existentes en la rama destino. Git pausará la operación y te pedirá que resuelvas los conflictos manualmente, al igual que lo haría durante un merge o rebase.

📝 Pasos para Resolver Conflictos

  1. Identifica los archivos en conflicto: Git te indicará qué archivos tienen conflictos.
    git status
    # On branch feature/nueva-funcionalidad
    # You are currently cherry-picking commit a4b5c6d.
    #   (fix conflicts and run "git cherry-pick --continue")
    #   (use "git cherry-pick --abort" to cancel this cherry-pick operation)
    #
    # Unmerged paths:
    #   (use "git add <file>..." to mark resolution)
    #       both modified: bug.txt
  1. Edita los archivos en conflicto: Abre los archivos listados y busca los marcadores de conflicto ( <<<<<<<, =======, >>>>>>>). Edita el archivo para resolver el conflicto, manteniendo la versión correcta de los cambios.

  2. Marca los conflictos como resueltos: Después de editar cada archivo, usa git add para marcarlo como resuelto.

    git add bug.txt
  1. Continúa el cherry-pick: Una vez que todos los conflictos estén resueltos y los archivos añadidos, puedes continuar la operación.
    git cherry-pick --continue
    ```

    Git creará el nuevo commit con los cambios aplicados y el mensaje de commit original (que puedes editar).

### ↩️ Abortar un `cherry-pick`

Si te encuentras en un lío de conflictos y decides que no quieres continuar con el `cherry-pick`, puedes abortarlo en cualquier momento:

```bash
git cherry-pick --abort

Esto revertirá tu rama al estado en que estaba antes de iniciar el cherry-pick, desechando todos los cambios parciales.


✨ Opciones Avanzadas de cherry-pick

git cherry-pick ofrece varias opciones que te dan más control sobre cómo se aplica el commit.

📌 git cherry-pick -n o --no-commit

Esta opción aplica los cambios del commit al directorio de trabajo y al staging area (índice), pero no crea un nuevo commit. Es útil si quieres inspeccionar los cambios o modificarlos antes de hacer tu propio commit.

git cherry-pick <hash> --no-commit
# Los cambios están en tu working directory y staging area, pero no hay commit.
# Puedes hacer modificaciones, y luego:
git commit -m "Mi propio mensaje para el cherry-picked commit"

📌 git cherry-pick -e o --edit

Esta opción te permite editar el mensaje de commit antes de que se cree el nuevo commit. El editor de texto configurado en Git se abrirá con el mensaje original del commit.

git cherry-pick <hash> --edit

Esto es útil si el mensaje original no es lo suficientemente claro para el contexto de la nueva rama, o si necesitas añadir información adicional sobre por qué se ha aplicado ese commit.

📌 git cherry-pick --signoff o -s

Añade una línea Signed-off-by: al final del mensaje de commit, indicando que el commit ha sido firmado por el autor que realiza el cherry-pick. Esto es común en proyectos de código abierto para atestiguar que los cambios son suyos.

git cherry-pick <hash> --signoff
📌 Nota: Usar `--signoff` ayuda a mantener un registro de quién aprobó y aplicó el commit, lo cual puede ser importante para la auditoría de código o la conformidad en algunos proyectos.

💡 Cuándo usar git cherry-pick (Casos de Uso)

Aunque git cherry-pick es una herramienta poderosa, no debe usarse indiscriminadamente. Es crucial entender sus casos de uso óptimos para evitar complicaciones en el historial del proyecto.

1. Aplicar Hotfixes Urgentes a Múltiples Ramas

Este es el caso de uso más común y directo. Si un error crítico se detecta en producción y se corrige en la rama principal, ese mismo arreglo a menudo necesita ser aplicado rápidamente a otras ramas de desarrollo o incluso a ramas de versiones anteriores que aún están en soporte.

Paso 1: Desarrollar y fusionar hotfix a `main`.
Paso 2: `git checkout feature/X` (u otra rama).
Paso 3: `git cherry-pick `.
Paso 4: Repetir para otras ramas afectadas.

2. Trasladar Pequeñas Funcionalidades entre Ramas

A veces, una pequeña funcionalidad o una mejora se desarrolla en una rama, pero se decide que debe ir en otra rama de características o incluso en la rama principal de forma independiente. cherry-pick permite mover ese commit sin fusionar toda la rama de origen.

3. Limpieza de Historial (con Cuidado)

Aunque git rebase es la herramienta principal para reescribir el historial, cherry-pick puede ser útil para seleccionar solo los commits realmente relevantes de una rama temporal antes de integrarlos en otra, descartando commits intermedios de trabajo o de prueba. Sin embargo, esto requiere mucha cautela y una comprensión clara de lo que se está haciendo, ya que reescribir el historial puede confundir a otros colaboradores.

4. Recopilar Commits de Varias Ramas a una Sola

En ocasiones, puedes tener varios pequeños commits dispersos en diferentes ramas temporales que necesitas consolidar en una única rama de integración. cherry-pick te permite seleccionar estos commits uno a uno o en rangos, construyendo una nueva rama con solo los cambios deseados.

⚠️ Cuándo NO usar git cherry-pick (Advertencias)

A pesar de su utilidad, el uso excesivo o incorrecto de git cherry-pick puede llevar a un historial de Git confuso y difícil de mantener.

  • Evita usarlo para grandes grupos de commits: Si necesitas integrar muchos commits de una rama a otra, es probable que git merge o git rebase sean opciones más adecuadas y seguras. cherry-pick está diseñado para la granularidad, no para la integración masiva.

  • Cuidado con los commits ya compartidos: Si haces cherry-pick de un commit que ya está presente en el historial de la rama destino (por ejemplo, porque una rama ya se fusionó a main, y luego main se fusionó a tu rama), podrías introducir un commit duplicado con el mismo contenido, aunque con un hash diferente. Esto puede confundir a herramientas de detección de duplicados y dificultar la resolución de futuros merges.

    ⚠️ Advertencia: Un `cherry-pick` de un commit ya fusionado creará un commit duplicado con un SHA-1 diferente. Esto puede generar problemas si intentas fusionar las ramas más tarde, ya que Git verá el mismo cambio dos veces y podría requerir resolución de conflictos manual, incluso si no hay conflictos reales.
  • Impacto en el historial: Recuerda que cherry-pick crea nuevos commits. Esto puede hacer que el historial se vea un poco más complejo, especialmente si el mismo commit original se ha cherry-picked varias veces a diferentes ramas. Considera siempre la legibilidad del historial.

🔄 Alternativas a git cherry-pick

Es importante saber que cherry-pick no es la única forma de mover cambios entre ramas. Dependiendo del escenario, otras herramientas de Git pueden ser más apropiadas.

git merge

Es la forma estándar de integrar cambios de una rama a otra. merge trae todos los commits desde el punto de bifurcación común hasta el HEAD de la rama de origen, creando un merge commit si no es un fast-forward merge. Es ideal para integrar ramas de características completas.

Característicagit cherry-pickgit merge
---------
GranularidadA nivel de commit individual (o rango).A nivel de rama completa (todos los commits desde un ancestro común).
HistorialCrea nuevos commits, puede duplicar cambios lógicamente.Mantiene el historial original, añade un merge commit.
---------
Uso principalHotfixes, funcionalidades muy específicas.Integración de ramas completas, sincronización.
ComplejidadRequiere identificar hashes específicos.Simple: git merge <rama>.

git rebase

rebase reescribe el historial aplicando los commits de una rama después de la última commit de otra rama, dando la apariencia de una línea de desarrollo recta. Es excelente para limpiar historiales antes de fusionar o para mantener ramas de desarrollo actualizadas con la main.

¿Rebase o Cherry-pick? Una Comparación Rápida

Ambas herramientas manipulan el historial al crear nuevos commits con los mismos cambios. La diferencia principal radica en la escala y el propósito:

  • cherry-pick: Para mover commits específicos de forma quirúrgica. No cambia la base de la rama entera, solo añade commits nuevos.
  • rebase: Para cambiar la base de una rama completa, aplicando sus commits sobre un nuevo punto en el historial. Más potente para reorganizar y limpiar el historial de una secuencia de commits.

Usa rebase cuando quieres mover toda tu rama a un nuevo punto en el historial de otra rama. Usa cherry-pick cuando solo quieres traer uno o dos commits específicos de cualquier parte del historial a tu rama actual, sin rebasar toda tu rama.

git patch

Si bien no es un comando de Git directamente comparable en su uso diario, la generación y aplicación de parches (git format-patch y git apply) puede verse como una alternativa aún más granular para mover cambios. Generas un archivo .patch de uno o varios commits y luego lo aplicas en cualquier otro repositorio o rama. Es útil para compartir cambios sin dar acceso directo al repositorio, pero es menos interactivo y flexible que cherry-pick para operaciones internas en el mismo repositorio.

80% Granularidad
40% Integración masiva

✅ Buenas Prácticas al Usar git cherry-pick

Para aprovechar al máximo git cherry-pick y evitar dolores de cabeza, sigue estas recomendaciones:

  1. Identifica commits cuidadosamente: Siempre verifica el contenido del commit que vas a aplicar (git show <hash>) antes de ejecutar cherry-pick. Asegúrate de que es exactamente lo que necesitas.
  2. Úsalo con moderación: cherry-pick es una herramienta de precisión. Si necesitas mover muchos commits o integrar una rama completa, merge o rebase son generalmente mejores opciones.
  3. Resuelve conflictos con atención: Los conflictos son inevitables. Tómate tu tiempo para resolverlos correctamente y prueba tu código después de cada cherry-pick que involucre conflictos.
  4. Comunica con tu equipo: Si vas a cherry-pick commits importantes o a ramas compartidas, informa a tu equipo. Esto ayuda a evitar confusiones y posibles duplicidades en el trabajo.
  5. Evita commits duplicados: Sé consciente de la posibilidad de crear commits lógicamente duplicados. Si un commit ya se ha fusionado en la rama destino, cherry-pick de ese mismo commit no es necesario y puede causar problemas futuros.
  6. Considera el --no-commit: Para mayor control, especialmente si planeas modificar los cambios o agruparlos con otros antes de un nuevo commit, --no-commit es una opción valiosa.

❓ Preguntas Frecuentes (FAQ)

¿Puedo hacer cherry-pick de un commit de otra persona? Sí, `git cherry-pick` opera sobre commits, no sobre autores. Mientras tengas acceso al historial del repositorio y al hash del commit, puedes aplicarlo a tu rama. El autor original del commit se mantendrá en el nuevo commit, pero el "committer" serás tú (a menos que uses opciones específicas de reescritura de autor, lo cual es más avanzado).
¿Qué sucede si hago cherry-pick de un commit que ya existe? Git creará un *nuevo* commit con los mismos cambios, pero con un SHA-1 diferente. Esto se conoce como un commit duplicado lógico. Puede generar conflictos en futuras fusiones (especialmente si se usan estrategias de fusión que detectan cambios idénticos) y dificultar el seguimiento del historial.
¿Es `git cherry-pick` una herramienta para principiantes o avanzados? Se considera una herramienta Intermedio a Avanzado. Aunque su sintaxis básica es sencilla, entender cuándo y cómo usarla correctamente, especialmente en la resolución de conflictos y la gestión del historial, requiere una buena comprensión de Git.
¿Puedo revertir un cherry-pick? Sí, puedes revertir el nuevo commit creado por `cherry-pick` usando `git revert `. Esto creará un nuevo commit que deshace los cambios del commit revertido.
¿Cómo hago cherry-pick de varios commits de forma interactiva? Para seleccionar y quizás modificar varios commits de forma interactiva, `git rebase -i ` es una herramienta más potente y adecuada. Dentro del rebase interactivo, puedes usar la acción `pick` para cada commit que quieras incluir, o incluso `edit` para modificarlo antes de que se aplique.

🏁 Conclusión

git cherry-pick es una herramienta invaluable en el arsenal de cualquier desarrollador que trabaja con Git. Ofrece una granularidad única para mover cambios específicos entre ramas, lo que lo hace indispensable para hotfixes rápidos, portar características menores o limpiar historiales de forma controlada. Sin embargo, su poder conlleva la responsabilidad de usarlo juiciosamente, comprendiendo sus implicaciones en el historial y prefiriendo merge o rebase cuando el escenario lo requiera.

Al dominar cherry-pick, añadirás una habilidad de precisión a tu flujo de trabajo de Git, permitiéndote gestionar tus repositorios con mayor flexibilidad y eficiencia.

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!