master branch i „origin / master” rozeszły się, jak „oddzielić” oddziały?

964

W jakiś sposób mój mistrz i mój początek / oddział master rozeszły się.
Właściwie nie chcę, żeby się rozeszli.

Jak mogę zobaczyć te różnice i „scalić” je?

Szczery
źródło
2
co rozumiesz przez rozbieżność? czy bazujesz na swoim mistrzu po pchnięciu go?
hasen
13
Otrzymuję komunikat: „Twoja gałąź i„ origin / master ”rozeszły się, # i odpowiednio 1 i 1 inny zatwierdzenie (-a).”
Frank
Zaktualizowałem swoją odpowiedź, aby odzwierciedlić komunikat ostrzegawczy „rozbieżny”.
VCC
Przyjęta odpowiedź na inne pytanie może być również pomocna w rozwiązywaniu niektórych przypadków, w których może się to pojawić (np. Próbujesz przenieść swojego mistrza, ale już został on przekazany): stackoverflow.com/questions/2862590/…
lindes
8
Wyjaśnienie na tym blogu pomogło mi nieskończenie bardziej niż jakakolwiek odpowiedź poniżej: sebgoo.blogspot.com/2012/02/…

Odpowiedzi:

1013

Możesz przejrzeć różnice za pomocą:

git log HEAD..origin/master

przed wyciągnięciem go (pobierz + scal) (zobacz także „Jak zdobyć Gita, aby zawsze pobierał z określonej gałęzi?” )


Gdy masz wiadomość typu:

„Twój oddział i„ origin / master ”rozeszły się, # i odpowiednio 1 i 1 inny zatwierdzenie (-a).”

, sprawdź, czy musisz zaktualizowaćorigin . Jeśli originjest aktualny, to niektóre zatwierdzenia zostały wypchnięte originz innego repozytorium, podczas gdy tworzyłeś własne zatwierdzenia lokalnie.

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \
                    C  master (your work)

Opierałeś zatwierdzenie C na zatwierdzeniu A, ponieważ była to najnowsza praca, którą ściągnąłeś wtedy w górę.

Jednak zanim spróbowałeś cofnąć się do źródła, ktoś inny pchnął zatwierdzenie B.
Historia rozwoju rozdzieliła się na osobne ścieżki.

Następnie możesz scalić lub zmienić bazę. Zobacz Pro Git: Rozgałęzianie Git - Rebasing, aby uzyskać szczegółowe informacje.

Łączyć

Użyj polecenia git merge:

$ git merge origin/master

To mówi Gitowi, aby zintegrował zmiany z origin/mastertwojej pracy i utworzył zatwierdzenie scalania.
Wykres historii wygląda teraz tak:

... o ---- o ---- A ---- B  origin/master (upstream work)
                   \      \
                    C ---- M  master (your work)

Nowe scalenie, zatwierdzenie M, ma dwoje rodziców, z których każdy reprezentuje jedną ścieżkę rozwoju, która doprowadziła do zawartości zapisanej w tym zatwierdzeniu.

Zauważ, że historia za M jest teraz nieliniowa.

Rebase

Użyj polecenia git rebase:

$ git rebase origin/master

To mówi Gitowi, aby powtórzył zatwierdzenie C (twoją pracę) tak, jakbyś oparł go na zatwierdzeniu B zamiast A. Użytkownicy
CVS i Subversion rutynowo dokonują zmian swoich lokalnych zmian w stosunku do poprzedniej pracy, gdy aktualizują się przed zatwierdzeniem.
Git po prostu dodaje wyraźną separację między krokami zatwierdzenia i zmiany bazy.

Wykres historii wygląda teraz tak:

... o ---- o ---- A ---- B  origin/master (upstream work)
                          \
                           C'  master (your work)

Commit C 'jest nowym zatwierdzeniem utworzonym przez polecenie git rebase.
Różni się od C na dwa sposoby:

  1. Ma inną historię: B zamiast A.
  2. Jego zawartość uwzględnia zmiany zarówno w B, jak i C; jest taki sam jak M z przykładu scalania.

Zauważ, że historia C 'jest nadal liniowa.
Wybraliśmy (na razie), aby pozwolić tylko na historię liniową w cmake.org/cmake.git.
Takie podejście pozwala zachować wcześniej używany przepływ pracy oparty na CVS i może ułatwić przejście.
Próba wypchnięcia C 'do naszego repozytorium zadziała (zakładając, że masz uprawnienia i nikt nie pchnął cię podczas bazowania).

Polecenie git pull zapewnia skrótowy sposób pobierania z miejsca początkowego i bazowania na nim pracy lokalnej:

$ git pull --rebase

Łączy to powyższe kroki pobierania i zmiany bazy w jedno polecenie.

VonC
źródło
5
Znalazłem to, szukając tego samego problemu. Czy możesz wyjaśnić, dlaczego „git reset - hard HEAD” nie rozwiązał problemu?
Neth
12
@Neth: ponieważ nie chodzi o modyfikacje etapowe (tj. Modyfikacje obecne w indeksie, ale jeszcze nie zatwierdzone ), ale o lokalne zatwierdzenia (które różnią się od zatwierdzeń obecnych na pilocie). git reset --hard HEADusuną tylko wszelkie niezatwierdzone modyfikacje lokalne i nie zrobią nic, aby pogodzić różnice między zatwierdzeniami lokalnymi i zdalnymi . Tylko scalenie lub rebase zgromadzi dwa zestawy commits (lokalny i zdalny).
VonC
4
Wow, dzięki za tę niesamowitą odpowiedź. Przypadkowo zrobiliśmy „git pull” bez „--rebase”, a „git rebase origin / master” było właśnie naprawą!
mrooney
3
Co powiesz na - chcę po prostu zignorować / zrzucić moje lokalne zmiany i być w lokalnym oddziale, w którym znajduje się pilot? Innymi słowy, chcę masterwskazać Bna twój przykład.
CygnusX1
23
@ CygnusX1, który byłby git reset --hard origin/masterjak wspomniano w odpowiedzi poniżej: stackoverflow.com/a/8476004/6309
VONC
725

Miałem to i jestem zdumiony, co go spowodowało, nawet po przeczytaniu powyższych odpowiedzi. Moje rozwiązanie miało zrobić

git reset --hard origin/master

Potem to po prostu resetuje moją (lokalną) kopię master (która, jak zakładam, jest spieprzona) do właściwego punktu, co reprezentuje (zdalne) origin / master.

OSTRZEŻENIE : Utracisz wszystkie zmiany, które nie zostały jeszcze wypchnięte origin/master.

skiphoppy
źródło
21
tak, to trochę przypomina opcję manekinów, ale jeśli nie ma realnego niebezpieczeństwa i jesteś tutaj, aby szybko naprawić - to działa (dla mnie i tak)
PandaWood
7
Wymaga to wcześniejszego przebywania w gałęzi master („git checkout master”).
niebieskawy 11.04.13
Zdarzyło mi się to raz, kiedy otrzymałem najnowszą wersję, a następnie ktoś inny naciskał na początek, co spowodowało cofnięcie poprzedniego zatwierdzenia w początku. Więc mój lokalny oddział miał cofnięte zatwierdzenie, a kiedy próbowałem wyciągnąć najnowsze z miejsca pochodzenia, mówiłem, że muszę się połączyć. W tym przypadku po prostu sensowne było zresetowanie --hard origin / (branch), ponieważ problem został już naprawiony w oryginale.
Landon Poch
96
Prawdopodobnie powinieneś ostrzec użytkowników, że w ten sposób stracą wszystkie zmiany, które nie zostały jeszcze wypchnięte
Pedro Loureiro,
6
@PedroLoureiro Commits są naprawdę zagubione, wciąż możesz je znaleźć git refloglub zobaczyć gitk --all. Ale oczywiście twardy reset to coś innego niż rebase.
sebkraemer
52
git pull --rebase origin/master 

to pojedyncze polecenie, które może ci pomóc przez większość czasu.

Edycja: Pobiera zatwierdzenia z źródła / wzorca i stosuje zmiany do nowo pobranej historii oddziału.

asitmoharna
źródło
89
proszę wspomnieć o tym, co robi polecenie, w przeciwnym razie ludzie mogliby go uruchomić i skończyć
zepsuciem
1
Jeśli nie ma problemu, powinieneś skończyć ze swoim masterem zawierającym wszystkie zmiany origin / master plus wszystkie lokalne zatwierdzenia zostaną odtworzone na nim. Wydaje mi się dobry.
Philipp Claßen,
7
Z wyjątkiem sytuacji, gdy istnieją prawdziwe różnice i pozostawia cię w przerwanej bazie.
ffledgling
Daje to błąd: błąd: nie można scalić zmian. Łata nie powiodła się w 0024 Modele zapytania i odpowiedzi
IgorGanapolsky
32

Znalazłem się w tej sytuacji, kiedy próbowałem zmienić bazę gałęzi śledzącej gałąź zdalną i próbowałem zmienić jej podstawę na master. W tym scenariuszu, jeśli spróbujesz dokonać zmiany bazy, najprawdopodobniej zauważysz, że twoja gałąź jest rozbieżna i może stworzyć bałagan, który nie jest dla git nubees!

Powiedzmy, że jesteś w gałęzi my_remote_tracking_branch, która została rozgałęziona od master

$ git status

# Na gałęzi my_remote_tracking_branch

nic do zatwierdzenia (czysty katalog roboczy)

A teraz próbujesz zmienić bazę na master jako:

git rebase master

ZATRZYMAJ SIĘ TERAZ i zaoszczędź sobie kłopotów! Zamiast tego użyj scalania jako:

Git Merge Master

Tak, otrzymasz dodatkowe zobowiązania w swoim oddziale. Ale jeśli nie masz ochoty na „nierozdzielanie” gałęzi, będzie to znacznie płynniejszy przepływ pracy niż ponowne bazowanie. Zobacz ten blog, aby uzyskać bardziej szczegółowe wyjaśnienia.

Z drugiej strony, jeśli twoja gałąź jest tylko gałęzią lokalną (tzn. Nie została jeszcze przekazana do żadnego zdalnego), zdecydowanie powinieneś zrobić rebase (i twoja gałąź nie będzie się rozbierać w tym przypadku).

Teraz, jeśli to czytasz, bo już w „rozeszły” scenariusz z powodu takiego rebase, można wrócić do ostatniego zatwierdzenia od pochodzenia (czyli w stanie un-odbiegał) za pomocą:

git reset --hard origin / my_remote_tracking_branch

paneer_tikka
źródło
5
Zasadą jest stosowanie, rebasejeśli gałąź, którą publikujesz, nie została opublikowana (i jest używana przez inne osoby). W przeciwnym razie użyj merge. Jeśli dokonujesz zmiany bazy już opublikowanych (i używanych) gałęzi, musisz koordynować spisek, aby przepisać historię dla każdego programisty, który używał twojej gałęzi.
Mikko Rantalainen
1
Niestety nie przeczytałem tej wiadomości przed zrobieniem git rebase master...
Witalij Isaev
Jeśli wykonam Git Rebase Master, gdy jestem na gałęzi „Foobar”, to technicznie Foobar jest rozbieżny od Origin / Foobar, dopóki nie zrobię Git Push-F, prawda?
powtórka
1
git reset --hard origin/my_remote_tracking_branchjest to, co naprawdę działało
roothahn
24

W moim przypadku jest to, co zrobiłem, aby spowodować rozbieżną wiadomość: zrobiłem, git pushale potem git commit --amenddodałem coś do wiadomości zatwierdzenia. Potem też zrobiłem kolejne zatwierdzenie.

W moim przypadku oznaczało to po prostu, że pochodzenie / master było nieaktualne. Ponieważ wiedziałem, że nikt inny nie dotyka źródła / mistrza, poprawka była trywialna: git push -f (gdzie -foznacza siłę)

Darren Cook
źródło
8
+1 za, git push -faby zastąpić zmiany poprzednio zatwierdzone i przekazane do źródła. Jestem też pewien, że nikt inny nie dotknął repozytorium.
zacharydl
4
Bardzo ryzykowne polecenie. Napisz krótką informację dotyczącą współczynnika ryzyka polecenia.
J4cK,
1
@Trickster: Już opisałem ryzyko: „ponieważ wiedziałem, że nikt inny nie dotyka pochodzenia / mistrza”. Uważam, że w takim przypadku nie jest to ryzykowne polecenie.
Darren Cook
1
Jeśli ktoś zobowiązuje się do nadrzędnego, a następnie jedna osoba uruchomi polecenie git push -f, wówczas jest to polecenie wysokiego ryzyka
J4cK
11

W moim przypadku wprowadziłem zmiany, origin/mastera potem zdałem sobie sprawę, że nie powinienem tego zrobić :-( Było to skomplikowane przez fakt, że zmiany lokalne były w poddrzewie. Wróciłem do ostatniego dobrego zatwierdzenia przed „złym” lokalnym zmiany (przy użyciu SourceTree), a następnie dostałem komunikat o rozbieżności.

Po naprawieniu mojego bałaganu lokalnie (tutaj szczegóły nie są ważne) chciałem „cofnąć się w czasie” do zdalnej origin/mastergałęzi, aby masterponownie zsynchronizowała się z lokalną . Rozwiązaniem w moim przypadku było:

git push origin master -f

Zwróć uwagę na -fprzełącznik (wymuszony). Spowodowało to usunięcie „złych zmian”, które zostały popchnięte origin/masterprzez pomyłkę, a teraz oddziały lokalne i zdalne są zsynchronizowane.

Pamiętaj, że jest to potencjalnie destrukcyjna operacja, więc wykonuj ją tylko wtedy, gdy masz 100% pewności, że „cofnięcie” zdalnego urządzenia nadrzędnego jest w porządku.

Laryx Decidua
źródło
Zawsze przydatny, ale na pewno nie odpowiada na pytanie.
Thibault D.
1
@ThibaultD. nawet jeśli nie, to właśnie tego szukałem.
Neil Chowdhury,
Dostaję You are not allowed to force push code to a protected branch on this project.. Próbuję naciskać na mój widelec.
BanAnanas
Musiałem usunąć ochronę na repozytorium gitlab stackoverflow.com/questions/32246503/...
BanAnanas
5

Wiem, że jest tu wiele odpowiedzi, ale myślę, że git reset --soft HEAD~1zasługuje na uwagę, ponieważ pozwala zachować zmiany w ostatnim zatwierdzeniu lokalnym (nie wypchniętym) podczas rozwiązywania rozbieżnego stanu. Myślę, że jest to bardziej uniwersalne rozwiązanie niż pull rebase, ponieważ lokalne zatwierdzenie może zostać przejrzane, a nawet przeniesione do innego oddziału.

Klawisz używa --softzamiast szorstkiego --hard. Jeśli jest więcej niż 1 zatwierdzenie, HEAD~xpowinna działać odmiana . Oto więc wszystkie kroki, które rozwiązały moją sytuację (miałem 1 zatwierdzenie lokalne i 8 zatwierdzeń w trybie zdalnym):

1) git reset --soft HEAD~1 cofnąć zatwierdzenie lokalne. Do kolejnych kroków użyłem interfejsu w SourceTree, ale myślę, że następujące polecenia powinny również działać:

2) git stash ukryć zmiany od 1). Teraz wszystkie zmiany są bezpieczne i nie ma już rozbieżności.

3) git pull aby uzyskać zdalne zmiany.

4) git stash pop lub git stash applyzastosować ostatnie ukryte zmiany, a następnie, w razie potrzeby, nowe zatwierdzenie. Ten krok jest opcjonalny, wraz z 2) , gdy chcesz usunąć zmiany w lokalnym zatwierdzeniu. Ponadto, jeśli chcesz zatwierdzić do innej gałęzi, ten krok należy wykonać po przełączeniu do żądanej gałęzi.

Bianca Daniciuc
źródło
Właściwie w dzisiejszych czasach i tak pull --rebasebędą się automatycznie chować. stackoverflow.com/a/30209750/6309
VonC
4

Aby wyświetlić różnice:

git difftool --dir-diff master origin/master

Spowoduje to wyświetlenie zmian lub różnic między dwiema gałęziami. W araxis (My favourite) wyświetla go w stylu porównywania folderów. Pokazuje każdy ze zmienionych plików. Następnie mogę kliknąć plik, aby wyświetlić szczegóły zmian w pliku.

C Johnson
źródło
1
Ciekawe użycie git-dir: +1
VonC
3

W moim przypadku było to spowodowane brakiem rozwiązania konfliktu.

Problem został spowodowany uruchomieniem git pullpolecenia. Zmiany w źródle doprowadziły do ​​konfliktów z moim lokalnym repozytorium, które rozwiązałem. Jednak ich nie popełniłem. Rozwiązaniem w tym momencie jest zatwierdzenie zmian ( git commitplik rozwiązany)

Jeśli zmodyfikowałeś również niektóre pliki od czasu rozwiązania konfliktu, git statuspolecenie wyświetli lokalne modyfikacje jako lokalne niestopniowe modyfikacje i scali rozwiązanie jako lokalne modyfikacje etapowe. Można to właściwie rozwiązać, najpierw zatwierdzając zmiany ze scalenia git commit, a następnie dodając i zatwierdzając zmiany niestacjonarne jak zwykle (np. Przez git commit -a).

Mohammad Reza Esmaeilzadeh
źródło
0

Miałem tę samą wiadomość, gdy próbowałem edytować ostatnią wiadomość zatwierdzenia, już wypchniętego zatwierdzenia, używając: git commit --amend -m "New message" Kiedy wypchnąłem zmiany przy użyciu, git push --force-with-lease repo_name branch_name nie było żadnych problemów.

LoveForDroid
źródło
0

Napotkałem ten problem, gdy utworzyłem gałąź na podstawie gałęzi A przez

git checkout -b a

a następnie ustawiam strumień rozgałęzienia A na początek B przez

git branch -u origin/B

Następnie otrzymałem powyższy komunikat o błędzie.

Jednym ze sposobów rozwiązania tego problemu było dla mnie:

  • Usuń gałąź a
  • Utwórz nowy oddział b
git checkout -b b origin/B
YanQing
źródło