Krótka odpowiedź
Pominąłeś fakt, że uruchomiłeś git push
, pojawił się następujący błąd, a następnie przystąpiłeś do uruchamiania 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.
Mimo że Git stara się być pomocny, jego rada „git pull” najprawdopodobniej nie jest tym, co chcesz zrobić .
Jeśli jesteś:
- Pracując nad samą „gałęzią funkcji” lub „gałęzią dewelopera” , możesz uruchomić
git push --force
aktualizację pilota za pomocą zatwierdzeń po rebase ( zgodnie z odpowiedzią użytkownika4405677 ).
- Pracując na gałęzi z wieloma programistami w tym samym czasie, prawdopodobnie nie powinieneś używać
git rebase
w pierwszej kolejności. Aby zaktualizować dev
ze zmianami z master
, powinieneś zamiast biegać git rebase master dev
, git merge master
gdy jest włączony dev
( zgodnie z odpowiedzią Justina ).
Nieco dłuższe wyjaśnienie
Każdy skrót zatwierdzenia w Git jest oparty na wielu czynnikach, z których jednym jest skrót zatwierdzenia, który występuje przed nim.
Jeśli zmienisz kolejność zatwierdzeń, zmienisz skróty zatwierdzeń; rebasing (kiedy coś robi) zmieni skróty zatwierdzeń. Dzięki temu wynik uruchomienia git rebase master dev
, gdzie nie dev
jest zsynchronizowany z master
, utworzy nowe zatwierdzenia (a tym samym skróty) z taką samą zawartością jak te włączone, dev
ale z zatwierdzeniami master
wstawionymi przed nimi.
W takiej sytuacji możesz znaleźć się na wiele sposobów. Dwa sposoby, które przychodzą mi do głowy:
- Możesz mieć commity, na
master
których chcesz oprzeć swoją dev
pracę
- Mogłeś mieć zatwierdzenia,
dev
które zostały już przesłane do pilota, a następnie przystąpisz do ich zmiany (przeredaguj komunikaty o zatwierdzeniach, zmień kolejność zatwierdzeń, zatwierdzeń squash itp.)
Lepiej zrozummy, co się stało - oto przykład:
Masz repozytorium:
2a2e220 (HEAD, master) C5
ab1bda4 C4
3cb46a9 C3
85f59ab C2
4516164 C1
0e783a3 C0
Następnie przystępujesz do zmiany zatwierdzeń.
git rebase --interactive HEAD~3 # Three commits before where HEAD is pointing
(Tutaj musisz uwierzyć na moje słowo: istnieje wiele sposobów zmiany zatwierdzeń w Git. W tym przykładzie zmieniłem czas C3
, ale ty wstawiasz nowe zatwierdzenia, zmieniasz komunikaty zmian, zmieniam kolejność zatwierdzeń, zgniatanie zatwierdzeń, itp.)
ba7688a (HEAD, master) C5
44085d5 C4
961390d C3
85f59ab C2
4516164 C1
0e783a3 C0
W tym miejscu ważne jest, aby zauważyć, że skróty zatwierdzania są różne. Jest to oczekiwane zachowanie, ponieważ zmieniłeś coś (cokolwiek) w nich. To jest w porządku, ALE:
Próba pchnięcia spowoduje wyświetlenie błędu (i podpowiedź, że powinieneś uruchomić 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.
Jeśli biegniemy git pull
, widzimy ten dziennik:
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
Lub pokazane w inny sposób:
A teraz mamy lokalnie zduplikowane zatwierdzenia. Gdybyśmy mieli uruchomić git push
, wysłalibyśmy je na serwer.
Aby uniknąć dotarcia do tego etapu, mogliśmy biec git push --force
(gdzie zamiast tego biegliśmy git pull
). To bez problemu wysłałoby nasze zatwierdzenia z nowymi hashami na serwer. Aby rozwiązać problem na tym etapie, możemy cofnąć się do stanu sprzed uruchomienia git pull
:
Spójrz na reflog ( git reflog
), aby zobaczyć, jaki był skrót zatwierdzenia przed uruchomieniem 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
Powyżej widzimy, że ba7688a
było to zobowiązanie, na którym byliśmy przed uruchomieniem git pull
. Z tym hashem commita w ręku możemy zresetować z powrotem do tego ( git reset --hard ba7688a
), a następnie uruchomić git push --force
.
Gotowe.
Ale czekaj, kontynuowałem pracę na podstawie zduplikowanych zatwierdzeń
Jeśli w jakiś sposób nie zauważyłeś, że zatwierdzenia zostały zduplikowane i kontynuowałeś pracę nad zduplikowanymi zatwierdzeniami, naprawdę narobiłeś sobie bałaganu. Rozmiar bałaganu jest proporcjonalny do liczby zatwierdzeń, które masz na szczycie duplikatów.
Jak to wygląda:
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
Lub pokazane w inny sposób:
W tym scenariuszu chcemy usunąć zduplikowane zatwierdzenia, ale zachować zmiany, które oparliśmy na nich - chcemy zachować C6 do C10. Podobnie jak w przypadku większości rzeczy, można to zrobić na kilka sposobów:
Zarówno:
- Utwórz nową gałąź przy ostatnim zduplikowanym zatwierdzeniu 1 ,
cherry-pick
każdym zatwierdzeniu (włącznie z C6 do C10) na tę nową gałąź i traktuj tę nową gałąź jako kanoniczną.
- Uruchom
git rebase --interactive $commit
, gdzie $commit
jest zatwierdzeniem przed obydwoma zduplikowanymi zatwierdzeniami 2 . Tutaj możemy wprost usunąć linie dla duplikatów.
1 To nie ma znaczenia, który z nich wybrać, albo ba7688a
czy 2a2e220
działają poprawnie.
2 W tym przykładzie byłoby to 85f59ab
.
TL; DR
Ustaw advice.pushNonFastForward
na false
:
git config --global advice.pushNonFastForward false