Niezupełnie związane z tą odpowiedzią, ale porzuciłbym git pull, co po prostu biegnie git fetchza nim git merge. Wykonujesz trzy scalenia, co spowoduje, że Twój Git uruchomi trzy operacje pobierania, podczas gdy jedno pobieranie jest wszystkim, czego potrzebujesz. W związku z tym:
git fetch origin # update all our origin/* remote-tracking branches
git checkout demo # if needed -- your example assumes you're on it
git merge origin/demo # if needed -- see below
git checkout master
git merge origin/master
git merge -X theirs demo # but see below
git push origin master # again, see below
Kontrolowanie najtrudniejszych połączeń
Najciekawsza część tutaj jest git merge -X theirs. Jak zauważył root545 , -Xopcje są przekazywane do strategii scalania, a zarówno recursivestrategia domyślna , jak i resolvestrategia alternatywna przyjmują -X ourslub -X theirs(jedna lub druga, ale nie obie). Aby jednak zrozumieć, co robią, musisz wiedzieć, w jaki sposób Git wyszukuje i leczy konflikty .
Konflikt scalania może wystąpić w pewnym pliku 1, gdy wersja podstawowa różni się zarówno od wersji bieżącej (nazywanej również --ourswersją lokalną, HEAD lub ), jak i innej (nazywanej również zdalną lub --theirs) wersją tego samego pliku. Oznacza to, że podczas scalania zidentyfikowano trzy wersje (trzy zatwierdzenia): podstawową, naszą i ich. Wersja „podstawowa” pochodzi z podstawy scalania między naszym zatwierdzeniem a ich zatwierdzeniem, jak można znaleźć na wykresie zatwierdzeń (aby uzyskać więcej informacji na ten temat, zobacz inne wpisy StackOverflow). Git znalazł wtedy dwa zestawy zmian: „co zrobiliśmy” i „co zrobili”. Te zmiany są (na ogół) widoczne wiersz po wierszu, czysto tekstowe . Git nie ma prawdziwego zrozumienia zawartości plików; jest to po prostu porównanie każdego wiersza tekstu.
Te zmiany są tym, co widzisz w git diffwynikach i jak zawsze mają również kontekst . Możliwe, że rzeczy, które zmieniliśmy, znajdują się w innych wierszach niż te, które zmieniły, więc zmiany wydają się nie kolidować, ale kontekst również się zmienił (np. Z powodu naszej zmiany znajdującej się blisko góry lub dołu pliku, aby plik skończył się w naszej wersji, ale w ich dodali też więcej tekstu na górze lub na dole).
Jeśli zmiany się zdarzyć na różnych liniach, na przykład, zmieniamy colorsię colourna linii 17 i zmieniają fredsię barneyna linii 71-to nie ma konfliktu: Git prostu wykonuje zarówno zmian. Jeśli zmiany zachodzą w tych samych wierszach, ale są identyczne , Git pobiera jedną kopię zmiany. Tylko jeśli zmiany są w tych samych wierszach, ale są to różne zmiany lub ten specjalny przypadek interferencji kontekstu, pojawia się konflikt modyfikacji / modyfikacji.
-X oursI -X theirsopcje powiedzieć Git jak rozwiązać ten konflikt, poprzez wskazanie tylko jednego z dwóch zmian: nasza, czy ich. Ponieważ powiedziałeś, że scalasz demo(ich) z master(naszymi) i chcesz zmiany z demo, na pewno chcesz -X theirs.
-XJednak ślepe stosowanie jest niebezpieczne. Tylko dlatego, że nasze zmiany nie kolidowały z linią po linii, nie oznacza, że nasze zmiany w rzeczywistości nie powodują konfliktu! Jeden klasyczny przykład występuje w językach z deklaracjami zmiennych. Podstawowa wersja może zadeklarować nieużywaną zmienną:
int i;
W naszej wersji usuwamy nieużywaną zmienną, aby ostrzeżenie kompilatora zniknęło - aw swojej wersji dodają pętlę kilka wierszy później, używając ijako licznika pętli. Jeśli połączymy te dwie zmiany, wynikowy kod nie będzie się już kompilować. Ta -Xopcja nie jest tutaj pomocna, ponieważ zmiany są w różnych wierszach .
Jeśli masz zestaw testów automatycznych, najważniejszą rzeczą do zrobienia jest uruchomienie testów po scaleniu. Możesz to zrobić po zatwierdzeniu i naprawić później, jeśli to konieczne; lub możesz to zrobić przed--no-commit zatwierdzeniem , dodając do git mergepolecenia. Szczegóły tego wszystkiego pozostawimy innym postom.
1 Możesz również uzyskać konflikty w odniesieniu do operacji „całego pliku”, np. Być może poprawiamy pisownię słowa w pliku (tak, że mamy zmianę), a oni usuwają cały plik (tak, że mają usunąć). Git nie rozwiąże samodzielnie tych konfliktów, niezależnie od -Xargumentów.
Wykonywanie mniejszej liczby połączeń i / lub inteligentniejszych połączeń i / lub używanie rebase
W obu naszych sekwencjach poleceń występują trzy połączenia. Pierwszym jest przeniesienie origin/demodo lokalnego demo(twoje zastosowania, git pullktóre, jeśli twój Git jest bardzo stary, nie zaktualizują się, origin/demoale dadzą ten sam wynik końcowy). Drugi jest doprowadzenie origin/masterdo master.
Nie jest dla mnie jasne, kto aktualizuje demoi / lub master. Jeśli napiszesz swój własny kod we własnej demogałęzi, a inni piszą kod i wypychają go do demogałęzi origin, to scalanie w pierwszym kroku może powodować konflikty lub powodować rzeczywiste scalanie. Najczęściej lepiej jest użyć rebase niż merge, aby połączyć pracę (trzeba przyznać, że to kwestia gustu i opinii). Jeśli tak, możesz użyć git rebasezamiast tego. Z drugiej strony, jeśli nigdy nie zrobić żadnej z własnymi zobowiązuje on demo, nawet nie trzeba się demooddział. Alternatywnie, jeśli chcesz zautomatyzować wiele z tych czynności, ale możesz dokładnie sprawdzić, czy są zatwierdzenia, które ty i inni zrobiliście, możesz użyćgit merge --ff-only origin/demo: to przyspieszy, jeśli to możliwe, i po prostu zakończy się niepowodzeniem, jeśli nie (w którym to momencie możesz sprawdzić dwa zestawy zmian i wybrać rzeczywiste scalenie lub ponowne ustawienie, jeśli to konieczne).demo aby dopasować zaktualizowany,origin/demo
Ta sama logika dotyczy master, choć robisz scalanie na master , więc na pewno nie potrzebujemy master. Jest jednak jeszcze bardziej prawdopodobne, że chciałbyś, aby scalanie nie powiodło się, jeśli nie można go wykonać jako szybkiego przewijania do przodu bez scalania, więc prawdopodobnie powinno tak być git merge --ff-only origin/master.
Powiedzmy, że nigdy nie wykonujesz własnych zatwierdzeń demo. W tym przypadku możemy democałkowicie porzucić nazwę :
git fetch origin # update origin/*
git checkout master
git merge --ff-only origin/master || die "cannot fast-forward our master"
git merge -X theirs origin/demo || die "complex merge conflict"
git push origin master
Jeśli są robi własne demozobowiązuje gałąź, to nie jest pomocne; równie dobrze możesz zachować istniejące scalanie (ale może dodać w --ff-onlyzależności od tego, jakie zachowanie chcesz) lub przełączyć na wykonanie rebase. Zwróć uwagę, że wszystkie trzy metody mogą się nie powieść: scalanie może się nie powieść z powodu konfliktu, scalanie z --ff-onlymoże nie być w stanie przewinąć do przodu, a ponowne bazowanie może się nie powieść z konfliktem (rebase działa w zasadzie poprzez wybieranie najlepszych zatwierdzeń, które wykorzystuje scalanie maszyneria i stąd może wystąpić konflikt scalania).
git push -f origin master