Gostaria de mudar os últimos commits comprometidos em dominar para uma nova ramificação e retornar o master antes que esses commits fossem feitos. Infelizmente, meu Git-fu ainda não é forte o suficiente, ajuda?
Ou seja, como posso passar disso
master A - B - C - D - E
para isso?
newbranch C - D - E
/
master A - B
git
git-branch
branching-and-merging
Mark A. Nicolosi
fonte
fonte
Respostas:
Movendo para uma ramificação existente
Se você deseja mover suas confirmações para uma ramificação existente , será semelhante a:
A
--keep
opção preserva quaisquer alterações não confirmadas que você possa ter em arquivos não relacionados ou anula se essas alterações precisarem ser substituídas - da mesma forma quegit checkout
ocorre. Se for interrompido,git stash
as alterações e tentativas serão repetidas ou usadas--hard
para perdê- las (mesmo de arquivos que não foram alterados entre as confirmações!)Movendo para uma nova ramificação
Este método funciona criando uma nova ramificação com o primeiro comando (
git branch newbranch
), mas sem mudar para ele. Em seguida, revertemos a ramificação atual (principal) e mudamos para a nova ramificação para continuar trabalhando.Mas certifique-se de quantos commits para voltar. Como alternativa, em vez de
HEAD~3
, você pode simplesmente fornecer o hash do commit (ou a referência comoorigin/master
) que deseja reverter, por exemplo:AVISO: Com o Git versão 2.0 e posterior, se você adiantar
git rebase
a nova ramificação na ramificação original (master
), poderá ser necessária uma--no-fork-point
opção explícita durante a reformulação para evitar perder as confirmações que você moveu da ramificação mestre. Tendobranch.autosetuprebase always
definido torna isso mais provável. Veja a resposta de John Mellor para obter detalhes.fonte
Para aqueles que se perguntam 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 a princípio:
Depois
git branch newBranch
:Depois
git reset --hard HEAD~2
:Como um ramo é apenas um ponteiro, o mestre apontou para o último commit. Quando você criou newBranch , você simplesmente criou um novo ponteiro para o último commit. Em seguida, usando
git reset
você moveu o ponteiro mestre para trás duas confirmações. Mas como você não moveu o newBranch , ele ainda aponta para o commit original.fonte
git push origin master --force
para a mudança aparecer no repositório principal.git rebase
, as 3 confirmações serão descartadas silenciosamentenewbranch
. Veja minha resposta para detalhes e alternativas mais seguras.origin/master
não aparece no diagrama acima. Se você pressionasseorigin/master
e fizesse as alterações acima, com certeza, as coisas seriam engraçadas. Mas esse é o tipo de problema "Doutor, dói quando faço isso". E está fora do escopo para o que a pergunta original fez. Sugiro que você escreva sua própria pergunta para explorar seu cenário em vez de sequestrar este.git branch -t newbranch
". Volte e leia as respostas novamente. Ninguém sugeriu fazer isso.newbranch
se basear namaster
filial local existente . Depois de realizar a resposta aceita, quando o usuário fica em torno de corrergit rebase
emnewbranch
, git vai lembrá-los que eles se esqueceu de definir o ramo upstream, então eles vão executargit branch --set-upstream-to=master
, em seguida,git rebase
e têm o mesmo problema. Eles também podem usargit branch -t newbranch
em primeiro lugar.Em geral...
O método exposto pelo sykora é a melhor opção nesse 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 deseja, é um processo de duas etapas:
Etapa 1 - Observe o que você confirma do mestre que deseja em um
newbranch
Executar
Observe os hashes de (digamos 3) confirmações que você deseja
newbranch
. Aqui vou usar:C commit:
9aa1233
D commit:
453ac3d
E commit:
612ecb3
Etapa 2 - Coloque-os no
newbranch
OR (no Git 1.7.2+, use intervalos)
O git cherry-pick aplica esses três commits ao newbranch.
fonte
Ainda outra maneira de fazer isso, usando apenas 2 comandos. Também mantém intacta a sua árvore de trabalho atual.
Versão antiga - antes de eu aprender sobre
git branch -f
Ser capaz de
push
para.
é um truque bom saber.fonte
git branch -f
aqui?.
é atual diretor. O git pode enviar para REMOTES ou URLs GIT.path to local directory
é suportada sintaxe dos URLs do Git. Consulte a seção URLs do GIT emgit help clone
.A maioria das respostas anteriores está perigosamente errada!
Não faça isso:
Na próxima vez em que você executar
git rebase
(ougit pull --rebase
) esses 3 commits serão descartados silenciosamentenewbranch
! (veja a explicação abaixo)Em vez disso, faça o seguinte:
--keep
é--hard
mais seguro, pois falha ao invés de jogar fora as alterações não confirmadas).newbranch
.newbranch
. Como eles não são mais referenciados por um ramo, ele faz isso usando o reflog do git :HEAD@{2}
é o commit queHEAD
costumava se referir a 2 operações atrás, ou seja, antes de 1. fazer o check-outnewbranch
e 2. usadogit reset
para descartar os 3 commit.Aviso: o reflog está ativado por padrão, mas se você o desativou manualmente (por exemplo, usando um repositório git "bare"), não será possível recuperar os 3 commits após a execução
git reset --keep HEAD~3
.Uma alternativa que não depende do reflog é:
(se preferir, você pode escrever
@{-1}
- o ramo previamente retirado - em vez deoldbranch
).Explicação técnica
Por que
git rebase
descartar os 3 commits após o primeiro exemplo? Isso ocorre porque,git rebase
sem argumentos, a--fork-point
opção por padrão é ativada, que usa o reflog local para tentar ser robusto contra o desvio do ramo upstream.Suponha que você ramificou origem / mestre quando ele continha confirmações M1, M2, M3 e, em seguida, fez três confirmações:
mas alguém reescreve o histórico pressionando origem / mestre para remover M2:
Usando seu reflog local, você
git rebase
pode ver que você se retirou de uma encarnação anterior da ramificação de origem / mestre e, portanto, as confirmações M2 e M3 não são realmente parte da ramificação de tópicos. Portanto, considera-se razoavelmente que, desde que o M2 foi removido da ramificação upstream, você não a deseja mais em sua ramificação de tópico, assim que a ramificação de tópico for rebaseada:Esse comportamento faz sentido e geralmente é a coisa certa a se fazer quando se rebase.
Portanto, o motivo pelo qual os seguintes comandos falham:
é porque eles deixam o reflog no estado errado. O Git vê
newbranch
como bifurcado no ramo upstream em uma revisão que inclui os 3 commits, depoisreset --hard
reescreve o histórico do upstream para remover os commits e, da próxima vez que você o executagit rebase
, descarta-os como qualquer outro commit que foi removido do upstream.Mas neste caso em particular, queremos que esses 3 commits sejam considerados como parte do ramo de tópicos. Para conseguir isso, precisamos extrair o upstream da revisão anterior que não inclui os 3 commits. É isso que minhas soluções sugeridas fazem, portanto, ambas deixam o reflog no estado correto.
Para mais detalhes, ver a definição de
--fork-point
no rebase git e merge-base git docs.fonte
master
. Então não, eles não estão perigosamente errados.-t
você está se referindogit branch
acontece implicitamente se você tivergit config --global branch.autosetuprebase always
definido. Mesmo se não, eu já expliquei a você que o mesmo problema ocorre se você configurar o rastreamento após executar esses comandos, como o OP provavelmente pretende fazer diante da pergunta deles.Solução muito mais simples usando o git stash
Aqui está uma solução muito mais simples para confirmações no ramo errado. Iniciando na ramificação
master
que possui três confirmações incorretas:Quando usar isso?
master
O que isso faz, pelo número da linha
master
e ainda mantém intactos todos os arquivos de trabalhomaster
árvore de trabalho exatamente igual ao estado HEAD ~ 3newbranch
Agora você pode usar
git add
egit commit
como faria normalmente. Todas as novas confirmações serão adicionadas anewbranch
.O que isso não faz
Metas
O OP declarou que o objetivo era "recuperar o domínio antes que esses comprometimentos fossem feitos" sem perder as alterações e essa solução faz isso.
Faço isso pelo menos uma vez por semana quando acidentalmente faço novos commit em
master
vez dedevelop
. Normalmente, tenho apenas uma confirmação para reverter, caso em que o usogit reset HEAD^
na linha 1 é uma maneira mais simples de reverter apenas uma confirmação.Não faça isso se você empurrou as alterações do mestre para montante
Outra pessoa pode ter feito essas alterações. Se você estiver reescrevendo apenas o mestre local, não haverá impacto quando for promovido a montante, mas enviar um histórico reescrito para os colaboradores pode causar dores de cabeça.
fonte
git add
egit commit
que eu usava, então tudo o que eu precisava fazer era acertar a seta e entrar algumas vezes e explodir! Tudo estava de volta, mas agora no ramo certo.Isso não os "move" no sentido técnico, mas tem o mesmo efeito:
fonte
rebase
para a mesma coisa?rebase
na ramificação desanexada no cenário acima.Para fazer isso sem reescrever o histórico (ou seja, se você já enviou os commit):
Ambos os galhos podem ser empurrados sem força!
fonte
Teve exatamente esta situação:
Eu executei:
Eu esperava que o commit fosse o HEAD, mas o commit é L agora ...
Para ter certeza de aterrissar no lugar certo na história, é mais fácil trabalhar com o hash do commit
fonte
Como posso ir disso
para isso?
Com dois comandos
dando
e
dando
fonte
Se você só precisa mover todos os seus commits não pressionados para uma nova ramificação , precisará,
crie uma nova ramificação a partir da atual:
git branch new-branch-name
empurre seu novo ramo :
git push origin new-branch-name
reverta sua ramificação antiga (atual) para o último estado push / estável:
git reset --hard origin/old-branch-name
Algumas pessoas também têm outras, em
upstreams
vez deorigin
, elas devem usarupstream
fonte
1) Crie uma nova ramificação, que move todas as suas alterações para new_branch.
2) Volte ao ramo antigo.
3) Faça git rebase
4) O editor aberto contém as últimas 3 informações de confirmação.
5) Altere
pick
paradrop
em todos esses 3 commits. Em seguida, salve e feche o editor.6) Agora, as 3 últimas confirmações são removidas da ramificação atual (
master
). Agora empurre o ramo vigorosamente, com+
sinal antes do nome do ramo.fonte
Você pode fazer isso é apenas 3 passo simples que eu usei.
1) faça uma nova ramificação onde deseja confirmar sua atualização recente.
git branch <branch name>
2) Encontre o ID de confirmação recente para confirmação na nova ramificação.
git log
3) Copie esse ID de confirmação, observe que a lista de confirmação Mais Recente ocorre no topo. para que você possa encontrar 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 está pronto. Se você escolheu a identificação correta e o ramo correto, terá sucesso. Portanto, antes disso, tenha cuidado. caso contrário, outro problema pode ocorrer.
Agora você pode enviar seu código
git push
fonte
Outra maneira de fazer isso:
[1] Renomeie o
master
ramo para o seunewbranch
(supondo que você esteja nomaster
ramo):[2] Crie um
master
branch a partir do commit que você deseja:fonte