Como mover certos commits para serem baseados em outro branch no git?

381

A situação:

  • mestre está em X
  • quickfix1 está em X + 2 confirma

De tal modo que:

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)

Então comecei a trabalhar no quickfix2, mas, por acidente, tomei o quickfix1 como o ramo de origem para copiar, não o mestre. Agora o quickfix2 está em X + 2 confirma + 2 confirmações relevantes.

o-o-X (master HEAD)
     \
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

Agora eu quero ter uma ramificação com o quickfix2, mas sem os 2 commits que pertencem ao quickfix1.

      q2a'--q2b' (quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

Tentei criar um patch a partir de uma determinada revisão no quickfix2, mas o patch não preserva o histórico de confirmação. Existe uma maneira de salvar meu histórico de consolidação, mas ter uma ramificação sem alterações no quickfix1?

Alex Yarmula
fonte
8
@ Kevin Essa pergunta apenas pergunta sobre a mudança de commits de um ramo para outro, este tem o requisito adicional de não incluir os commits quickfix1. (Observe também a diferença nas respostas.) #
558 Scott Weldon

Respostas:

372

Este é um caso clássico de rebase --onto:

 # let's go to current master (X, where quickfix2 should begin)
 git checkout master

 # replay every commit *after* quickfix1 up to quickfix2 HEAD.
 git rebase --onto master quickfix1 quickfix2 

Então você deve ir de

o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)
              \
               q2a--q2b (quickfix2 HEAD)

para:

      q2a'--q2b' (new quickfix2 HEAD)
     /
o-o-X (master HEAD)
     \ 
      q1a--q1b (quickfix1 HEAD)

É melhor fazer isso em uma árvore de trabalho limpa.
Vejogit config --global rebase.autostash true , especialmente depois do Git 2.10 .

VonC
fonte
24
Lembre-se de que essas etapas modificarão o histórico do quickfix2; portanto, se você já compartilhou a ramificação, use a seleção de cereja (consulte as respostas a seguir).
precisa saber é o seguinte
Apenas para os registros: com log basta arrastar do SmartGit q2aOnto Xe selecione Rebase 2 commits a partir das opções do diálogo ocorrendo.
Thomas S.
11
@ThomasS. Interessante. Essa é uma boa implementação de GUI de a git rebase --onto.
VonC 27/07/2015
11
Eu tenho que admitir, eu faço coisas tolas como me comprometer com a ramificação errada com mais frequência do que realmente deveria, a GUI da exibição de log do SmartGit me salvou tantas vezes com a mesma situação.
WORMSS
11
@Cosine concordou. Eu editei minha resposta para adicionar a referência à rebase.autostashconfiguração: isso evitará qualquer perda de trabalho em andamento na árvore de trabalho ao fazer uma nova refazer.
VonC
155

Você pode usar git cherry-pickapenas escolher o commit que deseja copiar.

Provavelmente, a melhor maneira é criar a ramificação fora do mestre e, nessa ramificação, use git cherry-pickas 2 confirmações do quickfix2 que você deseja.

DJ.
fonte
Essa também é a melhor opção se você deseja mover apenas um commit. Obrigado.
Alex
142

A coisa mais simples que você pode fazer é escolher uma variedade. Faz o mesmo que o, rebase --ontomas é mais fácil para os olhos :)

git cherry-pick quickfix1..quickfix2
Christoph
fonte
6
Além disso, ele não perde as confirmações originais, IIUC, então parece preferível para "jogar com segurança" como eu;) ou rebase --ontotambém preserva as alterações originais?
akavel
6
ambos rebasee cherry-pickfornecer novas chaves SHA. Isso ocorre porque cada confirmação é um instantâneo exclusivo do repositório.
Christoph
6
O que @akavel quis dizer é que cherry-pick irá manter os commits originais em seu ramo que é verdade
Mr_and_Mrs_D
4
Por tudo o que vale a pena, tentei cherry-pickum intervalo como nesta resposta e confundiu meu repo. Eu tive que fazer cherry-picks individuais para cada confirmação. (E talvez ele vai sem dizer, mas no caso de alguém está lutando, você tem que cherry-pickna ordem cronológica que seus commits foram aplicadas.)
carmenism
3
git checkouté crucial aqui. qual é a sua cabeça :)?
Sławomir Lenart
28

Eu acredito que é:

git checkout master
git checkout -b good_quickfix2
git cherry-pick quickfix2^
git cherry-pick quickfix2
Matthew Flaschen
fonte
3
cherry-pickfunciona com hashes de commit, portanto, se você quiser pegar um commit de algum lugar e colocá-lo em outro lugar, este é o caminho a seguir. Apenas certifique-se de fazer o checkout <branch>ramo correto primeiro.
John Leidegren
-1
// on your branch that holds the commit you want to pass
$ git log
// copy the commit hash found
$ git checkout [branch that will copy the commit]
$ git reset --hard [hash of the commit you want to copy from the other branch]
// remove the [brackets]

Outros comandos mais úteis aqui com explicação: Guia Git

Gopher
fonte