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

  1. Desfaz os últimos três commits (e suas mensagens) para master , mas deixa todos os arquivos de trabalho intactos
  2. Armazena todas as alterações do arquivo de trabalho, tornando a árvore de trabalho master igual ao estado HEAD ~ 3
  3. Muda para um branch newbranch existente
  4. 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ê 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







branching-and-merging