Git pull skutkuje nieistotnymi komunikatami „Merge branch” w dzienniku zatwierdzeń

110

Pracuję z innym programistą nad projektem i używamy Github jako naszego zdalnego repozytorium. Jestem na Macu z git 1.7.7.3, on na Windowsie używa git 1.7.6.

Oto, co się dzieje

  1. Jeden z nas (nazwijmy go deweloperem A, ale nie ma znaczenia który) wypycha zestaw zatwierdzeń do GitHub.
  2. Drugi (programista B) wykonuje pewne lokalne zatwierdzenia.
  3. B robi a git pull.
  4. B robi a git push.
  5. Patrząc na dziennik historii zmian , widzę Merge branch „master” na github.com:foo/bar

Dziennik zatwierdzeń jest z czasem zaśmiecony komunikatami „Merge branch”, a także pokazuje programistę B jako zatwierdzającego zmiany wprowadzone przez programistę A. Jedynym sposobem, w jaki udało nam się zapobiec temu problemowi, jest wykonanie a git pull --rebasew kroku 3, ale nie wiem, jakie skutki uboczne wprowadzi zmiana bazy. Po raz pierwszy pracuję nad repozytorium git dla wielu programistów, więc czy to tylko normalne zachowanie? Jakieś przemyślenia, jak rozwiązać ten problem?

mshafrir
źródło
2
Możesz wyświetlić dziennik bez git log --no-merges
połączeń

Odpowiedzi:

88

Zobowiązanie, które widzisz, jest w porządku. pullSkutecznie działa git fetch, a następnie git mergetak scalanie zwykle dzieje podczas uruchamiania git pull.

Alternatywa polegająca na zmianie bazy zamiast scalania jest możliwa, ale zwykle należy jej unikać. Rebasing pozwala zachować liniową historię, ale także usuwa wszelkie informacje o rozgałęzieniach, które pierwotnie miały miejsce. Spowoduje to również przepisanie historii bieżącej gałęzi, odtworzenie wszystkich zatwierdzeń, które nie są zawarte w gałęzi docelowej (w twoim przypadku zdalnej). Ponieważ odtworzone zatwierdzenia są różnymi zatwierdzeniami, może to spowodować wiele zamieszania podczas opracowywania razem z innymi, zwłaszcza gdy ludzie już wyewidencjonowali części tych zatwierdzeń, zanim zostaną przepisane (na przykład z odgałęzieniami funkcji). Dlatego z reguły nigdy nie należy przepisywać żadnego zatwierdzenia, które zostało już przesłane.

Zobowiązania, które widzisz, łączą dwie (lub więcej) gałęzie. Bardzo dobrze jest mieć zatwierdzenie, które nie robi nic innego niż scalanie wielu gałęzi. W rzeczywistości jest to bardzo jasne, gdy masz zatwierdzenie scalające, które łączy gałęzie, gdy patrzysz na historię. W porównaniu z rebasingiem, scalanie pozwala również efektywnie zobaczyć oryginalną historię w takiej postaci, w jakiej została opracowana, w tym faktyczne gałęzie, które współistniały.

Krótko mówiąc: tak, posiadanie zatwierdzeń scalających jest w porządku i nie należy się nimi martwić.

szturchać
źródło
2
Bardzo dobra odpowiedź. Sam wypróbowałem styl rebase, ponieważ był zalecany w niektórych wytycznych dotyczących wkładu do projektów open source i spowodował problemy. Nowy członek zespołu też miał to samo. Myślę, że opcja rebase nie jest przeznaczona dla zespołów pracujących razem przez cały dzień, ale jest odpowiednia dla projektów, które mają głównych współpracowników i innych współpracowników, którzy po prostu przesyłają poprawki. Powinni dobrze pobrać główne repozytorium i ponownie bazować na swoich zmianach tuż przed wysłaniem żądania ściągnięcia.
Meligy
2
@sTodorov Jeśli nie ma nowych zmian, część ściągania ściągania nic nie da, ale scalanie jest nadal wykonywane. Jeśli więc Twój obecny lokalny oddział nie jest aktualny, nowe zmiany zostaną scalone z Twoim oddziałem. A jeśli nie może wykonać szybkiego scalenia do przodu (jeśli masz rozbieżne zatwierdzenia), utworzy zatwierdzenie scalające.
poke
28
Ta odpowiedź sprawia, że ​​wydaje się, że użycie rebase, jak opisał OP, jest niebezpieczne, ale tak nie jest. Rebasing w kroku 3 nie zmienia całej historii. Tylko lokalne zatwierdzenia, które nie zostały przesłane, są przepisywane przez ponowne zastosowanie na nowym HEAD (najnowszym zatwierdzeniu przesłanym do tej gałęzi). Zapobiega to zbędnym zatwierdzeniom scalania i nie ma innych skutków ubocznych.
bob esponja
1
@bobesponja Wszystkie zatwierdzenia, które nie znajdują się w ściągniętej gałęzi zdalnej, są przepisywane. Może to obejmować opublikowane zatwierdzenia z innych gałęzi, np. Z gałęziami cech, do których inni mogli już mieć dostęp. W związku z tym tak, zmiana bazy bez zastanawiania się nad tym, co jest podstawą, jest nieco niebezpieczna.
szturchnij
1
@bobesponja Tak, jeśli publikujesz swoją gałąź funkcji wcześnie (ponieważ inni nad nią pracują lub po prostu jako kopia zapasowa), nie powinieneś zmieniać jej bazy, ponieważ inni mogli już ją pobrać. A zatem zbuntowanie się - jak sam mówisz - jest sprzeczne z wytycznymi dotyczącymi ponownego założenia, które przedstawiłem w mojej odpowiedzi. Jeśli jednak nie publikujesz swoich zatwierdzeń, zmiana bazy jest w porządku, jeśli chcesz i nie przeszkadza ci linearna historia. Ale to zależy od tego, jak pracujesz, więc ogólną odpowiedzią jest unikanie tego, chyba że jest to naprawdę bezpieczne. Przy okazji. Poprawiłem swoją odpowiedź, więc jeśli problem zostanie rozwiązany, będę wdzięczny, jeśli wycofasz swój głos przeciw.
poke
48

Ta odpowiedź została poprawiona, ponieważ moje rozumienie, diagramy i wnioski były niepoprawne.


git pullpowoduje, że merge zatwierdza się, ponieważ git jest scalany. Można to zmienić, ustawiając swoje gałęzie tak, aby używały rebase zamiast scalania. Użycie rebase zamiast scalania podczas ściągania zapewnia bardziej liniową historię do współdzielonego repozytorium. Z drugiej strony, zmiany typu merge pokazują równoległe prace rozwojowe w gałęzi.

Na przykład dwie osoby pracują w tej samej branży. Oddział zaczyna się jako:

...->C1

Pierwsza osoba kończy pracę i przepycha się do gałęzi:

...->C1->C2

Druga osoba kończy pracę i chce naciskać, ale nie może, ponieważ musi zaktualizować. Lokalne repozytorium dla drugiej osoby wygląda następująco:

...->C1->C3

Jeśli pull jest ustawiony na scalanie, repozytorium drugiej osoby będzie wyglądać jak.

...->C1->C3->M1
      \      /
       ->C2->

Gdzie M1 jest zatwierdzeniem scalającym. Ta nowa historia gałęzi zostanie przeniesiona do repozytorium. Jeśli zamiast tego pull jest ustawiony na ponowne bazowanie, lokalne repozytorium wyglądałoby następująco:

...->C1->C2->C3

Nie ma zatwierdzenia łączenia. Historia stała się bardziej linearna.

Oba wybory odzwierciedlają historię branży. git pozwala wybrać preferowaną historię.

Rzeczywiście istnieją miejsca, w których rebase może powodować problemy ze zdalnymi oddziałami. To nie jest jeden z tych przypadków. Wolimy używać rebase, ponieważ upraszcza to już skomplikowaną historię gałęzi, a także pokazuje wersję historii w odniesieniu do współdzielonego repozytorium.

Możesz ustawić branch.autosetuprebase = always tak, aby git automatycznie ustalał twoje zdalne gałęzie jako rebase zamiast master.

git config --global branch.autosetuprebase always

To ustawienie powoduje, że git automatycznie tworzy ustawienie konfiguracyjne dla każdej zdalnej gałęzi:

branch.<branchname>.rebase=true

Możesz ustawić to samodzielnie dla swoich zdalnych oddziałów, które są już skonfigurowane.

git config branch.<branchname>.rebase true

Chciałbym podziękować @LaurensHolst za przesłuchanie i kontynuację moich poprzednich wypowiedzi. Z pewnością dowiedziałem się więcej o tym, jak działa git z zatwierdzeniami pull i merge.

Więcej informacji na temat zatwierdzeń scalających można znaleźć w artykule Współtworzenie projektu w ProGit-Book . Sekcja Private Small Team pokazuje zatwierdzenia scalenia.

Bill Door
źródło
7
„Użycie rebase zamiast scalania podczas ściągania zapewnia poprawną historię do współużytkowanego repozytorium. Korzystanie z funkcji scalania zapewnia fałszywą historię ”. - Jakie jest uzasadnienie tego dość śmiałego stwierdzenia? Nie ma mowy, żeby historia z fuzjami była „fałszywą historią”. Jest to dokładne przedstawienie kolejności, w jakiej się wydarzyły. To, co robisz, zmieniając bazę, tak naprawdę zmienia historię, tworząc jej nieco bardziej liniową wersję. Poświęcasz dokładność na rzecz estetyki. Może coś, co wolisz robić, ale w żaden sposób nie bardziej prawdziwe.
Laurens Holst
2
Używanie rebase zamiast scalania nie poświęca dokładności na rzecz estetyki. Używamy --no-ff do łączenia, więc estetyka nie jest wymaganiem. Dokładność to pragnienie. Rebase zapewnia taką dokładność.
Bill Door
2
W jaki sposób przeredagowana historia jest dokładniejsza? Nie wyjaśniasz tego, a ja nie widzę, jak by to było.
Laurens Holst
1
Historia jest odzwierciedleniem czasu, w którym wystąpiły zatwierdzenia we wspólnym repozytorium. Pewnego dnia 1, udostępnione repozytorium zobaczyło zatwierdzenie C2. Drugiego dnia udostępnione repozytorium widzi commit C3. Gdyby C3 pojawił się przed C2, to odbicie czasu nie byłoby poprawne. C3 nie pojawił się przed C2. Wszystko, co robi rebase, to reorganizacja zatwierdzeń w lokalnym repozytorium, aby odpowiednio odzwierciedlić historię wyświetlaną przez współdzielone repozytorium.
Bill Door
6
Twoje pytania skłoniły mnie do zweryfikowania mojego rozumienia zobowiązań dotyczących scalania. Mój schemat jest nieprawidłowy. Koryguję dyskusję. Moje wnioski również są błędne. Historia rebase i scalania jest równie poprawna. Możesz dokonać własnego wyboru.
Bill Door
11

Możesz to zrobić:

git pull --rebase

Jednak to zawsze umieszcza Twoje zmiany na wierzchu plików współpracowników. Ale nie otrzymasz żadnej zanieczyszczającej wiadomości o scalaniu.

wytworny
źródło
9

W rzeczywistości istnieje znacznie prostsza odpowiedź na to pytanie. Po prostu poproś programistę B o wykonanie pociągnięcia PRZED podjęciem decyzji. Zapobiegnie to tym zatwierdzeniom scalającym, ponieważ są one spowodowane historią utworzoną w lokalnym repozytorium z lokalnego zatwierdzenia próbującego scalić się z historią zatwierdzeń w zdalnym repozytorium. Jeśli podczas wyciągania pojawi się komunikat mówiący coś w rodzaju „zmiany zostaną nadpisane”, oznacza to po prostu, że oboje dotknęliście tego samego pliku, więc zrób:

git stash
git pull
git stash pop

wtedy możesz rozwiązać wszelkie konflikty scalania, jeśli takie istnieją.

Łukasz
źródło
Najbardziej irytujące i niespokojne są właśnie konflikty scalania. Raczej tego
Green
1
@Green Jeśli martwisz się konfliktami scalania, to nawet git pull nie jest inny.
Zoso
Z wyjątkiem tego jednego razu, kiedy zapomnisz o tym stashprzed sobą pull. Ugh git wymaga, żebym cały czas był na szczycie mojej gry.
linuxNoob
Potrzeba git pull --rebaseintegracji zdalnych zmian przed lokalne, niezależnie.
vonbrand
7

Wykonanie polecenia git pull spowoduje wstawienie wiadomości „Merge branch”, po prostu to robi. Wykonując git pull, połączyłeś zdalną gałąź z lokalną.

Kiedy wykonujesz polecenie git pull i wystąpią konflikty, dziennik git pokaże aktualizacje plików będących w konflikcie jako pochodzące od użytkownika, który rozwiązał konflikty. Zakładam, że dzieje się tak, ponieważ osoba, która rozwiązuje konflikt, ponownie zatwierdza plik.

O ile wiem, właśnie tak działa git i nie ma sposobu na obejście tego.

Rebasing zniszczy historię git, więc nie będziesz w stanie zobaczyć, kiedy nastąpiło połączenie.

kclair
źródło