O que significa escolher um commit com Git?

2340

Recentemente, fui convidado para cherry-pickum commit.

Então, o que significa escolher um commit no git? Como você faz isso?

Rahul
fonte
13
Em vez de mesclar, é mais fácil com a confirmação da seleção de uma ramificação para a ramificação de destino (ex: master).
Levent Divilioglu

Respostas:

2859

A escolha de cereja no Git significa escolher um commit de um ramo e aplicá-lo em outro.

Isso contrasta com outras formas como mergee rebaseque normalmente aplicam muitos commits em outro ramo.

  1. Verifique se você está no ramo ao qual deseja aplicar o commit.

    git checkout master
    
  2. Execute o seguinte:

    git cherry-pick <commit-hash>
    

NB:

  1. Se você escolher um ramo público, considere usar

    git cherry-pick -x <commit-hash>
    

    Isso irá gerar uma mensagem de confirmação padronizada. Dessa forma, você (e seus colegas de trabalho) ainda podem acompanhar a origem da confirmação e evitar conflitos de mesclagem no futuro.

  2. Se você tiver notas anexadas ao commit, elas não seguirão a opção de escolha. Para trazê-los também, você deve usar:

    git notes copy <from> <to>
    

Links adicionais:

Philip Fourie
fonte
247
Se você escolher um ramo público, considere usá-lo git cherry-pick -x <commit-hash>. Isso irá gerar uma mensagem de confirmação padronizada. Dessa forma, você (e seus colegas de trabalho) ainda podem acompanhar a origem da confirmação e evitar conflitos de mesclagem no futuro.
MBober
2
A colheita de cerejas é realmente necessária? Uma redefinição mista ou uma redefinição suave não fará um trabalho semelhante?
Nav
10
Observe que, se você tiver notas anexadas ao commit, elas não seguirão a opção de escolha. Você tem que usar git notes copy <from> <to>para trazê-los também.
Zitrax
5
git push é o último passo a tomar alterações no mestre
sensação boa e programação
58
FYI: um commit semanticamente contém todos os arquivos da árvore de trabalho daquele momento (e o hash cometer da submissão anterior), para que você não está aplicando um todo comprometer com outra cometer, mas as mudanças a cometer fez na anterior cometer "cherry-pick commit applies the changes introduced by the named commit on the current branch"maioria As pessoas tendem a pensar no commit como mudanças (como svn was iirc), mas não é, cada commit refere-se à árvore de trabalho completa. Embora isso não faça diferença neste caso, ele pode ajudar a entender por que o git funciona como ele.
Emile Vrijdags
314

Esta citação é retirada de; Controle de versão com Git (livro realmente bom, recomendo que você o compre se estiver interessado em git)

Edit: Como esta resposta ainda está sendo impressa, eu gostaria de adicionar um tutorial em vídeo muito bom sobre a ação:

Youtube: Introdução ao Git cherry-pick

Usando git cherry-pick O comando git cherry-pick commit aplica as alterações introduzidas pelo commit nomeado na ramificação atual. Ele apresentará um novo e distinto commit. A rigor, o uso do git cherry-pick não altera o histórico existente em um repositório; em vez disso, adiciona ao histórico. Como em outras operações do Git que introduzem alterações através do processo de aplicação de um diff, pode ser necessário resolver conflitos para aplicar completamente as alterações do commit fornecido . O comando git cherry-pick é normalmente usado para introduzir confirmações específicas de uma ramificação dentro de um repositório em uma ramificação diferente. Um uso comum é confirmar ou enviar porta a porta de uma ramificação de manutenção para uma ramificação de desenvolvimento.

$ git checkout rel_2.3
$ git cherry-pick dev~2 # commit F, above

antes: antes

depois de: depois de

Teoman shipahi
fonte
12
quando confirmações escolhidas a dedo são tomadas em alguma ramificação (b1) e posteriormente entregues ao mestre. E se a ramificação b1 (da qual as confirmações foram originalmente selecionadas) também tentar ser entregue ao mestre. E os conflitos? Isso foi resolvido ou como funciona?
parasrish
3
@parasrish Sim, eles já foram cuidados com suas fusões anteriores. Então você fez as alterações a, b, c, d do ramo (b1). Você cereja escolheu apenas "c". Então, no futuro, depois que você mesclar de (b1) para mestre, como as alterações "c" são as mesmas, ele somente mesclará a, b, d e permanecerá "c". Mas se você reverter sua mesclagem, retornará as alterações com "c". Você precisará revertê-los separadamente.
Teoman shipahi
12
Deve ser enfatizado: No exemplo dado, apenas a diferença (F - E) é aplicada a Z. Esse é um caso restrito. A seleção de cereja pode ser usada para aplicar as diferenças de várias confirmações, digamos, todas as diferenças entre duas confirmações não adjacentes. Por exemplo, seguindo acima, (F - E), (E - D), (D - C) e (C - B). Isso é equivalente a aplicar a diferença (F - B).
22617 Thomas Bitonti
2
Além disso, o que acontece se o Commit selecionado (F no exemplo) tiver mais de um predecessor imediato?
22617 Thomas Bitonti
2
@ j2emanue em outras palavras, cherry-pick só aceita alterações de last-commit. Se você confirmar três vezes diferentes e se escolher o último, não será necessário alterar as alterações na primeira e na segunda. O comando Mesclar fará com que todas as suas alterações sejam aplicadas ao seu ramo de destino (mestre).
Teoman shipahi
157

A escolha da cereja no Git foi projetada para aplicar alguns commit de um ramo em outro. Isso pode ser feito se você, por exemplo. cometeu um erro e cometeu uma alteração no ramo errado, mas não deseja mesclar o ramo inteiro. Você pode apenas por exemplo. reverta o commit e escolha-o em outro ramo.

Para usá-lo, você só precisa git cherry-pick hash, onde hashestá um hash de consolidação de outro ramo.

Para obter o procedimento completo, consulte: http://technosophos.com/2009/12/04/git-cherry-picking-move-small-code-patches-across-branches.html

Tadeck
fonte
96

Pequeno exemplo de situação, quando você precisa escolher uma cereja

Considere o seguinte cenário. Você tem dois ramos.

a) release1 - Esta filial está indo para o seu cliente, mas ainda existem alguns bugs a serem corrigidos.

b) master - ramificação master clássica, onde você pode, por exemplo, adicionar funcionalidade para o release2.

AGORA : Você corrige algo no release1 . Claro que você precisa dessa correção também no master . E esse é um caso de uso típico para a colheita de cerejas. Portanto, a escolha de cereja nesse cenário significa que você aceita um commit do branch release1 e o inclui no diretório ramo mestre .

Daniel Perník
fonte
3
Você pode precisar apenas do outro lado. Você corrigiu um bug no master e deve escolher isso para liberar1. Também eles podem ser repositórios em vez de ramos
canbax
1
Por que não usar mesclagem?
FreeLightman
Gostaria: criar ramificação fora do lançamento, corrigi-lo no ramo, mesclar ramo no lançamento, mesclar lançamento no mestre.
Jasper-M
57

cherry-pick é um recurso do Git. Se alguém desejar confirmar confirmações específicas em uma ramificação em uma ramificação de destino, será usada a seleção de cereja.
As etapas git cherry-pick são as seguintes.

  1. checkout (alternar para) ramo de destino.
  2. git cherry-pick <commit id>
    

    Aqui, o commit id é o ID da atividade de outro branch.Eg.

    git cherry-pick 9772dd546a3609b06f84b680340fb84c5463264f
    
  3. empurrar para o ramo alvo

Visite https://git-scm.com/docs/git-cherry-pick

Vijay SB
fonte
44

Eu preparei ilustrações passo a passo o que o cherry-pick faz - e uma animação dessas ilustrações (perto do fim).

  1. Antes de escolher a cereja
    (vamos fazer uma escolha cereja do commit a Lpartir da ramificação feature): insira a descrição da imagem aqui

  1. Iniciando o comando git cherry-pick feature~2
    ( feature~2é o commit antes
    feature, ou seja, o commit L): insira a descrição da imagem aqui

  1. Depois de executar o comando ( git cherry-pick feature~2): insira a descrição da imagem aqui

O mesmo animado: insira a descrição da imagem aqui


Nota:

A confirmação L'é do ponto de vista do usuário (confirmação = captura instantânea) a cópia exata da confirmaçãoL .

Tecnicamente (internamente), é um commit novo e diferente (porque, por exemplo, Lcontém um ponteiro para K(como pai), enquanto L'contém um ponteiro para E).

MarianD
fonte
Isso significa que L 'será N -> M -> L no mestre da filial? ou trará exclusivamente commit L no ramo principal
Priyank Thakkar
1
@PriyankThakkar, sim, exclusivamente L , nada mais (como você pode ver nas fotos / animação).
MarianD
22

Você pode pensar se uma escolha de cereja é semelhante a uma rebase, ou melhor, é gerenciada como uma rebase. Com isso, quero dizer que ele pega um commit existente e o regenera, assumindo, como ponto de partida, o chefe do branch em que você está atualmente.

A rebasepega uma confirmação que tinha um pai X e regenera a confirmação como se realmente tivesse um pai Y, e é exatamente isso que a cherry-pickfaz.

A escolha da cereja é mais sobre como você seleciona os commits. Com pull(rebase), o git regenera implicitamente seus commits locais, além do que é puxado para sua ramificação, mas com cherry-pickvocê escolhe explicitamente alguns commit (s) e os regenera implicitamente (eles) sobre seu branch atual.

Portanto, a maneira como você faz isso é diferente, mas sob o capô são operações muito semelhantes - a regeneração de confirmações.

Hugh
fonte
1
Acho que essa é uma visão bastante útil das coisas. Isso implica por que cherry-pickse comporta da mesma maneira quando o ramo de destino é posteriormente mesclado de volta ao ramo de origem. Obrigado senhor.
Aluan Haddad
3
eu gostaria de usar cherry pick em vez de git merge após a conclusão de um recurso. todos sempre git mesclam feature_branch quando concluem um recurso. por que não usar o comando cherry-pick? você tem alguma ideia por que se preocupar esmagando commits se eu posso cherry-pick?
j2emanue
11

É como copiar (de algum lugar) e colar (para algum lugar), mas para confirmações específicas.

Se você deseja fazer uma correção, por exemplo, pode usar o cherry-pickrecurso.

Faça isso cherry-pickem um ramo de desenvolvimento e mergeque se comprometa com um ramo de lançamento. Da mesma forma, faça a cherry-pickpartir de uma ramificação de liberação para dominar. Voila

Ajeet Sharma
fonte
11

Quando você está trabalhando com uma equipe de desenvolvedores em um projeto, gerenciar as alterações entre vários ramos git pode se tornar uma tarefa complexa. Às vezes, você não deseja mesclar uma ramificação inteira em outra e precisa escolher apenas uma ou duas confirmações específicas. Esse processo é chamado de 'colheita da cereja'.

Encontrei um ótimo artigo sobre a escolha da cereja, confira detalhes detalhados: https://www.previousnext.com.au/blog/intro-cherry-picking-git

Wolfack
fonte
7

Se você deseja mesclar sem confirmar os IDs, pode usar este comando

git cherry-pick master~2 master~0

O comando acima mesclará os últimos três commits do master de 1 a 3

Se você quiser fazer isso para o commit único, remova a última opção

git cherry-pick master~2

Dessa forma, você mesclará a terceira confirmação a partir do final do mestre.

Contas
fonte
Isso é confuso. Eu acho que aqui você está em um ramo que não é mestre, certo? E quando você mencionou dois commits, você está se referindo aos <from> e <to> commits para definir o intervalo que deseja escolher. Corrigir? Seria de grande ajuda se o cenário fosse descrito. Boa adição embora. Obrigado.
Saurabh Patil
6

Ele aplicará uma confirmação específica à sua ramificação atual.

Isso significa :

  • todos os arquivos adicionados por este commit serão adicionados
  • todos os arquivos excluídos por este commit serão excluídos
  • todos os arquivos modificados por esse commit serão mesclados. Isso significa todo o arquivo da confirmação, não apenas as alterações dessa confirmação!

Ex: considere comprometer A

added newFileA
modified main:
+ import './newFileA'

comprometer B

added newFileB
modified main:
+ import './newFileB'

Se você escolher o commit B em outro ramo, você terminará com:

/newFileB
/main :
   import './newFileA'
   import './newFileB'

como o commit B contém newFileB e main , mas nenhum newFileA , resultando em um bug, portanto, use com cuidado.

mandelf
fonte
0

Trecho dos documentos oficiais:

Dada uma ou mais confirmações existentes, aplique a alteração que cada uma introduz, registrando uma nova confirmação para cada uma. Isso requer que sua árvore de trabalho esteja limpa (nenhuma modificação do commit HEAD).

Quando não é óbvio como aplicar uma alteração, acontece o seguinte:

  1. A ramificação atual e o ponteiro HEAD permanecem na última confirmação efetuada com êxito.

  2. A referência CHERRY_PICK_HEAD está configurada para apontar para o commit que introduziu a alteração que é difícil de aplicar.

  3. Os caminhos nos quais as alterações aplicadas corretamente são atualizadas no arquivo de índice e na sua árvore de trabalho.

  4. Para caminhos conflitantes, o arquivo de índice registra até três versões, conforme descrito na seção "TRUE MERGE" do git-merge. Os arquivos da árvore de trabalho incluirão uma descrição do conflito entre colchetes pelos marcadores de conflito usuais <<<<<<< e >>>>>>>.

Nenhuma outra modificação é feita.

Consulte Mais informação...

Saikat
fonte