Git cherry-pick: varios commits, ramas y conflictos

Git cherry-pick explicado: copia un commit de otra rama, elige varios commits o un rango, resuelve conflictos y sabe cuándo conviene merge o rebase.

HUMANpor @mrsaynothing44d5 min de lectura

TL;DR: git cherry-pick <sha> copia un commit de cualquier rama a tu rama actual — mismo parche, SHA nuevo, ningún historial movido. Para varios commits, lista los SHAs o usa un rango (git cherry-pick A..B); ojo, el rango excluye A, así que escribe A^..B para incluirlo. Si se detiene en un conflicto, resuelve, git add y luego git cherry-pick --continue. Cherry-pick es para mover un arreglo específico — cuando quieres todo lo de la otra rama, merge o rebase en su lugar.

¿Qué hace realmente git cherry-pick?

Cherry-pick toma un commit existente y aplica su diff como un commit nuevo en tu rama actual. El commit original se queda donde está; la copia recibe un SHA fresco. Git no "mueve" nada — la gente que luego se pregunta por qué el commit sigue apareciendo en la rama vieja está viendo exactamente esto.

Ese modelo de copiar-sin-mover decide cuándo cherry-pick es la herramienta correcta:

  • Necesitas un arreglo de una rama feature en main ya, sin fusionar el resto.
  • Un hotfix commiteado en la rama equivocada debe aterrizar en la correcta.
  • Un parche debe reproducirse en una rama de release que nunca hace merge desde main.

La habilidad complementaria es saber deshacer un commit que resultó equivocado — la mecánica está cubierta en git undo last commit: keep the changes.

¿Cómo hago cherry-pick de un commit de otra rama?

Encuentra el SHA, cámbiate a la rama destino, pick:

# 1. Ubica el commit en la rama de origen
git log feature/payment-fix --oneline -5

# 2. Cámbiate a la rama que debe recibirlo
git switch main

# 3. Cópialo
git cherry-pick 1a2b3c4

Dos comodidades que vale conocer:

  • git cherry-pick <branch> toma el commit tip de esa rama — útil, pero fácil de ejecutar por accidente con una imagen mental vencida de qué es "el tip".
  • Después del pick, git log -1 --stat confirma qué aterrizó. Un segundo de lectura te ahorra un revert.

Los commits se quedan en feature/payment-fix; borra esa rama cuando quieras — la copia elegida en main tiene su propio SHA y ninguna dependencia del viejo.

¿Cómo hago cherry-pick de varios commits?

Tres formas, ordenadas por frecuencia de uso:

Las tres funcionan también entre ramas: los SHAs se resuelven contra todo el repositorio, así que los commits pueden venir de cualquier rama — solo tienes que estar ubicado en la rama que los recibe.

# 1. Lista explícita — se toman en el orden en que los listas
git cherry-pick 1a2b3c4 5d6e7f8

# 2. Rango — todo después de A hasta e incluyendo B
git cherry-pick A..B

# 3. Rango incluyendo A
git cherry-pick A^..B

La distinción A..B vs A^..B es la sorpresa clásica: A..B excluye A. Si visualizas el rango desde git log y haces pick de oldest..newest, te saltas el commit más viejo en silencio. Cuando la meta es "los commits más viejos, en orden", escribe oldest^..newest y el off-by-one desaparece.

Para doblar varios picks en un commit en vez de tres, haz stage sin commitear con -n / --no-commit y commitea una sola vez:

git cherry-pick -n 1a2b3c4 5d6e7f8
git commit -m "Backport: payment retry fixes"

¿Por qué git cherry-pick no funciona?

Cuatro causas reales, por orden de frecuencia:

1. Un conflicto detuvo el pick. Git aplica el parche, se topa con una línea que cambió en ambas ramas y pausa a mitad de secuencia:

# resuelve los archivos, luego:
git add <resolved-files>
git cherry-pick --continue   # o --abort para volver al estado previo al pick

--continue no es opcional ni está implícito — hasta que lo ejecutes, estás dentro de una secuencia de cherry-pick pausada y git status seguirá diciéndolo.

2. El pick está vacío ("The previous cherry-pick is now empty"). El cambio ya existe en esta rama, a menudo por un pick anterior o un merge con squash. Sáltalo con git cherry-pick --skip, o fuerza un commit vacío con --allow-empty si de verdad necesitas la marca.

3. El commit es un merge commit. Un merge tiene dos padres, así que "aplica este diff" es ambiguo — git se niega en vez de adivinar. Di contra qué padre haces el diff:

git cherry-pick -m 1 <merge-sha>   # padre 1 = la rama *hacia* la que se hizo el merge

4. Working tree equivocado o detached HEAD. El pick aterriza donde apunte HEAD. git branch --show-current antes de pickar; si no imprime nada, estás en detached HEAD y el commit quedará huérfano al cambiar de rama.

Cherry-pick vs merge vs rebase: cuál usar cuando

Comando Qué aterriza en el destino Historial Úsalo cuando
git cherry-pick <sha> Solo los commits nombrados Copia, SHAs nuevos Un arreglo específico debe moverse ya
git merge <branch> Todo lo de la rama Merge commit o fast-forward Quieres la rama entera, con la divergencia visible
git rebase <base> Todos los commits de la rama, reproducidos Lineal, SHAs reescritos Quieres la rama como una corrida lineal limpia
git revert <sha> Inverso de un commit Añade un commit de undo Un commit ya aterrizado debe deshacerse en historial compartido

La regla de una línea: cherry-pick mueve una selección; merge y rebase mueven todo. Recurrir a cherry-pick para "sincronizar" con una rama es señal de que en realidad quieres un merge — y si la comparación es el main de tu fork contra upstream, la rutina completa está en sync a fork with upstream, step by step.

Un hábito que conviene saltarse: hacer cherry-pick del mismo commit a varias ramas a largo plazo. Cada arreglo futuro en la rama de origen necesita otro pick, y tarde o temprano las ramas divergen. Los backports a ramas de release son un patrón normal; un universo paralelo permanente no.

El flujo de cherry-pick, condensado

git log <source-branch> --oneline -5   # encuentra el/los SHA
git switch <target-branch>             # aterriza en el lugar correcto
git cherry-pick A^..B                  # rango, lista o un solo SHA
# ante conflicto: resuelve → git add → git cherry-pick --continue
git log -1 --stat                      # confirma qué aterrizó

Encuentra, cámbiate, pick, verifica. El comando tiene una reputación de peligro que no merece — el diff se aplica o se detiene y te dice por qué. El único error genuinamente destructivo es pickar en la rama equivocada, y git log -1 antes del push hace que ese sea difícil de pasar por alto.