significado Mover a(s) confirmação(ões) mais recente(s) para uma nova ramificação com o Git
ver lista de branches git (8)
Eu gostaria de mover os últimos commits que eu cometi para masterizar em um novo branch e levar o master de volta para antes dos commits serem feitos. Infelizmente, meu Git-fu ainda não é forte o suficiente, alguma ajuda?
Ou seja, como eu posso ir disso
master A - B - C - D - E
para isso?
newbranch C - D - E
/
master A - B
https://code.i-harness.com
Em geral...
O método exposto pelo sykora é a melhor opção neste caso. Mas às vezes não é o mais fácil e não é um método geral. Para um método geral use git cherry-pick :
Para alcançar o que o OP quer, é um processo de duas etapas:
Passo 1 - Anote quais commits do master você quer em um newbranch
Executar
git checkout master
git log
Observe os hashes de (digamos 3) commits que você quer no newbranch
. Aqui vou usar:
C commit: 9aa1233
D commit: 453ac3d
E commit: 612ecb3
Nota: Você pode usar os primeiros sete caracteres ou todo o hash de confirmação
Passo 2 - Coloque-os no newbranch
git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233
OU (no Git 1.7.2+, use intervalos)
git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233
git cherry-pick aplica esses três commits para newbranch.
Solução muito mais simples usando o git stash
E se:
- Seu objetivo principal é reverter o
master
e - Você quer manter as alterações, mas não se importa particularmente com os commits individuais, e
- Você ainda não empurrou e
- Você quer que isso seja fácil e não complicado com ramos temporários e outras dores de cabeça
Então, o seguinte é muito mais simples (iniciando no branch master
que possui três commits errados):
git reset HEAD~3
git stash
git checkout newbranch
git stash pop
O que isto faz, por número de linha
- Desfaz os últimos três commits (e suas mensagens) para
master
, mas deixa todos os arquivos de trabalho intactos - Armazena todas as alterações do arquivo de trabalho, tornando a árvore de trabalho
master
igual ao estado HEAD ~ 3 - Muda para um branch
newbranch
existente - Aplica as alterações ocultas ao seu diretório de trabalho e limpa o estoque
Agora você pode usar git add
e git commit
como faria normalmente. Todos os novos commits serão adicionados ao newbranch
.
O que isso não faz
- Não deixa galhos temporários aleatórios bagunçando sua árvore
- Ele não preserva os commits e commit das mensagens, então você precisa adicionar uma nova mensagem de commit a este novo commit
Objetivos
O OP declarou que o objetivo era "levar o mestre de volta a antes que os commits fossem feitos" sem perder as alterações e essa solução faz isso.
Eu faço isso pelo menos uma vez por semana quando eu acidentalmente faço novos commits para master
ao invés de develop
. Normalmente eu tenho apenas um commit para rollback, em cujo caso usar o git reset HEAD^
na linha 1 é uma forma mais simples de reverter apenas um commit.
Não faça isso se você forçar as mudanças do mestre a montante
Alguém pode ter puxado essas mudanças. Se você está apenas reescrevendo seu mestre local, não há impacto quando ele é empurrado para cima, mas empurrar um histórico reescrito para os colaboradores pode causar dores de cabeça.
Movendo-se para um novo ramo
AVISO: Este método funciona porque você está criando uma nova ramificação com o primeiro comando: git branch newbranch
. Se você quiser mover confirmações para uma ramificação existente, precisará mesclar suas alterações na ramificação existente antes de executar a git reset --hard HEAD~3
(consulte Movendo para uma ramificação existente abaixo). Se você não mesclar suas alterações primeiro, elas serão perdidas.
A menos que haja outras circunstâncias envolvidas, isso pode ser feito facilmente, ramificando e retrocedendo.
# Note: Any changes not committed will be lost.
git branch newbranch # Create a new branch, saving the desired commits
git reset --hard HEAD~3 # Move master back by 3 commits (GONE from master)
git checkout newbranch # Go to the new branch that still has the desired commits
Mas tenha certeza de quantos commits voltar. Alternativamente, você pode, em vez de HEAD~3
, simplesmente fornecer o hash do commit (ou a referência como origem / master ) que você quer "reverter" para o branch master (/ current), por exemplo:
git reset --hard a1b2c3d4
* 1 Você só estará "perdendo" commits da ramificação master, mas não se preocupe, você terá aqueles commits no newbranch!
ATENÇÃO: Com o Git versão 2.0 e posterior, se você posteriormente git rebase
a nova ramificação na ramificação original ( master
), você pode precisar de uma opção explícita --no-fork-point
durante o rebase para evitar perder as confirmações transportadas. Ter branch.autosetuprebase always
definido torna isso mais provável. Veja a resposta de John Mellor para detalhes.
Movendo-se para um ramo existente
Se você quiser mover seus commits para uma ramificação existente , ficará assim:
git checkout existingbranch
git merge master
git checkout master
git reset --hard HEAD~3 # Go back 3 commits. You *will* lose uncommitted work.
git checkout existingbranch
1) Crie uma nova ramificação, que move todas as suas alterações para new_branch.
git checkout -b new_branch
2) Então volte para o ramo antigo.
git checkout master
3) fazer rebase git
git rebase -i <short-hash-of-B-commit>
4) Em seguida, o editor aberto contém as últimas 3 informações de confirmação.
...
pick <C's hash> C
pick <D's hash> D
pick <E's hash> E
...
5) Alterar pick
para drop
em todos os 3 commits. Em seguida, salve e feche o editor.
...
drop <C's hash> C
drop <D's hash> D
drop <E's hash> E
...
6) Agora, os últimos 3 commits são removidos da ramificação atual ( master
). Agora empurre o ramo com força, com o sinal +
antes do nome da ramificação.
git push origin +master
Isso não "move" eles no sentido técnico, mas tem o mesmo efeito:
A--B--C (branch-foo)
\ ^-- I wanted them here!
\
D--E--F--G (branch-bar)
^--^--^-- Opps wrong branch!
While on branch-bar:
$ git reset --hard D # remember the SHAs for E, F, G (or E and G for a range)
A--B--C (branch-foo)
\
\
D-(E--F--G) detached
^-- (branch-bar)
Switch to branch-foo
$ git cherry-pick E..G
A--B--C--E'--F'--G' (branch-foo)
\ E--F--G detached (This can be ignored)
\ /
D--H--I (branch-bar)
Now you won't need to worry about the detached branch because it is basically
like they are in the trash can waiting for the day it gets garbage collected.
Eventually some time in the far future it will look like:
A--B--C--E'--F'--G'--L--M--N--... (branch-foo)
\
\
D--H--I--J--K--.... (branch-bar)
Para aqueles que estão se perguntando por que funciona (como eu estava no começo):
Você quer voltar para C e mover D e E para o novo ramo. Aqui está o que parece no começo:
A-B-C-D-E (HEAD)
↑
master
Depois git branch newBranch
:
newBranch
↓
A-B-C-D-E (HEAD)
↑
master
Após git reset --hard HEAD~2
:
newBranch
↓
A-B-C-D-E (HEAD)
↑
master
Como um ramo é apenas um ponteiro, o mestre apontou para o último commit. Quando você fez newBranch , você simplesmente fez um novo ponteiro para o último commit. Então, usando o git reset
você moveu o ponteiro mestre de volta para dois commits. Mas desde que você não mudou newBranch , ele ainda aponta para o commit originalmente feito.
Teve apenas esta situação:
Branch one: A B C D E F J L M
\ (Merge)
Branch two: G I K N
Eu executei:
git branch newbranch
git reset --hard HEAD~8
git checkout newbranch
Eu esperava que cometer eu seria a cabeça, mas comprometo L é agora ...
Para ter certeza de pousar no lugar certo na história, é mais fácil trabalhar com o hash do commit
git branch newbranch
git reset --hard #########
git checkout newbranch
Você pode fazer isso é apenas 3 simples passo que eu usei.
1) faça uma nova ramificação onde você deseja enviar sua atualização recente.
git branch <branch name>
2) Encontrar o ID de confirmação recente para confirmar no novo ramo.
git log
3) Copie essa nota de ID de commit que a lista de commits Most Recent ocorre no topo. então você pode encontrar o seu commit. você também encontra isso via mensagem.
git cherry-pick d34bcef232f6c...
você também pode fornecer alguns toques de id de confirmação.
git cherry-pick d34bcef...86d2aec
Agora seu trabalho feito. Se você escolheu o ID correto e o ramo correto, você terá sucesso. Então, antes disso, tenha cuidado. mais outro problema pode ocorrer.
Agora você pode empurrar seu código
git push