Cherry-pick: copiando commits específicos

1. Introdução ao Cherry-pick

O comando git cherry-pick é uma ferramenta poderosa que permite copiar commits específicos de um ponto do histórico para outro. Diferente do merge (que une branches inteiras) e do rebase (que reaplica uma sequência de commits), o cherry-pick trabalha com commits individuais, selecionando exatamente aqueles que você deseja transportar.

A principal diferença entre essas operações:
- Merge: Combina duas branches, trazendo todo o histórico de uma para outra
- Rebase: Reaplica commits de uma branch sobre outra, reescrevendo o histórico
- Cherry-pick: Copia commits específicos, ignorando o restante do histórico

Cenários típicos de uso incluem:
- Aplicar um hotfix de correção crítica da branch de desenvolvimento para a branch de produção
- Portar uma funcionalidade específica de uma branch experimental para a branch principal
- Recuperar um commit perdido ou removido acidentalmente

2. Comando Básico: git cherry-pick

A sintaxe fundamental é simples:

git cherry-pick <commit-hash>

Este comando pega as alterações do commit especificado e as aplica como um novo commit na branch atual. O novo commit terá um hash diferente, mas conterá exatamente as mesmas alterações.

Exemplo prático

Suponha que você tenha a seguinte situação:

Branch main:    A---B---C---D
Branch hotfix:  E---F (commit F contém a correção)

Para aplicar o commit F na branch main:

git checkout main
git cherry-pick F

Resultado:

Branch main:    A---B---C---D---F'
Branch hotfix:  E---F

O commit F' é uma cópia do commit F, aplicada sobre o estado atual da branch main.

3. Cherry-pick de Múltiplos Commits

Você pode copiar vários commits de uma só vez usando diferentes abordagens.

Faixa de commits

Para copiar todos os commits entre dois pontos:

git cherry-pick A..B

Isso copia todos os commits após A até B (excluindo A). Para incluir A também, use:

git cherry-pick A^..B

Commits específicos

Para copiar commits específicos em ordem:

git cherry-pick C D E

A ordem importa: os commits serão aplicados na sequência em que você os listar. Se você listar E antes de C, o Git tentará aplicar E primeiro, o que pode causar conflitos se E depender de alterações de C.

Diferença entre intervalo fechado e aberto

  • A..B: intervalo aberto (exclui A, inclui B)
  • A^..B: intervalo fechado (inclui A e B)
  • A...B: intervalo simétrico (commits que estão em uma branch ou outra, mas não em ambas)

4. Opções Essenciais do Cherry-pick

-n ou --no-commit

Aplica as alterações sem criar automaticamente um commit. Útil para revisar ou modificar as mudanças antes de commitá-las:

git cherry-pick -n <commit>
git add .
git commit -m "Mensagem personalizada"

-x

Adiciona uma referência ao commit original na mensagem do commit copiado:

git cherry-pick -x <commit>

A mensagem do novo commit incluirá algo como:

(cherry picked from commit abc123def456...)

Essa opção é especialmente útil para rastreabilidade em projetos colaborativos.

-e ou --edit

Permite editar a mensagem do commit antes de finalizar:

git cherry-pick -e <commit>

O editor padrão será aberto para que você modifique a mensagem.

5. Gerenciando Conflitos no Cherry-pick

Conflitos ocorrem quando as alterações do commit copiado não se aplicam suavemente ao estado atual da branch. Isso é comum quando:
- O código foi modificado em ambas as branches
- Dependências do commit original não existem na branch de destino

Identificando conflitos

Quando um conflito ocorre, o Git interrompe o processo e você pode usar:

git status
git diff

O git status mostrará os arquivos com conflitos (marcados como "both modified"), enquanto git diff exibirá as diferenças detalhadas.

Resolvendo conflitos

  1. Edite os arquivos conflitantes manualmente
  2. Remova os marcadores de conflito (<<<<<<<, =======, >>>>>>>)
  3. Adicione as alterações resolvidas:
git add <arquivo-resolvido>
  1. Continue o processo:
git cherry-pick --continue

6. Desfazendo um Cherry-pick

Abortando o processo

Se você encontrar problemas durante o cherry-pick e quiser desistir completamente:

git cherry-pick --abort

Isso retorna a branch ao estado anterior ao início do cherry-pick.

Pulando um commit problemático

Se você estiver aplicando múltiplos commits e um deles causar problemas:

git cherry-pick --skip

Isso pula o commit atual e continua com o próximo.

Revertendo um cherry-pick concluído

Se o cherry-pick já foi concluído e você precisa desfazê-lo:

git revert <hash-do-novo-commit>

O git revert cria um novo commit que desfaz as alterações, preservando o histórico.

7. Cherry-pick entre Repositórios

É possível copiar commits de repositórios diferentes, não apenas de branches no mesmo repositório.

Adicionando um repositório remoto

git remote add outro-repo https://github.com/usuario/repositorio.git

Buscando commits

git fetch outro-repo

Aplicando commits

git cherry-pick outro-repo/main~3..outro-repo/main

Isso copia os últimos 3 commits do branch main do repositório remoto para sua branch atual.

8. Boas Práticas e Armadilhas Comuns

Evite cherry-pick em histórico compartilhado sem necessidade

O cherry-pick cria commits duplicados, o que pode causar confusão no histórico. Use com moderação em branches compartilhadas.

Cuidado com duplicação de commits

Se você fizer cherry-pick de um commit que já existe em outra branch, pode criar conflitos futuros quando tentar fazer merge entre as branches.

Quando preferir rebase ou merge

  • Use merge quando quiser unir branches inteiras com todo o histórico
  • Use rebase quando quiser reaplicar uma sequência linear de commits
  • Use cherry-pick apenas para commits específicos e isolados

Dicas práticas

  • Sempre verifique o hash do commit antes de aplicar
  • Use -x para manter rastreabilidade
  • Teste as alterações após o cherry-pick
  • Documente o motivo do cherry-pick na mensagem do commit

Referências