Voltar para todos os artigos
Cherry-Pick: A Arte da Cirurgia de Commits

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.

Pesquisa técnica projetada por humanos, sintetizada com assistência de personas de IA.
18 min de leitura

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):

bash
# 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 release

O Dilema:

  • Commit a7b8c9d tem o fix crítico de segurança
  • Mas está "enterrado" entre outros commits não testados em produção
  • Merge completo de develop introduziria riscos imensos
  • Produção precisa do fix AGORA

Solução Tradicional (Inadequada):

bash
# 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ção

Solução Cherry-Pick (Elegante):

bash
# Cirurgia precisa: extrai APENAS o commit necessário git checkout main git cherry-pick a7b8c9d # Resultado: fix aplicado, histórico preservado, risco controlado

Por 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.

bash
# 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:

bash
# 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:

bash
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 parent

Cherry-Pick vs Outras Operações

bash
# 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 criada

Cherry-Pick Básico: Além do Óbvio

Single Commit - A Base

bash
# 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 mensagem

Multiple Commits - Poder Real

bash
# 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ência

Exemplo Prático - Backport de Feature:

bash
# 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 release

Resoluçã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:

bash
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:

bash
# Edita arquivos conflitantes vim src/payment.js # Resolve conflitos manualmente git add src/payment.js git cherry-pick --continue

2. Estratégias Automáticas:

bash
# 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 branch

3. Cherry-Pick com Merge Tool:

bash
# 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ção

Conflitos em Série - O Desafio Real

bash
# 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 processo

Script de Automação para Conflitos Previsíveis:

bash
#!/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 done

Técnicas Avançadas: A Maestria

Cherry-Pick Reverso - Desfazendo Aplicações

bash
# 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 original

Cherry-Pick com Modificações

bash
# 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:

bash
# 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 parent

Cherry-Pick com Preservação de Merge

bash
# 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órico

Workflows Profissionais com Cherry-Pick

1. Hotfix Multi-Versão

Cenário: Empresa mantém 3 versões em produção, bug crítico descoberto.

bash
#!/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 done

2. Feature Backport Seletivo

bash
# 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 Facebook

3. Release Preparation Workflow

bash
# 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 aprovadas

4. Dependency Update Selective Sync

bash
# 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 changes

Automação e Scripting Avançado

Script de Cherry-Pick Inteligente

bash
#!/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

bash
#!/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:

bash
# 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 --skip

2. Dependências Não Satisfeitas:

bash
# 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 ordem

3. Conflitos Recorrentes:

bash
# 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 similares

Recovery de Cherry-Pick Problemático

bash
# 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

bash
# 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 true

Batch Cherry-Pick Otimizado

bash
#!/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

bash
# 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

bash
# 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ção

3. Client-Specific Customization

bash
# 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" done

Monitoramento e Auditoria

Tracking Cherry-Picks

bash
# 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

bash
#!/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.


Receba novos artigos

Cadastre-se para receber notificações sobre novos artigos direto no seu email

Não enviaremos spam. Você pode cancelar a inscrição a qualquer momento.