Como copiar confirmações de uma ramificação para outra?

728

Eu tenho dois ramos do meu mestre:

  • v2.1 : (versão 2) Estou trabalhando há vários meses
  • wss : que eu criei ontem para adicionar um recurso específico ao meu mestre (em produção)

Existe uma maneira de copiar confirmações de ontem do wss para a v2.1?

Bob Walsh
fonte
Simplesmente copiar commits (ou um intervalo de commits) de um galho para outro esta resposta ajudou-me melhor: stackoverflow.com/questions/1994463/...
caramba

Respostas:

566

Você realmente deve ter um fluxo de trabalho que permita fazer tudo isso mesclando:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (wss)

Então tudo que você precisa fazer é git checkout v2.1e git merge wss. Se, por algum motivo, você realmente não puder fazer isso e não puder usar o git rebase para mover seu ramo wss para o lugar certo, o comando para pegar um único commit de algum lugar e aplicá-lo em outro lugar é git cherry-pick . Basta verificar o ramo em que você deseja aplicá-lo e executar git cherry-pick <SHA of commit to cherry-pick>.

Algumas das maneiras pelas quais a rebase pode salvá-lo:

Se o seu histórico for assim:

- x - x - x (v2) - x - x - x (v2.1)
           \
            x - x - x (v2-only) - x - x - x (wss)

Você pode usar git rebase --onto v2 v2-only wsspara mover o wss diretamente na v2:

- x - x - x (v2) - x - x - x (v2.1)
          |\
          |  x - x - x (v2-only)
           \
             x - x - x (wss)

Então você pode mesclar! Se você realmente, realmente, realmente não consegue chegar ao ponto em que pode mesclar, ainda pode usar o rebase para efetivamente fazer várias escolhas de uma só vez:

# wss-starting-point is the SHA1/branch immediately before the first commit to rebase
git branch wss-to-rebase wss
git rebase --onto v2.1 wss-starting-point wss-to-rebase
git checkout v2.1
git merge wss-to-rebase

Nota: a razão pela qual é necessário algum trabalho extra para fazer isso é que ele está criando confirmações duplicadas no seu repositório. Isso não é realmente uma coisa boa - o objetivo de facilitar a ramificação e a fusão é poder fazer tudo, tornando o commit (s) em um só lugar e fundindo-o onde for necessário. Confirmações duplicadas significam uma intenção de nunca mesclar essas duas ramificações (se você decidir que deseja mais tarde, terá conflitos).

Cascabel
fonte
1
Não foi possível concordar mais com esta resposta. +1. Veja também minha antiga resposta para ilustrar as conseqüências da escolha da cereja: stackoverflow.com/questions/881092/…
VonC
18
Excelente resposta sobre como fazer isso da maneira correta ! Eu gostaria de poder votar duas vezes pelo esforço de criar diagramas ASCII também.
gotgenes 19/03/10
@VonC: Obrigado pelo apoio e pelas informações extras sobre por que não escolher - eu sei que passei um pouco lá. @gotgenes: Obrigado! Eu acho que vale totalmente a pena o esforço - basta olhar para a página de manual do git-rebase. Não há melhor maneira de explicar isso.
Cascabel
Por que você pode não conseguir mesclar - a fusão do Git não funciona bem com o git-svn. Para copiar uma série de confirmações de uma ramificação SVN para outra, acabei escolhendo-as e realizando uma reformulação / reformulação interativa para remover as git-svn-idreferências incorretas antes de dcommiting novamente. Embora eu provavelmente pudesse ter deixado de fora a etapa de escolha da cereja e usado apenas uma rebase sozinha.
Bob
1
Aqui está o meu caso de uso: correções críticas de erros foram confirmadas na ramificação do recurso. Eu preciso no master para entrar em produção agora. Isso vai salvar minha bunda.
Captain Hypertext
910

Usar

git cherry-pick <commit>

para aplicar <commit>à sua filial atual .

Eu próprio provavelmente verificaria as confirmações que selecionei gitke as selecionaria com cliques com o botão direito na entrada de confirmação lá.


Se você quiser ser mais automático (com todos os seus perigos) e assumindo que todos os commits desde ontem ocorreram no wss, você poderá gerar a lista de commits usando git log( --prettysugerido por Jefromi)

git log --reverse --since=yesterday --pretty=%H

então tudo junto assumindo que você usa bash

for commit in $(git log --reverse --since=yesterday --pretty=%H);
do
    git cherry-pick $commit
done

Se algo der errado aqui (há muito potencial), você está com problemas, pois isso funciona no checkout ao vivo, então faça escolhas manuais manuais ou use rebase como sugerido por Jefromi.

Benjamin Bannier
fonte
Todos os espaços reservados para a opção --pretty estão na página de manual do git-log. Você pode obter qualquer formato que desejar - particularmente útil para obter os campos desejados para um script em um formato facilmente analisável.
Cascabel
Também gostaria de salientar que, supondo que você realmente queira criar confirmações duplicadas, o método usado git rebasena minha resposta é mais robusto. Em particular, usando um loop for como este, se uma das opções de cereja falhar, ela ainda tentará fazer todo o resto. Isso é ... muito, muito ruim, digamos.
Cascabel
2
Acordado. É por isso que nunca o uso, mas faço manualmente. Mas escolher a cereja ainda é a resposta, pelo menos para o título da pergunta. Eu modifiquei a resposta.
Benjamin Bannier
1
Alguém comprometido com uma ramificação antiga / incorreta, e escolher a cereja, deixe-me colocar essa confirmação na ramificação correta (enquanto ainda a mantenho como committer). Perfeito.
Patrick
8
Uma visão rara, uma gitresposta que é simples e direta para a solução, em vez de vagar pelos meandros do git para provar o quão bem o respondente sabe disso.
Przemek D
74

git cherry-pick : Aplique as alterações introduzidas por algumas confirmações existentes

Suponha que temos o ramo A com confirmações (X, Y, Z). Precisamos adicionar estes commit ramo B . Nós vamos usar as cherry-pickoperações.

Quando usamos cherry-pick, devemos acrescentar commits no ramo B na mesma ordem cronológica que os commits aparecer na Filial A .

cherry-pick suporta uma variedade de confirmações, mas se você tiver mesclagens confirmadas nesse intervalo, fica realmente complicado

git checkout B
git cherry-pick SHA-COMMIT-X
git cherry-pick SHA-COMMIT-Y
git cherry-pick SHA-COMMIT-Z

Exemplo de fluxo de trabalho:

insira a descrição da imagem aqui

Podemos usar cherry-pickcom opções

-e ou --edit : Com esta opção, o git cherry-pick permite editar a mensagem de confirmação antes de confirmar.

-n ou --no-commit : Normalmente, o comando cria automaticamente uma sequência de confirmações. Esse sinalizador aplica as alterações necessárias para escolher cada commit nomeado com cereja na sua árvore de trabalho e no índice, sem fazer nenhum commit. Além disso, quando essa opção é usada, seu índice não precisa corresponder à confirmação HEAD. A escolha da cereja é feita no estado inicial do seu índice.

Aqui um artigo interessante sobre cherry-pick.

Lyes CHIOUKH
fonte
19

Você pode criar um patch a partir das confirmações que deseja copiar e aplicar o patch à ramificação de destino.

Charles Ma
fonte
16
Mesmo se você, por algum motivo, realmente quiser usar patch (s) em vez de cherry-pick (s) / rebase, a maneira direta de fazer isso é com git format-patch <revision range>e git am *.patch.
Cascabel
Requer checkoutpara outro ramo.
CoolMind
12

Ou, se você está um pouco menos do lado do evangelista, pode fazer um pouco da maneira feia que estou usando. Em deploy_template, há confirmações que quero copiar no meu mestre como filial deploy

git branch deploy deploy_template
git checkout deploy
git rebase master

Isso criará uma nova implantação de ramificação (eu uso -f para substituir a ramificação de implantação existente) em deploy_template, depois rebase essa nova ramificação para master, deixando deploy_template intocado.

Petr Sykora
fonte
1

Para o simples caso de apenas copiar o último commit do branch wss para a v2.1, você pode simplesmente pegar o id do commit ( git log --oneline | head -n 1) e fazer:

git checkout v2.1
git merge <commit>
zeroimpl
fonte
Isso requer check-out para outro ramo.
CoolMind 22/05/19
1

O comando cherry-pick pode ler a lista de confirmações da entrada padrão.

O comando a seguir cherry-picks confirma a criação do usuário John, que existe na ramificação "develop", mas não na ramificação "release", e faz isso na ordem cronológica.

git log develop --not release --format=%H --reverse --author John | git cherry-pick --stdin
Gebb
fonte