O que é Git Cherry-Pick?
Uma correção crítica acabou de chegar à sua branch de desenvolvimento -- mas o mesmo bug está em produção. Você não pode fazer merge de toda a branch de desenvolvimento na branch de release, porque ela está cheia de funcionalidades pela metade. O que você realmente precisa é pegar aquele commit específico e aplicá-lo em outro lugar. É exatamente isso que o git cherry-pick faz.
O cherry-pick pega as mudanças introduzidas por um commit existente e as reproduz na sua branch atual como um commit totalmente novo. O novo commit contém o mesmo diff e, por padrão, a mesma mensagem, mas tem um pai diferente e, portanto, um SHA diferente. Esse detalhe importa mais do que parece: o Git identifica commits pelo SHA, então depois de um cherry-pick seu repositório contém dois commits distintos que introduzem a mesma mudança. Guarde isso -- explica tanto por que o cherry-pick é tão útil quanto por que o uso excessivo causa dores de cabeça mais tarde.
Quando o cherry-pick é a ferramenta certa
Retroportar um hotfix para uma branch de release
É o caso clássico. Você corrigiu um bug na main, mas seus usuários estão na versão 2.3 e precisam da correção agora. Faça cherry-pick da correção na branch de release:
git switch release/2.3
git cherry-pick a1b2c3d
A branch de release recebe exatamente aquela correção, e nada mais da main vem junto de carona.
Um commit caiu na branch errada
Você queria fazer commit na sua branch de feature, mas estava na main. O cherry-pick oferece uma recuperação limpa: mude para a branch onde o commit deveria estar, faça o cherry-pick lá, depois volte e remova-o da branch onde ele não pertence. Se a etapa de remoção gera dúvidas, nosso guia sobre como desfazer um commit no Git cobre cada opção em detalhe.
Resgatar uma correção de uma branch abandonada
Às vezes um experimento não dá em nada, mas um commit no meio da branch corrigia um bug de verdade. Em vez de fazer merge de uma branch sem futuro, faça cherry-pick do único commit valioso para a sua branch ativa e deixe o resto do experimento ser apagado em paz.
Uso básico
A forma mais simples recebe um único commit:
git cherry-pick a1b2c3d
O Git aplica as mudanças daquele commit e cria imediatamente um novo commit na sua branch atual, reutilizando a mensagem original. Você também pode passar vários commits de uma vez, e o Git os aplica um a um, na ordem em que você os lista:
git cherry-pick a1b2c3d f4e5d6c
Opções práticas que você deveria conhecer
-x: registrar de onde o commit veio
Ao retroportar, mais tarde você vai querer saber de onde um commit se originou. A opção -x acrescenta uma linha como (cherry picked from commit a1b2c3d...) à mensagem do novo commit:
git cherry-pick -x a1b2c3d
Transforme isso em hábito para qualquer cherry-pick entre branches públicas de longa vida. Daqui a seis meses, essa única linha dirá na hora se uma correção chegou a uma release e de onde veio.
Pegar um intervalo de commits
Você pode fazer cherry-pick de um intervalo inteiro com a sintaxe de dois pontos:
git cherry-pick A..B
Cuidado: isso aplica os commits depois de A, até B inclusive. O próprio A fica de fora. Se você quer incluir A, escreva:
git cherry-pick A^..B
O ^ significa "o pai de A", o que coloca A de volta dentro do intervalo. Confundir essas duas sintaxes é um dos erros mais comuns com cherry-pick.
--no-commit: aplicar sem fazer commit
Às vezes você quer as mudanças, mas não um commit automático -- por exemplo, para combinar vários commits colhidos em um só, ou para ajustar o resultado antes do commit:
git cherry-pick --no-commit a1b2c3d
As mudanças chegam ao seu diretório de trabalho e à área de staging, e você cria o commit por conta própria quando estiver pronto.
Lidando com conflitos durante um cherry-pick
Um cherry-pick pode gerar conflitos pela mesma razão que um merge: o commit que você está pegando foi escrito sobre um código diferente do da sua branch atual. Quando isso acontece, o Git para no meio da operação e marca os arquivos em conflito:
error: could not apply a1b2c3d... fix login timeout
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue"
Agora você tem três saídas:
git cherry-pick --continue-- depois de editar os arquivos em conflito e adicioná-los ao staging comgit add, isso conclui o cherry-pick e cria o commit.git cherry-pick --abort-- cancela toda a operação e devolve sua branch ao estado exato em que estava antes de começar. Nada se perde, nada é aplicado.git cherry-pick --skip-- ao pegar vários commits, pula o atual e segue para o próximo. Útil quando um commit do intervalo se revela já aplicado ou irrelevante.
Resolver os conflitos em si funciona exatamente como resolver um conflito de merge: abra cada arquivo em conflito, escolha entre os hunks concorrentes (ou combine-os), remova os marcadores de conflito e adicione o arquivo ao staging. Se os marcadores de conflito ainda intimidam, nosso passo a passo sobre resolver conflitos de merge do Git visualmente também vale para cherry-picks.
O que NÃO fazer com cherry-pick
Não faça cherry-pick de branches inteiras
Se você se pegar fazendo cherry-pick de cinco, dez, vinte commits de uma branch para outra, pare. É para isso que existem merge e rebase. Ambos movem trabalho entre branches deixando o Git entender a relação entre elas, o que mantém as operações futuras simples e sem conflitos. Se você não sabe qual dos dois encaixa no seu fluxo de trabalho, nossa comparação de rebase vs merge percorre os prós e contras.
Histórico duplicado cobra a conta depois
Lembre-se: um cherry-pick cria um commit novo com um SHA novo, e o Git não guarda nenhum registro formal de que os dois commits representam "a mesma mudança". Se você faz cherry-pick de commits de uma branch de feature para a main e depois faz merge daquela branch mesmo assim, o Git precisa reconciliar duas cópias das mesmas mudanças. Muitas vezes ele consegue em silêncio. Mas assim que qualquer uma das cópias foi modificada depois, surgem conflitos confusos em que os dois lados parecem quase idênticos -- e seu histórico mostra a mesma mudança duas vezes, com duas datas e dois SHA, o que dificulta o uso de ferramentas como git log e git bisect.
Uma boa regra prática: cherry-pick serve para mover exceções -- um hotfix, um commit fora do lugar, uma correção resgatada. No momento em que ele vira sua forma rotineira de mover trabalho entre branches, seu histórico está dizendo que a estratégia de branches precisa ser repensada.
Cherry-pick no GitSquid
No GitSquid, o cherry-pick está onde você esperaria: clique com o botão direito em qualquer commit no grafo de commits e escolha a opção cherry-pick no menu de contexto. Sem copiar SHA de um lado para o outro entre um log e um terminal.
O ganho maior é saber no que você está se metendo. O Conflict Predictor do GitSquid -- gratuito para todos -- mostra exatamente quais arquivos entrarão em conflito antes de você executar um merge, rebase ou cherry-pick, com prévias dos hunks e realce de sintaxe. Em vez de descobrir conflitos no meio de uma operação, você os vê de antemão e pode decidir se prossegue, escolhe outro commit ou prepara a resolução com calma.
E quando um cherry-pick de fato entra em conflito, o "Resolve in scratch worktree" abre um worktree temporário como uma nova aba, para que você resolva tudo lá enquanto seu checkout ativo permanece intocado.
Referência rápida
| Comando | O que faz |
|---|---|
git cherry-pick <sha> |
Aplica um commit na branch atual |
git cherry-pick <sha1> <sha2> |
Aplica vários commits, em ordem |
git cherry-pick -x <sha> |
Acrescenta o SHA de origem à mensagem do commit |
git cherry-pick A..B |
Pega os commits depois de A até B (A excluído) |
git cherry-pick A^..B |
Pega o intervalo incluindo A |
git cherry-pick --no-commit <sha> |
Aplica as mudanças sem fazer commit |
git cherry-pick --continue |
Conclui o pick após resolver os conflitos |
git cherry-pick --abort |
Cancela e restaura a branch como estava |
git cherry-pick --skip |
Pula o commit atual, continua com o resto |
O cherry-pick é um bisturi, não uma pá. Usado para a extração precisa e ocasional -- o retroporte de um hotfix, um commit fora do lugar, uma correção resgatada -- é um dos comandos mais satisfatórios do Git. Usado como substituto do merge, ele enche silenciosamente seu histórico de duplicatas que voltam para assombrar você. Conheça a diferença, adicione -x ao retroportar e mantenha o --abort em mente como saída de emergência.
Quer ver quais arquivos entrarão em conflito antes mesmo de começar? Baixe o GitSquid grátis e deixe o Conflict Predictor tirar a adivinhação do seu próximo cherry-pick.