mover alterações confirmadas (mas não forçadas) para uma nova ramificação após puxar

460

Eu fiz um bom trabalho ("Seu ramo está à frente de 'origem / mestre' em 37 commits".) Que realmente deveria ter entrado em seu próprio ramo e não em master. Esses commits existem apenas na minha máquina local e não foram enviados origin, mas a situação é um pouco complicada porque outros desenvolvedores estão pressionando origin/mastere eu fiz essas alterações.

Como passo retroativamente meus 37 commits locais para uma nova ramificação? Com base nos documentos, parece que git rebase --onto my-new-branch masterou ...origin/masterdeveria fazer isso, mas ambos me deram o erro "fatal: precisava de uma única revisão". man git-rebasenão diz nada sobre como fornecer uma revisão rebasee seus exemplos não o fazem, por isso não tenho idéia de como resolver esse erro.

(Observe que isso não é uma duplicata de Mover trabalho não confirmado existente para uma nova ramificação no Git ou Como mesclar minhas alterações não confirmadas locais em outra ramificação do Git? Pois essas perguntas lidam com alterações não confirmadas na árvore de trabalho local, e não com alterações foi confirmado localmente.)

Dave Sherohman
fonte
Confira esta solução . Parece ser fácil e limpo.
Tony
Confira esta solução . Parece ser fácil e limpo.
Tony

Respostas:

518

Isso deve ser bom, já que você não enviou seus commits em nenhum outro lugar ainda, e você pode reescrever o histórico de sua ramificação depois origin/master. Primeiro, eu executaria um git fetch originpara ter certeza de que origin/masterestá atualizado. Supondo que você esteja atualmente master, você deve ser capaz de:

git rebase origin/master

... que irá reproduzir todos os seus commits que não estão em origin/masterpara origin/master. A ação padrão do rebase é ignorar confirmações de mesclagem (por exemplo, aquelas que você git pullprovavelmente introduziu) e tentará aplicar o patch introduzido por cada uma das confirmações origin/master. (Talvez seja necessário resolver alguns conflitos ao longo do caminho.) Em seguida, você pode criar sua nova ramificação com base no resultado:

git branch new-work

... e, em seguida, redefina as mastercostas para origin/master:

# Use with care - make sure "git status" is clean and you're still on master:
git reset --hard origin/master

Ao fazer este tipo de manipulação de ramos com git branch, git resetetc. Acho que é útil para freqüentemente olhar para o gráfico com commit gitk --allou uma ferramenta semelhante, apenas para verificar que eu entendo de onde todos os diferentes refs estão apontando.

Como alternativa, você pode ter acabado de criar uma ramificação de tópico com base no local onde seu mestre está ( git branch new-work-including-merges) e, em seguida, redefinir mastercomo acima. No entanto, como o ramo de tópicos incluirá mesclagens origin/mastere você ainda não efetuou alterações nas alterações, sugiro que você faça uma nova reformulação para que o histórico fique mais organizado. (Além disso, quando você eventualmente mesclar a ramificação do tópico de volta ao mestre, as alterações serão mais óbvias.)

Mark Longair
fonte
8
@Olie: Não, a resposta está correta sob as premissas da pergunta e as que eu expus na parte superior da resposta. As confirmações que deveriam estar em uma nova ramificação separada já estão dentro master; a rebase reescreve a masterramificação para que as novas confirmações estejam linearmente em cima origin/mastere git branch new-workcria uma new-workramificação apontando na ponta de master(a ramificação atual) sem mudar a ramificação atual para new-work. Então agora new-workcontém todos os novos commits. A redefinição move a ramificação atual (estática master) de volta para origin/master.
precisa saber é o seguinte
1
@ Quintesse: Sinto muito se você perdeu o trabalho, mas tenho certeza que esta resposta está correta para a situação descrita pelo questionador original. (Acabei de responder às observações de Olie, que esperam esclarecer.) De qualquer forma, para o caso de ajudar a recuperar seu trabalho, devo dizer que, se seu trabalho foi realizado nos últimos dias (uma das suposições nesta pergunta e resposta) ), você poderá recuperá-lo facilmente através do refletor git.
precisa saber é o seguinte
5
@ Olie: talvez uma maneira melhor de explicar: as ramificações no git são como rótulos que apontam para um commit específico; eles são movidos automaticamente para novas confirmações se você os criar nessa ramificação ou puder ser movido de git resetvárias outras maneiras. Ele git branch new-workestá apenas dizendo "crie um ramo apontando para esse commit enquanto eu permanecer no meu ramo atual (que é mestre nesse caso)". Portanto, não há necessidade de ter um comando que move os commits de mestre para a nova filial - você apenas criar um novo ramo lá e quando você redefinir mestre o novo ramo é deixado onde mestre era
Mark Longair
1
um pouco atrasado para a festa, mas @Olie, apenas porque o status git quando no novo ramo não mostra os commits à frente do master não significa que eles não estão realmente lá (assumindo que é por isso que você estava preocupado). Tente empurrar o novo ramo de origem: você verá os commits estão lá
Félix Gagnon-Grenier
2
@ FélixGagnon-Grenier, não se preocupe com o "atraso" - sempre há pessoas procurando perguntas antigas e todos os esclarecimentos ajudam. Obrigado! :)
Olie
148

Se você tem um número baixo de confirmações e não se importa se elas são combinadas em um mega-commit, isso funciona bem e não é tão assustador quanto git rebase:

desestabilizar os arquivos (substitua 1 pelo número de confirmações)

git reset --soft HEAD~1

crie uma nova ramificação

git checkout -b NewBranchName

adicione as mudanças

git add -A

fazer um commit

git commit -m "Whatever"
Stachu
fonte
5
Para mostrar um gráfico fácil de entender, use git log --all --decorate --oneline --graph.
EliuX 28/03
Hey @EliuX - Estou perdendo a relevância aqui. Você pode expandir?
Stachu 29/03
Isso é algo útil para verificar se você tem o resultado procurado em que você fez
EliuX
4
Obrigado!! esta é uma solução muito simples e funcionou perfeitamente !!
Chris Sim
91

Eu fiquei com o mesmo problema. Eu encontrei a solução mais fácil que eu gostaria de compartilhar.

1) Crie uma nova ramificação com suas alterações.

git checkout -b mybranch

2) (Opcional) Pressione o novo código da filial no servidor remoto.

git push origin mybranch

3) Finalize a compra para o ramo principal.

git checkout master

4) Redefina o código da ramificação principal com o servidor remoto e remova a confirmação local.

git reset --hard origin/master
NiRmaL
fonte
10
Isso é realmente a maneira mais fácil
dhilt
4
Você pode deixar de fora a etapa 2. Suponho que, desde a resposta inicial, o git mudou e essa precessão não era permitida antes.
21718 Sebastian
Esta é a melhor resposta na minha opinião.
19419 Macindows
1
Esta resposta precisa passar para o topo. Obrigado.
amit
27

Mais uma maneira de assumir que branch1 - é ramo com alterações confirmadas branch2 - é ramo desejável

git fetch && git checkout branch1
git log

selecione os IDs de confirmação que você precisa mover

git fetch && git checkout branch2
git cherry-pick commit_id_first..commit_id_last
git push

Agora reverta confirmações não enviadas da ramificação inicial

git fetch && git checkout branch1
git reset --soft HEAD~1
Andriy
fonte
5
Cherry-pick é realmente o melhor comando "copiar / mover um único commit", esp. quando a história é bagagem para seus propósitos.
John Neuhaus 14/05
Esta é até agora a resposta mais conveniente para a pergunta. Obrigado pelo comando!
Farah
você pode atualizar seu último comentário em que 1 ou n é o número de confirmações não enviadas? Ainda é uma solução muito boa para esta pergunta.
chAlexey
9

Como alternativa, logo após confirmar com a ramificação errada, execute estas etapas:

  1. git log
  2. git diff {previous to last commit} {latest commit} > your_changes.patch
  3. git reset --hard origin/{your current branch}
  4. git checkout -b {new branch}
  5. git apply your_changes.patch

Eu posso imaginar que existe uma abordagem mais simples para as etapas um e dois.

Andreas B
fonte
6

A respeito:

  1. Ramifique da CABEÇA atual.
  2. Verifique se você está no mestre , não no seu novo ramo.
  3. git reset volte para a última confirmação antes de começar a fazer alterações.
  4. git pull para puxar novamente apenas as alterações remotas que você jogou fora com a redefinição.

Ou isso explodirá quando você tentar mesclar novamente o ramo?

Tim Keating
fonte
2
Ah, isso é basicamente a opção B descrito por @ Mark-Longair acima
Tim Keating
2

Aqui está uma maneira muito mais simples:

  1. Crie uma nova ramificação

  2. Em sua nova ramificação, faça um git merge master- isso mesclará as alterações confirmadas (não enviadas) para sua nova ramificação

  3. Excluir sua ramificação principal local git branch -D masterUse em -Dvez de -dporque deseja forçar a exclusão da ramificação.

  4. Basta fazer um git fetchno seu ramo principal e git pullno seu ramo principal para garantir que você tenha o código mais recente da sua equipe.

A Kok
fonte
1

Uma abordagem mais simples, que eu tenho usado (supondo que você queira mover 4 confirmações):

git format-patch HEAD~4

(Procure no diretório a partir do qual você executou o último comando para os 4 .patcharquivos)

git reset HEAD~4 --hard

git checkout -b tmp/my-new-branch

Então:

git apply /path/to/patch.patch

Na ordem que você quisesse.

user1429980
fonte
0
  1. Fazer checkout de uma nova cópia de suas fontes

    git clone ........

  2. Faça ramificação da posição desejada

    git checkout {position} git checkout -b {branch-name}

  3. Adicionar repositório remoto

    git remote add shared ../{original sources location}.git

  4. Obter fontes remotas

    git fetch shared

  5. Fazer checkout da filial desejada

    git checkout {branch-name}

  6. Mesclar fontes

    git merge shared/{original branch from shared repository}

Sergey Kabashnyuk
fonte
0

Para mim, essa foi a melhor maneira:

  1. Verifique se há alterações e conflitos de mesclagem git fetch
  2. Crie uma nova ramificação git branch my-changese envie para remoto
  3. Alterar upstream para nova ramificação criada git master -u upstream-branch remotes/origin/my-changes
  4. Envie seus commit para o novo ramo upstream.
  5. Voltar para o upstream anterior git branch master --set-upstream-to remotes/origin/master
Sebastian
fonte