Puxe todos os commits de um branch, envie os commits especificados para outro

102

Tenho os seguintes branches:

  • master
  • production

e as seguintes filiais remotas:

  • origin/master
  • origin/production

Eu tenho um script que busca o origin/masterbranch e obtém a diferença do que mudou em meu último fetch ( log -p master..origin/master). Então eu mesclo origin/master.

Os commits encontrados são enviados para uma ferramenta de revisão de código.

Eu quero enviar os commits bem-sucedidos - e somente eles - para o ramo de produção e, é claro, para origin/production.

Como posso fazer isso?

Além disso, tenho 2 scripts em execução: o que busca origin/master, envia os detalhes dos commits para um banco de dados e mescla, e o outro que estou escrevendo no momento, que terá que enviar os commits bem-sucedidos.

Eu gostaria de ter esses 2 scripts em execução, evitando condições de corrida / conflito de fusão. Já que eu só quero trabalhar com commits especificados, talvez haja uma maneira de me livrar dos commits que eu não quero?

Sylvain
fonte
O que você quer dizer com 'commits bem-sucedidos'?
bdonlan
aquele que foi revisado e marcado como bem-sucedido. realmente não importa aqui, o importante é que há commits que eu quero manter e enviar para outro branch, e outros que quero me livrar / ignorar.
Sylvain

Respostas:

313

O termo que acho que você está procurando é uma 'escolha certa'. Ou seja, pegue um único commit do meio de um branch e adicione-o a outro:

A-----B------C
 \
  \
   D

torna-se

A-----B------C
 \
  \
   D-----C'

Isso, é claro, pode ser feito com o comando git cherry-pick.

O problema com esse commit é que o git considera os commits para incluir todo o histórico antes deles - assim, se você tiver três commits como este:

A-----B-----C

E para tentar se livrar de B, você deve criar um commit totalmente novo como:

A-----------C'

Onde C 'tem um SHA-1 ID diferente. Da mesma forma, escolher aleatoriamente um commit de um branch para outro envolve basicamente gerar um patch e, em seguida, aplicá-lo, perdendo história dessa forma também.

Esta mudança de IDs de confirmação quebra a funcionalidade de fusão do git entre outras coisas (embora se usado com moderação, existem heurísticas que irão encobrir isso). Mais importante, porém, ele ignora dependências funcionais - se C realmente usou uma função definida em B, você nunca saberá.

Talvez a melhor maneira de lidar com isso seja ter galhos com grãos mais finos. Ou seja, em vez de apenas ter um 'mestre', tenha 'featureA', 'bugfixB', etc. Execute a revisão de código em um branch inteiro de cada vez - onde cada branch está muito focado em fazer apenas uma coisa - e então mescle isso um ramo quando estiver pronto. Este é o fluxo de trabalho para o qual o git foi projetado e no que ele é bom :)

Se você insiste em lidar com as coisas no nível dos patches, você pode querer dar uma olhada no darcs - ele considera um repositório como um conjunto de patches e, portanto, a escolha seletiva torna-se a operação fundamental. No entanto, isso tem seu próprio conjunto de problemas, como ser muito lento :)

Edit: Além disso, não tenho certeza se entendi sua segunda pergunta, sobre os dois scripts. Talvez você possa descrevê-lo com mais detalhes, possivelmente como uma pergunta separada para evitar que as coisas fiquem confusas.

bdonlan
fonte
Sobre a minha segunda pergunta, eu só quero ter certeza de que os processos de busca de alterações (1º script) e envio de commits fornecidos para outro local (2º script) podem funcionar sem conflito de condição de corrida / fusão, ao trabalhar com diferentes branches. Mas no final eu acho que isso não importa, já que eu poderia mesclar os 2 scripts em um para que os 2 scripts não funcionassem simultaneamente :)
Sylvain
9
"Essa mudança de IDs de confirmação quebra a funcionalidade de fusão do git entre outras coisas" @bdonlan, explique como a funcionalidade de fusão é travada. O que isso significa?
Narek
5
@Narek Ele provavelmente quer dizer que as mudanças no commit C 'irão colidir com as mesmas mudanças no commit C quando você mesclar o segundo branch. Essa é a consequência de perder história por trás do commit C.
bytefu
1
"E tente se livrar de B" - por que você está tentando se livrar de B?
d512
3
@ user1334007, ele quer dizer que antes costumava ser ABC. Agora, devido à sua escolha certa de C, seu ramo é AD-C ', que não contém mais' B '.
AnneTheAgile,
1

Sei que essa é uma questão antiga, mas é referenciada aqui: Como mesclar um commit específico no Git

Conseqüentemente, uma resposta mais recente: Use branches de recursos e solicitações de pull.

O que parece, onde fA é um commit com o recurso A e fB é um commit com o recurso B:

            fA   fC (bad commit, don't merge)
           /  \ /
master ----A----B----C
                \  /
                 fB

As solicitações pull são associadas à funcionalidade do GitHub, mas, na verdade, tudo o que quero dizer é que alguém tem a responsabilidade de mesclar os branches de recursos no master.

MattJenko
fonte