Короткий ответ
Вы пропустили тот факт, что вы запустили git push
, получили следующую ошибку и затем продолжили работу 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.
Несмотря на то, что Git пытается быть полезным, его совет «git pull», скорее всего, не то, что вы хотите делать .
Если ты:
- Работая над «ответвлением новой функции» или «разработчик филиалом» только , то вы можете запустить ,
git push --force
чтобы обновить пульт с вашими после перебазирования фиксаций ( в соответствии с ответом user4405677 игровых ).
- Если вы работаете в ветке с несколькими разработчиками одновременно, вам, вероятно, не следует использовать его
git rebase
в первую очередь. Чтобы обновить dev
с изменениями из master
, вы должны вместо запуска git rebase master dev
запускать git merge master
во время работы dev
( согласно ответу Джастина ).
Немного более длинное объяснение
Каждый хэш фиксации в Git основан на нескольких факторах, один из которых - хэш предшествующей фиксации.
Если вы измените порядок коммитов, вы измените хеши коммитов; rebase (когда он что-то делает) изменит хеши коммитов. При этом результат выполнения git rebase master dev
, с которым dev
не синхронизирован master
, создаст новые коммиты (и, следовательно, хэши) с тем же содержанием, что и те, которые включены, dev
но с коммитами, master
вставленными перед ними.
Вы можете попасть в такую ситуацию разными способами. Я могу думать о двух способах:
- У вас могут быть коммиты, на
master
которых вы хотите основывать своиdev
работу
- У вас могли быть коммиты
dev
, которые уже были отправлены на удаленный компьютер, которые вы затем переходите к изменению (перефразируйте сообщения коммитов, переупорядочивайте коммиты, сквош-коммиты и т.
Давайте лучше разберемся, что произошло - вот пример:
У вас есть репозиторий:
2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0
Затем вы переходите к изменению коммитов.
git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing
(Здесь вам придется поверить мне на слово: есть несколько способов изменить коммиты в Git. В этом примере я изменил время C3
, но вы будете вставлять новые коммиты, изменять сообщения коммитов, переупорядочивать коммиты, объединение коммитов и т. д.)
ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0
Здесь важно заметить, что хеши коммитов разные. Это ожидаемое поведение, поскольку вы что-то (что-то) в них изменили. Это нормально, НО:
Попытка нажать покажет вам ошибку (и намекнет, что вам следует запустить 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.
Если мы запустим git pull
, то увидим такой лог:
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
Или, как показано по-другому:
И теперь у нас есть дублирующиеся коммиты локально. Если бы мы запустили, git push
мы бы отправили их на сервер.
Чтобы не попасть на этот этап, мы могли бежать git push --force
(там, где мы бежали git pull
). Это без проблем отправило бы наши коммиты с новыми хешами на сервер. Чтобы решить проблему на этом этапе, мы можем вернуться к предыдущему состоянию git pull
:
Посмотрите на reflog ( git reflog
) , чтобы увидеть , что совершить хэш был до того мы побежали 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
Выше мы видим, что это ba7688a
была фиксация, в которой мы были до запуска git pull
. Имея в руках этот хеш фиксации, мы можем вернуться к этому ( git reset --hard ba7688a
) и затем запустить git push --force
.
И мы закончили.
Но подождите, я продолжал основывать работу на дублированных коммитах.
Если вы каким-то образом не заметили, что коммиты были дублированы, и продолжили работать поверх повторяющихся коммитов, вы действительно навредили себе. Размер беспорядка пропорционален количеству коммитов, которые у вас есть поверх дубликатов.
Как это выглядит:
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
Или, как показано по-другому:
В этом сценарии мы хотим удалить повторяющиеся коммиты, но сохранить основанные на них коммиты - мы хотим сохранить от C6 до C10. Как и в большинстве случаев, есть несколько способов сделать это:
Либо:
- Создайте новую ветку при последней дублированной фиксации 1 ,
cherry-pick
каждую фиксацию (с C6 по C10 включительно) в эту новую ветку и рассматривайте эту новую ветвь как каноническую.
- Выполнить
git rebase --interactive $commit
, где $commit
находится фиксация перед обеими дублированными коммитами 2 . Здесь мы можем сразу удалить строки для дубликатов.
1 Не имеет значения , какой из двух вы выбираете, либо ba7688a
или 2a2e220
нормально работать.
2 В примере это было бы 85f59ab
.
TL; DR
Набор advice.pushNonFastForward
для false
:
git config --global advice.pushNonFastForward false