Resposta curta
Você omitiu o fato de executar git push
, obteve o seguinte erro e prosseguiu com a execução git pull
:
To git@bitbucket.org:username/test1.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Apesar de o Git tentar ser útil, seu conselho sobre 'git pull' provavelmente não é o que você deseja fazer .
Se você é:
- Trabalhando em um "ramo de recurso" ou "ramo desenvolvedor" sozinho , então você pode executar
git push --force
para atualizar o controle remoto com seus commits pós-REBASE ( como por resposta das user4405677 ).
- Trabalhando em uma filial com vários desenvolvedores ao mesmo tempo, você provavelmente não deveria estar usando
git rebase
em primeiro lugar. Para atualizar dev
com as alterações de master
, você deve, em vez de executar git rebase master dev
, executar git merge master
enquanto estiver dev
( conforme a resposta de Justin ).
Uma explicação um pouco mais longa
Cada hash de confirmação no Git é baseado em vários fatores, um dos quais é o hash da confirmação que vem antes dele.
Se você reordenar as confirmações, alterará os hashes de confirmação; rebasing (quando faz alguma coisa) mudará os hashes de confirmação. Com isso, o resultado da execução git rebase master dev
, onde dev
está fora de sincronia master
, criará novas confirmações (e, portanto, hashes) com o mesmo conteúdo que as ativadas, dev
mas com as confirmações master
inseridas antes deles.
Você pode acabar em uma situação como essa de várias maneiras. Duas maneiras em que posso pensar:
- Você pode ter confirmações nas
master
quais deseja basear seu dev
trabalho
- Você pode ter confirmações
dev
que já foram enviadas para um controle remoto, e depois proceder à alteração (reformular as mensagens de confirmação, reordenar confirmações, squash confirma, etc.)
Vamos entender melhor o que aconteceu - aqui está um exemplo:
Você tem um repositório:
2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0
Em seguida, prossiga para alterar confirmações.
git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing
(É aqui que você terá que aceitar minha palavra: existem várias maneiras de alterar confirmações no Git. Neste exemplo, mudei o horário de C3
, mas você está inserindo novas confirmações, alterando mensagens de confirmação, reordenando confirmações, squashing comete em conjunto, etc.)
ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0
É aqui que é importante notar que os hashes de confirmação são diferentes. Esse é um comportamento esperado, pois você alterou algo (qualquer coisa) sobre eles. Está tudo bem, MAS:
Tentar empurrar mostrará um erro (e sugerirá que você deve executar git pull
).
$ git push origin master
To git@bitbucket.org:username/test1.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/test1.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Se rodarmos git pull
, vemos este log:
7df65f2 (HEAD, master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 (origin/master) C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
Ou, mostrado de outra maneira:
E agora temos confirmações duplicadas localmente. Se rodássemos, git push
nós os enviaríamos para o servidor.
Para evitar chegar a esse estágio, poderíamos ter corrido git push --force
(onde corremos git pull
). Isso teria enviado nossos commits com os novos hashes para o servidor sem problemas. Para corrigir o problema neste estágio, podemos redefinir para antes de executar git pull
:
Olhe para o reflog ( git reflog
) para ver o que o commit de hash foi antes de nós corremos git pull
.
070e71d HEAD@{1}: pull: Merge made by the 'recursive' strategy.
ba7688a HEAD@{2}: rebase -i (finish): returning to refs/heads/master
ba7688a HEAD@{3}: rebase -i (pick): C5
44085d5 HEAD@{4}: rebase -i (pick): C4
961390d HEAD@{5}: commit (amend): C3
3cb46a9 HEAD@{6}: cherry-pick: fast-forward
85f59ab HEAD@{7}: rebase -i (start): checkout HEAD~~~
2a2e220 HEAD@{8}: rebase -i (finish): returning to refs/heads/master
2a2e220 HEAD@{9}: rebase -i (start): checkout refs/remotes/origin/master
2a2e220 HEAD@{10}: commit: C5
ab1bda4 HEAD@{11}: commit: C4
3cb46a9 HEAD@{12}: commit: C3
85f59ab HEAD@{13}: commit: C2
4516164 HEAD@{14}: commit: C1
0e783a3 HEAD@{15}: commit (initial): C0
Acima, vemos que ba7688a
era o commit em que estávamos antes de executar git pull
. Com esse hash de commit em mãos, podemos redefinir para that ( git reset --hard ba7688a
) e depois executar git push --force
.
E nós terminamos.
Mas espere, continuei baseando o trabalho nos commits duplicados
Se você não percebeu que as confirmações foram duplicadas e continuou a trabalhar em cima das confirmações duplicadas, você realmente fez uma bagunça. O tamanho da bagunça é proporcional ao número de confirmações que você tem sobre as duplicatas.
Como é isso:
3b959b4 (HEAD, master) C10
8f84379 C9
0110e93 C8
6c4a525 C7
630e7b4 C6
070e71d (origin/master) Merge branch 'master' of bitbucket.org:username/test1
ba7688a C5
44085d5 C4
961390d C3
2a2e220 C5
85f59ab C2
ab1bda4 C4
4516164 C1
3cb46a9 C3
0e783a3 C0
Ou, mostrado de outra maneira:
Nesse cenário, queremos remover as confirmações duplicadas, mas manter as confirmações que baseamos nelas - queremos manter C6 a C10. Como na maioria das coisas, existem várias maneiras de fazer isso:
Ou:
- Crie uma nova ramificação na última confirmação duplicada 1 ,
cherry-pick
cada confirmação (inclusive C6 a C10) nessa nova ramificação e trate essa nova ramificação como canônica.
- Execute
git rebase --interactive $commit
, onde $commit
está a confirmação antes das confirmações duplicadas 2 . Aqui, podemos excluir completamente as linhas das duplicatas.
1 Não importa qual dos dois você escolher, ba7688a
ou 2a2e220
funciona bem.
2 No exemplo seria 85f59ab
.
TL; DR
Defina advice.pushNonFastForward
como false
:
git config --global advice.pushNonFastForward false