
Cherry-Pick: A Arte da Cirurgia de Commits
Domine o git cherry-pick, desde o uso básico `abc123` até a aplicação em série, resolução de conflitos complexos e automação para hotfixes e backports.
✨TL;DR / Sumário Executivo
Domine o git cherry-pick, desde o uso básico `abc123` até a aplicação em série, resolução de conflitos complexos e automação para hotfixes e backports.
💡 TL;DR (Resumo)
Cherry-pick é a capacidade do Git de aplicar commits específicos de uma branch para outra, como um transplante cirúrgico de código. Vai muito além do uso básico
git cherry-pick abc123- inclui aplicação em série, resolução de conflitos complexos, cherry-pick reverso, e automação para releases multi-versão. É fundamental para hotfixes em produção, backports de features, e sincronização seletiva entre branches de desenvolvimento. Quando dominado, torna-se uma ferramenta de precisão para scenarios onde merge completo seria inadequado, mas você precisa de mudanças específicas aplicadas com controle total.
É 3:47 da madrugada. Seu pager acabou de tocar com um alerta crítico: falha de segurança em produção. O fix já está implementado e testado na branch de desenvolvimento, mas produção está rodando uma versão três releases atrás. Fazer merge da branch inteira traria centenas de commits não testados para produção.
Você precisa de cirurgia, não de transplante de órgão completo.
Você precisa de cherry-pick.
Esta é a história da ferramenta mais subestimada do Git - uma que transforma desenvolvedores em cirurgiões de código, capazes de extrair commits específicos e transplantá-los com precisão milimétrica para qualquer branch que precise deles.
O Problema que Cherry-Pick Resolve
Cenário Real: A Emergência de Produção
Imagine esta situação (baseada em caso real de sistema de pagamentos):
# Estado atual dos branches
git log --oneline --graph --all
# * f1a2b3c (develop) Add new payment gateway
# * e4d5c6f Refactor authentication system
# * a7b8c9d Fix critical SQL injection vulnerability ← ESTE É O QUE PRECISAMOS
# * 1x2y3z4 Update dependencies
# * 5a6b7c8 (main, production) Last stable releaseO Dilema:
- Commit
a7b8c9dtem o fix crítico de segurança - Mas está "enterrado" entre outros commits não testados em produção
- Merge completo de
developintroduziria riscos imensos - Produção precisa do fix AGORA
Solução Tradicional (Inadequada):
# Opção 1: Replicar mudanças manualmente
git checkout main
# Copia e cola código do commit
# Propenso a erros, perde histórico, não escalável
# Opção 2: Merge completo
git merge develop
# Traz TODOS os commits, testados ou não
# Risco inaceitável para produçãoSolução Cherry-Pick (Elegante):
# Cirurgia precisa: extrai APENAS o commit necessário
git checkout main
git cherry-pick a7b8c9d
# Resultado: fix aplicado, histórico preservado, risco controladoPor que Cherry-Pick é Revolucionário
Cherry-pick implementa um conceito fundamental: aplicação seletiva de mudanças. É como ter uma ferramenta que extrai DNA específico de uma célula e o transplanta para outra, mantendo toda a informação genética intacta.
# Cherry-pick preserva:
# - Autor original
# - Timestamp
# - Commit message
# - Changeset exato
# - Metadata completa
git cherry-pick a7b8c9d
# Author: John Doe <[email protected]>
# Date: Mon Oct 15 14:30:22 2024 -0300
# (cherry picked from commit a7b8c9d1234567890abcdef)Anatomia de um Cherry-Pick
O Algoritmo por Trás da Magia
Cherry-pick usa o mesmo algoritmo de merge de 3-vias do Git, mas de forma diferente:
# Cherry-pick de commit C aplicado em branch B
#
# ANTES:
# A---B (current branch)
# \
# P---C (source branch)
#
# Git compara:
# - Parent de C (P)
# - Commit C
# - Current HEAD (B)
#
# DEPOIS:
# A---B---C' (C' = C aplicado sobre B)O processo interno:
git cherry-pick c1234567
# 1. Git identifica parent do commit source
git show --pretty=format:"%P" c1234567
# a9876543
# 2. Calcula diff entre parent e commit
git diff a9876543..c1234567
# 3. Aplica esse diff no HEAD atual
# 4. Cria novo commit com mesmo conteúdo mas novo parentCherry-Pick vs Outras Operações
# MERGE: traz histórico completo
git merge feature-branch
# Todos os commits de feature-branch vêm junto
# REBASE: move commits, reescrevendo história
git rebase feature-branch
# Muda parent commits, reescreve SHAs
# CHERRY-PICK: copia commit específico, preserva original
git cherry-pick abc123
# Original permanece inalterado, nova cópia criadaCherry-Pick Básico: Além do Óbvio
Single Commit - A Base
# Aplicar um commit específico
git cherry-pick a1b2c3d
# Visualizar o que será aplicado antes
git show a1b2c3d --stat
# Mostra arquivos que serão modificados
# Cherry-pick com commit message personalizada
git cherry-pick a1b2c3d --edit
# Abre editor para modificar mensagemMultiple Commits - Poder Real
# Range de commits (exclusivo do início)
git cherry-pick start-commit..end-commit
# Aplica todos entre start e end (start não incluído)
# Range inclusivo
git cherry-pick start-commit^..end-commit
# Inclui start-commit também
# Lista específica de commits
git cherry-pick commit1 commit2 commit3
# Aplica os três commits em sequênciaExemplo Prático - Backport de Feature:
# Feature implementada em develop com 4 commits
git log --oneline develop
# d4e5f6g Complete user authentication feature
# c3d4e5f Add password validation
# b2c3d4e Implement user registration
# a1b2c3d Add user model
# Backport completo para release branch
git checkout release/v2.1
git cherry-pick a1b2c3d^..d4e5f6g
# Todos os 4 commits aplicados em ordem na releaseResolução de Conflitos: A Cirurgia Complexa
Conflitos em Cherry-Pick São Diferentes
Conflitos em cherry-pick têm características únicas porque você está aplicando mudanças fora do contexto original:
git cherry-pick feature-commit
# Auto-merging src/payment.js
# CONFLICT (content): Merge conflict in src/payment.js
# error: could not apply a1b2c3d... Add new payment method
# Estado especial: CHERRY_PICK_HEAD
git status
# On branch main
# You are currently cherry-picking commit a1b2c3d.
# (fix conflicts and run "git cherry-pick --continue")
# (use "git cherry-pick --skip" to skip this patch)
# (use "git cherry-pick --abort" to cancel the cherry-pick operation)Estratégias de Resolução
1. Resolução Manual Tradicional:
# Edita arquivos conflitantes
vim src/payment.js
# Resolve conflitos manualmente
git add src/payment.js
git cherry-pick --continue2. Estratégias Automáticas:
# Usar estratégia específica
git cherry-pick -X theirs a1b2c3d
# Em caso de conflito, prefere mudanças do commit sendo cherry-picked
git cherry-pick -X ours a1b2c3d
# Em caso de conflito, prefere estado atual da branch3. Cherry-Pick com Merge Tool:
# Configurar merge tool (exemplo: vimdiff)
git config merge.tool vimdiff
git cherry-pick problematic-commit
# Em caso de conflito:
git mergetool
# Abre interface visual para resoluçãoConflitos em Série - O Desafio Real
# Cherry-picking múltiplos commits com conflitos
git cherry-pick commit1 commit2 commit3
# Se commit2 conflita:
# 1. Resolve conflito em commit2
git add .
git cherry-pick --continue
# 2. Git automaticamente continua para commit3
# 3. Se commit3 também conflita, repete processoScript de Automação para Conflitos Previsíveis:
#!/bin/bash
# cherry-pick-with-auto-resolve.sh
commits=("$@")
for commit in "${commits[@]}"; do
echo "Cherry-picking $commit..."
if ! git cherry-pick "$commit"; then
echo "Conflict in $commit, attempting auto-resolve..."
# Estratégia customizada baseada em padrões de conflito
if grep -q "package.json" .git/CHERRY_PICK_HEAD; then
# Para conflitos em package.json, prefere versão mais nova
git checkout --theirs package.json
git add package.json
git cherry-pick --continue
else
echo "Manual resolution required for $commit"
exit 1
fi
fi
doneTécnicas Avançadas: A Maestria
Cherry-Pick Reverso - Desfazendo Aplicações
# Scenario: cherry-pick foi aplicado incorretamente
git log --oneline
# f5e4d3c (HEAD) Fix authentication bug (cherry picked from a1b2c3d)
# c2b1a09 Previous commit
# Opção 1: Revert do cherry-pick
git revert f5e4d3c
# Cria commit que desfaz as mudanças
# Opção 2: Cherry-pick reverso (mais elegante)
git cherry-pick -R a1b2c3d
# Aplica o inverso do commit originalCherry-Pick com Modificações
# Aplicar commit mas não fazer commit automaticamente
git cherry-pick --no-commit a1b2c3d
# Agora você pode:
# - Modificar arquivos
# - Adicionar mudanças extras
# - Ajustar commit message
# Finalizar quando pronto
git commit -m "Cherry-picked a1b2c3d with modifications"Mainline Selection em Merge Commits
Merge commits têm múltiplos parents - cherry-pick precisa saber qual usar:
# Merge commit tem 2 parents
git show --pretty=format:"%P" merge-commit
# parent1-sha parent2-sha
# Especificar qual parent usar como base
git cherry-pick -m 1 merge-commit # Usa primeiro parent
git cherry-pick -m 2 merge-commit # Usa segundo parentCherry-Pick com Preservação de Merge
# Para manter estrutura de merge em cherry-pick
git cherry-pick -m 1 --keep-redundant-commits merge-commit
# Útil quando estrutura de merge é importante para históricoWorkflows Profissionais com Cherry-Pick
1. Hotfix Multi-Versão
Cenário: Empresa mantém 3 versões em produção, bug crítico descoberto.
#!/bin/bash
# hotfix-multi-version.sh
BUG_FIX_COMMIT="a1b2c3d"
VERSIONS=("release/v1.0" "release/v2.0" "main")
echo "Applying hotfix $BUG_FIX_COMMIT to all versions..."
for version in "${VERSIONS[@]}"; do
echo "Processing $version..."
git checkout "$version"
git pull origin "$version"
if git cherry-pick "$BUG_FIX_COMMIT"; then
echo "✅ Successfully applied to $version"
git push origin "$version"
else
echo "❌ Conflicts in $version - manual resolution required"
# Notificar equipe ou abrir ticket
git cherry-pick --abort
fi
done2. Feature Backport Seletivo
# Cenário: Feature grande em develop, mas cliente precisa só de parte
git log --oneline develop
# h7i8j9k Complete social login feature
# g6h7i8j Add Google OAuth
# f5g6h7i Add Facebook login
# e4f5g6h Add base OAuth framework
# d3e4f5g Previous work...
# Cliente quer apenas Google OAuth (sem Facebook)
git checkout release/client-special
# Cherry-pick seletivo
git cherry-pick e4f5g6h # Base framework
git cherry-pick g6h7i8j # Google OAuth
# Pula f5g6h7i (Facebook) intencionalmente
# Resultado: cliente tem Google OAuth sem Facebook3. Release Preparation Workflow
# Cenário: Preparar release com features específicas de develop
git checkout -b release/v2.3.0 main
# Features aprovadas para release
APPROVED_FEATURES=(
"feature1-final-commit"
"feature2-final-commit"
"bugfix-critical-commit"
)
# Script de preparação de release
for feature in "${APPROVED_FEATURES[@]}"; do
echo "Including feature: $feature"
# Encontrar todos commits da feature
feature_commits=$(git log --reverse --pretty=format:"%H" $feature ^main)
# Cherry-pick toda a feature
git cherry-pick $feature_commits
done
# Release branch pronta com apenas features aprovadas4. Dependency Update Selective Sync
# Cenário: Update de dependência em develop, aplicar seletivamente
git log --oneline develop | grep "deps:"
# j9k0l1m deps: Update lodash to 4.17.21
# i8j9k0l deps: Update react to 18.2.0
# h7i8j9k deps: Update webpack to 5.75.0
# Aplicar apenas updates críticos de segurança
git checkout main
git cherry-pick j9k0l1m # lodash (security fix)
# Pula react e webpack (breaking changes)
# Main tem security fix sem breaking changesAutomação e Scripting Avançado
Script de Cherry-Pick Inteligente
#!/bin/bash
# intelligent-cherry-pick.sh
function smart_cherry_pick() {
local commit=$1
local target_branch=$2
echo "Analyzing commit $commit for $target_branch..."
# Verificar se commit já foi aplicado
if git merge-base --is-ancestor "$commit" "$target_branch"; then
echo "⚠️ Commit already in $target_branch history"
return 1
fi
# Verificar se é merge commit
if [[ $(git cat-file -p "$commit" | grep -c "^parent ") -gt 1 ]]; then
echo "⚠️ Merge commit detected - manual review required"
return 1
fi
# Tentar cherry-pick
if git cherry-pick "$commit"; then
echo "✅ Successfully cherry-picked $commit"
return 0
else
echo "❌ Conflicts detected in $commit"
# Análise automática de conflitos
conflict_files=$(git diff --name-only --diff-filter=U)
echo "Conflicted files: $conflict_files"
# Estratégias automáticas baseadas em tipo de arquivo
for file in $conflict_files; do
case "$file" in
*.json)
echo "JSON conflict - attempting merge..."
git checkout --theirs "$file"
git add "$file"
;;
*.md|*.txt)
echo "Documentation conflict - preferring theirs..."
git checkout --theirs "$file"
git add "$file"
;;
*)
echo "Code conflict in $file - manual resolution required"
return 1
;;
esac
done
# Tentar continuar após resolução automática
if git cherry-pick --continue; then
echo "✅ Auto-resolved and applied $commit"
return 0
else
git cherry-pick --abort
echo "❌ Auto-resolution failed for $commit"
return 1
fi
fi
}
# Uso do script
smart_cherry_pick "a1b2c3d" "$(git rev-parse --abbrev-ref HEAD)"Cherry-Pick com Validação Automática
#!/bin/bash
# validated-cherry-pick.sh
function validated_cherry_pick() {
local commit=$1
echo "Pre-flight checks for $commit..."
# Backup do estado atual
local current_commit=$(git rev-parse HEAD)
# Tentar cherry-pick em branch temporária
git checkout -b "temp-cherry-pick-$(date +%s)"
if git cherry-pick "$commit"; then
echo "✅ Cherry-pick successful, running validations..."
# Validações automáticas
if command -v npm &> /dev/null && [[ -f "package.json" ]]; then
echo "Running npm tests..."
if npm test; then
echo "✅ Tests pass"
else
echo "❌ Tests fail - aborting cherry-pick"
git checkout -
git branch -D "temp-cherry-pick-*"
return 1
fi
fi
# Validação de build
if [[ -f "Makefile" ]]; then
echo "Testing build..."
if make; then
echo "✅ Build successful"
else
echo "❌ Build fails - aborting cherry-pick"
git checkout -
git branch -D "temp-cherry-pick-*"
return 1
fi
fi
# Aplicar na branch original
git checkout -
git cherry-pick "$commit"
git branch -D "temp-cherry-pick-*"
echo "✅ Validated cherry-pick complete"
else
echo "❌ Cherry-pick failed"
git checkout -
git branch -D "temp-cherry-pick-*"
return 1
fi
}Troubleshooting: Quando Cherry-Pick Dá Errado
Problemas Comuns e Soluções
1. Commit Já Aplicado:
# Erro: "The previous cherry-pick is now empty"
git cherry-pick a1b2c3d
# error: The previous cherry-pick is now empty, possibly due to conflict resolution.
# Diagnóstico: commit já existe na branch atual
git log --grep="a1b2c3d"
# Solução: skip se intencional
git cherry-pick --skip2. Dependências Não Satisfeitas:
# Commit depende de outros commits não presentes
git cherry-pick feature-final-commit
# Erro: código não compila, referências indefinidas
# Solução: cherry-pick dependencies primeiro
git log --reverse feature-branch ^current-branch
# Identifica commits missing, aplica em ordem3. Conflitos Recorrentes:
# Mesmo conflito aparece em múltiplos cherry-picks
# Solução: rerere (reuse recorded resolution)
git config rerere.enabled true
# Git memoriza resolução de conflitos
# Aplica automaticamente em situações similaresRecovery de Cherry-Pick Problemático
# Estado corrompido durante cherry-pick
git status
# You are currently cherry-picking commit a1b2c3d.
# Opções de recovery:
# 1. Abortar completamente
git cherry-pick --abort # Volta ao estado anterior
# 2. Skip commit atual
git cherry-pick --skip # Pula para próximo na série
# 3. Reset manual se tudo falhar
git reset --hard HEAD~1 # Volta 1 commit (use com cuidado)Performance e Otimização
Cherry-Pick em Repositórios Grandes
# Para repositórios com milhões de commits
# Usar estratégias de performance
# 1. Shallow clone para operações temporárias
git clone --depth 50 large-repo temp-cherry-pick
cd temp-cherry-pick
# 2. Fetch apenas commits necessários
git fetch origin +commit-hash:refs/remotes/origin/temp-ref
# 3. Cherry-pick com cache otimizado
git config core.preloadindex true
git config core.fscache trueBatch Cherry-Pick Otimizado
#!/bin/bash
# batch-optimized-cherry-pick.sh
commits=("$@")
total=${#commits[@]}
echo "Batch cherry-picking $total commits..."
# Pre-load all objects
git cat-file --batch-check <<< "${commits[*]}" |
git cat-file --batch >/dev/null
# Apply with progress
for i in "${!commits[@]}"; do
commit=${commits[$i]}
progress=$(( (i + 1) * 100 / total ))
echo -ne "\r[$progress%] Applying $commit..."
if ! git cherry-pick "$commit" >/dev/null 2>&1; then
echo -e "\n❌ Failed at $commit"
exit 1
fi
done
echo -e "\n✅ Batch complete: $total commits applied"Casos de Uso Avançados
1. Security Patch Distribution
# Cenário: Vulnerabilidade descoberta, patch deve ir para todas versões
SECURITY_PATCH="security-fix-sha"
AFFECTED_BRANCHES=(
"release/v1.0" # Legacy ainda em uso
"release/v2.0" # Current stable
"release/v2.1" # Current beta
"main" # Development
)
function distribute_security_patch() {
local patch=$1
shift
local branches=("$@")
echo "🔒 Distributing security patch $patch..."
for branch in "${branches[@]}"; do
echo "Applying to $branch..."
git checkout "$branch"
git pull origin "$branch"
if git cherry-pick "$patch"; then
# Tag como security release
version=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
new_version="${version%.*}.$((${version##*.} + 1))-security"
git tag -a "$new_version" -m "Security release: $patch"
git push origin "$branch" --tags
echo "✅ $branch updated and tagged as $new_version"
else
echo "❌ Manual resolution required for $branch"
git cherry-pick --abort
fi
done
}
distribute_security_patch "$SECURITY_PATCH" "${AFFECTED_BRANCHES[@]}"2. A/B Test Feature Deployment
# Cenário: Feature para A/B test, aplicar seletivamente
FEATURE_COMMITS=(
"ab1234 - Add A/B test framework"
"cd5678 - Implement variant A"
"ef9012 - Implement variant B"
"gh3456 - Add metrics collection"
)
# Deploy A/B framework + variant A para produção A
git checkout production-a
git cherry-pick ab1234 cd5678 gh3456
# Deploy A/B framework + variant B para produção B
git checkout production-b
git cherry-pick ab1234 ef9012 gh3456
# Ambos ambientes têm framework e métricas
# Mas variants diferentes para comparação3. Client-Specific Customization
# Cenário: SaaS com customizações por cliente
CLIENT_CUSTOMIZATIONS=(
"client-a:feature1,feature3,bugfix2"
"client-b:feature2,feature3,enhancement1"
"client-c:feature1,feature2,bugfix1,bugfix2"
)
function deploy_client_version() {
local client=$1
local features=$2
echo "Building version for $client..."
# Branch específica do cliente
git checkout -b "release/$client-$(date +%Y%m%d)" main
# Aplicar features específicas
IFS=',' read -ra FEATURES <<< "$features"
for feature in "${FEATURES[@]}"; do
echo "Applying $feature for $client..."
git cherry-pick "$feature"
done
# Build e deploy
echo "✅ Custom version for $client ready"
}
# Processar cada cliente
for config in "${CLIENT_CUSTOMIZATIONS[@]}"; do
client="${config%%:*}"
features="${config##*:}"
deploy_client_version "$client" "$features"
doneMonitoramento e Auditoria
Tracking Cherry-Picks
# Encontrar todos cherry-picks no repositório
git log --grep="cherry picked from commit" --oneline
# Rastrear origem de commit cherry-picked
git show commit-sha | grep "cherry picked from"
# Ver todos cherry-picks de um commit específico
git log --all --grep="$(git rev-parse --short original-commit)"Script de Auditoria
#!/bin/bash
# cherry-pick-audit.sh
function audit_cherry_picks() {
local branch=${1:-HEAD}
echo "Cherry-pick audit for branch: $branch"
echo "=================================="
# Encontrar todos cherry-picks
cherry_picks=$(git log "$branch" --grep="cherry picked from commit" --pretty=format:"%H")
if [[ -z "$cherry_picks" ]]; then
echo "No cherry-picks found."
return 0
fi
echo "Found $(echo "$cherry_picks" | wc -l) cherry-picked commits:"
echo
for commit in $cherry_picks; do
echo "Commit: $(git rev-parse --short $commit)"
echo "Message: $(git log -1 --pretty=format:'%s' $commit)"
# Extrair commit original
original=$(git log -1 --pretty=format:'%b' $commit |
grep "cherry picked from commit" |
sed 's/.*cherry picked from commit \([a-f0-9]*\).*/\1/')
if [[ -n "$original" ]]; then
echo "Original: $original"
echo "Author: $(git log -1 --pretty=format:'%an <%ae>' $original)"
echo "Date: $(git log -1 --pretty=format:'%ad' $original)"
fi
echo "---"
done
}
audit_cherry_picks "$@"Conclusão: A Maestria da Precisão
Cherry-pick é muito mais que um comando Git - é uma filosofia de precisão cirúrgica aplicada ao desenvolvimento de software. Quando dominado, transforma você de um desenvolvedor que aplica mudanças em massa para um cirurgião de código capaz de extrair e transplantar funcionalidades com precisão milimétrica.
As Lições Fundamentais
1. Precisão sobre Volume
- Nem sempre você precisa de merge completo
- Às vezes, mudanças específicas são exatamente o que você precisa
- Cherry-pick oferece controle granular impossível com merge
2. Context Preservation
- Cherry-pick mantém integridade do commit original
- Autor, timestamp, e metadata são preservados
- Rastreabilidade completa entre original e cópia
3. Risk Management
- Aplicação seletiva reduz surface de risco
- Testes podem focar apenas nas mudanças aplicadas
- Rollback é simples e granular
Quando Usar Cherry-Pick
✅ Use para:
- Hotfixes críticos em produção
- Backports seletivos de features
- Sincronização entre release branches
- Aplicação de security patches
- Customizações cliente-específicas
❌ Evite para:
- Substituir workflows normais de merge
- Aplicar mudanças que dependem de contexto perdido
- Situations onde historical integrity é crítica
- Quando existe alternativa menos disruptiva
O Poder da Automação
Os scripts e workflows mostrados neste artigo demonstram que cherry-pick verdadeiramente poderoso vem da automação inteligente:
- Validation scripts previnem erros
- Batch operations escalam para múltiplos commits
- Conflict resolution automatizada reduz intervenção manual
- Audit trails mantêm compliance e transparency
A Evolução Contínua
Cherry-pick continua evoluindo com novas features do Git:
- Melhor handling de merge commits
- Estratégias de conflict resolution mais sofisticadas
- Integration com ferramentas de CI/CD
- Support para workflows GitOps
A verdadeira maestria não está em usar cherry-pick para tudo, mas em saber exatamente quando é a ferramenta certa para o problema específico.
Como toda ferramenta poderosa, cherry-pick exige sabedoria. Use-o como um cirurgião usa o seu bisturi - com precisão, propósito, e profundo entendimento das consequências de cada corte.
"The best surgeon is not the one who operates the most, but the one who knows exactly when surgery is necessary."
No mundo Git, cherry-pick é sua ferramenta cirúrgica. Use-a com sabedoria.