Niezupełnie związane z tą odpowiedzią, ale porzuciłbym git pull
, co po prostu biegnie git fetch
za 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 , -X
opcje są przekazywane do strategii scalania, a zarówno recursive
strategia domyślna , jak i resolve
strategia alternatywna przyjmują -X ours
lub -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ż --ours
wersją 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 diff
wynikach 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 color
się colour
na linii 17 i zmieniają fred
się barney
na 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 ours
I -X theirs
opcje 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
.
-X
Jednak ś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 i
jako licznika pętli. Jeśli połączymy te dwie zmiany, wynikowy kod nie będzie się już kompilować. Ta -X
opcja 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 merge
polecenia. 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 -X
argumentó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/demo
do lokalnego demo
(twoje zastosowania, git pull
które, jeśli twój Git jest bardzo stary, nie zaktualizują się, origin/demo
ale dadzą ten sam wynik końcowy). Drugi jest doprowadzenie origin/master
do master
.
Nie jest dla mnie jasne, kto aktualizuje demo
i / lub master
. Jeśli napiszesz swój własny kod we własnej demo
gałęzi, a inni piszą kod i wypychają go do demo
gałę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 rebase
zamiast tego. Z drugiej strony, jeśli nigdy nie zrobić żadnej z własnymi zobowiązuje on demo
, nawet nie trzeba się demo
oddział. 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 demo
cał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 demo
zobowiązuje gałąź, to nie jest pomocne; równie dobrze możesz zachować istniejące scalanie (ale może dodać w --ff-only
zależ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-only
moż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