Короткий ответ
Вы пропустили тот факт, что вы запустили git push
, получили следующую ошибку, а затем продолжили выполнение git pull
:
To [email protected]:username/test1.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to '[email protected]: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 основан на нескольких факторах, одним из которых является хэш предшествующей фиксации.
Если вы измените порядок коммитов, вы измените хеши коммитов; перебазирование (когда он что-то делает) изменит хеши коммитов. При этом результат выполнения 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 [email protected]:username/test1.git
! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to '[email protected]: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
:
Взгляните на журнал ссылок (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, _39 _ каждую фиксацию (с C6 по C10 включительно) в эту новую ветку и рассматривать эту новую ветвь как каноническую.
- Запустите
git rebase --interactive $commit
, где $commit
- это предшествующая фиксация для обеих дублированных фиксаций 2. Здесь мы можем сразу удалить строки для дубликатов.
1 Неважно, какой из двух вы выберете, ba7688a
или 2a2e220
работают нормально.
2 В примере это будет 85f59ab
.
TL;DR
Установите для advice.pushNonFastForward
значение false
:
git config --global advice.pushNonFastForward false
person
Whymarrh
schedule
18.06.2015