Jak rozwiązać konflikty scalania w Git

4764

Jak rozwiązać konflikty scalania w Git?

Łup
źródło
31
Poniższy post na blogu wydaje się stanowić bardzo dobry przykład radzenia sobie z konfliktem scalania z Gitem, który powinien poprowadzić Cię we właściwym kierunku. Radzenie sobie z konfliktami w Git i unikanie ich
mwilliams,
4
Możesz skonfigurować narzędzie do scalania (kdiff3 jebaird.com/2013/07/08/... ), a następnie użyć git scaletool. Podczas pracy w dużych zespołach programistów zawsze napotykasz konflikty scalania.
Grady G. Cooper
Nie zapominaj, że możesz złagodzić większość konfliktów scalania poprzez regularne łączenie w dół łańcucha dostaw!
Ant P
8
Fascynujące pytanie: zadane w 2008 r., 100% otwarte zakończyło się bez żadnej wskazówki na temat tego, o co tak naprawdę chodzi (czy chodzi o GUI? O polecenia git? O semantykę? O pchanie / wyciąganie czy po prostu ogólne konflikty?) - całkowicie nieodpowiedzialne. 30 odpowiedzi, wszystkie (o ile szybki rzut oka pokazuje) mniej więcej o różnych narzędziach diff3 i scalających, żadne nie są akceptowane. Odpowiedź najczęściej głosowana wspomina o poleceniu, które nawet nie działa od razu po gitinstalacji domyślnej . Udało mi się wejść dziś na stronę startową SE, 2017, z 1,3 mln wyświetleń i tysiącami głosów w obie strony. Fascynujący.
AnoE,

Odpowiedzi:

2911

Próbować: git mergetool

Otwiera GUI, które przeprowadzi cię przez każdy konflikt, i będziesz mógł wybrać sposób połączenia. Czasami wymaga to później ręcznej edycji, ale zwykle wystarczy sam. Z pewnością jest to o wiele lepsze niż zrobienie wszystkiego ręcznie.

Zgodnie z komentarzem @JoshGlover:

Komenda

niekoniecznie otwiera GUI, chyba że go zainstalujesz. Uruchomienie git mergetooldla mnie spowodowało, że zostałem vimdiffużyty. Można zainstalować jeden z poniższych narzędzi, aby go używać zamiast: meld, opendiff, kdiff3, tkdiff, xxdiff, tortoisemerge, gvimdiff, diffuse, ecmerge, p4merge, araxis, vimdiff, emerge.

Poniżej znajduje się przykładowa procedura do vimdiffrozwiązywania konfliktów scalania. Na podstawie tego linku

Krok 1 : Uruchom następujące polecenia w swoim terminalu

git config merge.tool vimdiff
git config merge.conflictstyle diff3
git config mergetool.prompt false

Spowoduje to ustawienie vimdiff jako domyślnego narzędzia do scalania.

Krok 2 : Uruchom następujące polecenie w terminalu

git mergetool

Krok 3 : Zobaczysz ekran vimdiff w następującym formacie

  ╔═══════╦══════╦════════╗
  ║       ║      ║        ║
  ║ LOCAL ║ BASE ║ REMOTE ║
  ║       ║      ║        ║
  ╠═══════╩══════╩════════╣
  ║                       ║
  ║        MERGED         ║
  ║                       ║
  ╚═══════════════════════╝

Te 4 widoki są

LOKALNIE - jest to plik z bieżącego oddziału

BASE - wspólny przodek, jak plik wyglądał przed obiema zmianami

ZDALNIE - plik, który scalasz ze swoim oddziałem

POŁĄCZONE - wynik scalania, to jest zapisywane w repozytorium

Możesz poruszać się między tymi widokami za pomocą ctrl+ w. Możesz bezpośrednio przejść do widoku POŁĄCZONE za pomocą ctrl+, wa następnie j.

Więcej informacji o nawigacji vimdiff tutaj i tutaj

Krok 4 . Możesz edytować widok POŁĄCZONY w następujący sposób

Jeśli chcesz otrzymywać zmiany z ZDALNEGO

:diffg RE  

Jeśli chcesz uzyskać zmiany z BASE

:diffg BA  

Jeśli chcesz otrzymywać zmiany z LOKALNEJ

:diffg LO 

Krok 5 . Zapisz, wyjdź, zobowiązaj się i posprzątaj

:wqa zapisz i wyjdź z vi

git commit -m "message"

git clean Usuń dodatkowe pliki (np. * .Orig) utworzone przez narzędzie diff.

Peter Burns
źródło
54
Informacje, których możesz użyć, git mergetool -yaby zapisać kilka naciśnięć klawiszy, jeśli scalasz wiele plików jednocześnie.
davr
373
Cóż, niekoniecznie otwiera GUI, chyba że go zainstalujesz. Uruchomienie git mergetooldla mnie spowodowało, że zostałem vimdiffużyty. Można zainstalować jeden z poniższych narzędzi, aby go używać zamiast: meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse ecmerge p4merge araxis vimdiff emerge.
Josh Glover
31
Dobra uwaga, Josh. Na ubuntu miałem najwięcej szczęścia z meldem, jego trójstronny sposób wyświetlania scalania nie jest zły. W OSX git wybrał niezłe ustawienie domyślne.
Peter Burns
18
To otworzyło KDiff3. Którego absolutnie nie mam pojęcia jak używać.
David Murdoch,
7
Możesz także użyć Beyond Compare 3 teraz ( git mergetool -t bc3).
AzP
1703

Oto prawdopodobny przypadek użycia od góry:

Wprowadzisz kilka zmian, ale ups, nie jesteś na bieżąco:

git fetch origin
git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Updating a030c3a..ee25213
error: Entry 'filename.c' not uptodate. Cannot merge.

Bądź na bieżąco i spróbuj ponownie, ale masz konflikt:

git add filename.c
git commit -m "made some wild and crazy changes"
git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Auto-merging filename.c
CONFLICT (content): Merge conflict in filename.c
Automatic merge failed; fix conflicts and then commit the result.

Więc decydujesz się spojrzeć na zmiany:

git mergetool

O rany, o rany, zmieniłem niektóre rzeczy, ale żeby użyć moich zmian ... nie ... ich zmian ...

git checkout --ours filename.c
git checkout --theirs filename.c
git add filename.c
git commit -m "using theirs"

A potem próbujemy ostatni raz

git pull origin master

From ssh://[email protected]:22/projectname
 * branch            master     -> FETCH_HEAD
Already up-to-date.

Ta-da!

CoolAJ86
źródło
19
Było to bardzo pomocne, ponieważ miałem wiele błędów scalania z plikami binarnymi (zasobami sztuki), a łączenie ich wydaje się zawsze
kończyć
188
Ostrożny! Znaczenie --ours i --theirs jest odwrócone. --ours == pilot. --tirowie == lokalny. Zobaczgit merge --help
mmell,
57
W moim przypadku potwierdzam, że --theirs = zdalne repozytorium, --ours = moje własne lokalne repozytorium. Jest to przeciwieństwo komentarzy @mmell.
Aryo
24
@mmell Najwyraźniej tylko na podstawie. Patrzthis question
Navin,
184
Faceci, „nasi” i „ich” odnoszą się do tego, czy łączysz się, czy bazujesz. Jeśli jesteś Scalanie , to „nasze” oznacza oddział jesteś wtopienie, a „ich” jest oddział jesteś łączących w., Kiedy jesteś podścielanie , to „nasze” oznacza commity jesteś podścielanie na , podczas gdy „ich” odnosi się do zatwierdzeń, które chcesz zmienić.
736

Uważam, że narzędzia do scalania rzadko pomagają mi zrozumieć konflikt lub rozwiązanie. Zazwyczaj odnoszę większe sukcesy, patrząc na znaczniki konfliktu w edytorze tekstów i używając git log jako dodatku.

Oto kilka wskazówek:

Wskazówka pierwsza

Najlepszą rzeczą, jaką znalazłem, jest użycie stylu konfliktu scalania „diff3”:

git config merge.conflictstyle diff3

Powoduje to utworzenie takich znaczników konfliktu:

<<<<<<<
Changes made on the branch that is being merged into. In most cases,
this is the branch that I have currently checked out (i.e. HEAD).
|||||||
The common ancestor version.
=======
Changes made on the branch that is being merged in. This is often a 
feature/topic branch.
>>>>>>>

Środkowa część wyglądała jak wspólny przodek. Jest to przydatne, ponieważ można porównać go z wersjami górną i dolną, aby lepiej zrozumieć, co zostało zmienione w każdej gałęzi, co daje lepszy pomysł na to, jaki był cel każdej zmiany.

Jeśli konflikt składa się tylko z kilku linii, generalnie czyni to konflikt bardzo oczywistym. (Umiejętność rozwiązania konfliktu jest zupełnie inna; musisz zdawać sobie sprawę z tego, nad czym pracują inni ludzie. Jeśli jesteś zdezorientowany, prawdopodobnie najlepiej po prostu zadzwoń do tej osoby do swojego pokoju, aby mogli zobaczyć, czego szukasz) w.)

Jeśli konflikt jest dłuższy, wytnę i wkleję każdą z trzech sekcji w trzy osobne pliki, takie jak „moje”, „wspólne” i „ich”.

Następnie mogę uruchomić następujące polecenia, aby zobaczyć dwa porcje diff, które spowodowały konflikt:

diff common mine
diff common theirs

Nie jest to to samo, co użycie narzędzia scalania, ponieważ narzędzie scalania obejmie również wszystkie nie sprzeczne porcje diff. Uważam, że to rozprasza.

Wskazówka druga

Ktoś już o tym wspominał, ale zrozumienie intencji stojących za każdym kawałkiem różnic jest ogólnie bardzo pomocne w zrozumieniu, skąd wziął się konflikt i jak sobie z nim poradzić.

git log --merge -p <name of file>

To pokazuje wszystkie zatwierdzenia, które dotknęły tego pliku pomiędzy wspólnym przodkiem i dwiema główkami, które łączycie. (Więc nie obejmuje zatwierdzeń, które już istnieją w obu gałęziach przed scaleniem.) Pomaga to zignorować różne fragmenty, które wyraźnie nie są czynnikiem w twoim obecnym konflikcie.

Wskazówka trzecia

Sprawdź swoje zmiany za pomocą zautomatyzowanych narzędzi.

Jeśli masz automatyczne testy, uruchom je. Jeśli masz kłaczki , uruchom to. Jeśli jest to projekt do zbudowania, skompiluj go przed zatwierdzeniem itp. We wszystkich przypadkach musisz wykonać trochę testów, aby upewnić się, że zmiany nic nie zepsuły. (Cholera, nawet scalenie bez konfliktów może uszkodzić działający kod.)

Wskazówka czwarta

Planować naprzód; komunikować się ze współpracownikami.

Planowanie z wyprzedzeniem i świadomość, nad czym pracują inni, może pomóc w zapobieganiu konfliktom scalania i / lub pomóc w ich wcześniejszym rozwiązywaniu - a szczegóły są wciąż aktualne.

Na przykład, jeśli wiesz, że ty i inna osoba pracujecie nad innym refaktoryzacją, która wpłynie na ten sam zestaw plików, powinieneś porozmawiać ze sobą wcześniej i lepiej zrozumieć, jakie rodzaje zmian każdy z was jest zrobienie. Możesz zaoszczędzić sporo czasu i wysiłku, jeśli przeprowadzisz zaplanowane zmiany serio, a nie równolegle.

W przypadku poważnych refaktoryzacji, które przecinają dużą część kodu, powinieneś poważnie rozważyć pracę serią: wszyscy przestają pracować nad tym obszarem kodu, podczas gdy jedna osoba wykonuje pełne refaktoryzowanie.

Jeśli nie możesz pracować seryjnie (być może z powodu presji czasu), to przekazanie informacji o spodziewanych konfliktach scalania przynajmniej pomoże ci rozwiązać problemy wcześniej, dopóki szczegóły nie zostaną pominięte. Na przykład, jeśli współpracownik dokonuje destrukcyjnej serii zatwierdzeń w ciągu jednego tygodnia, możesz zdecydować o scaleniu / zmianie bazy w tym oddziale współpracowników raz lub dwa razy dziennie w ciągu tego tygodnia. W ten sposób, jeśli znajdziesz konflikty scalania / rebase, możesz je rozwiązać szybciej niż przez kilka tygodni, aby scalić wszystko razem w jedną dużą bryłę.

Wskazówka piąta

Jeśli nie masz pewności co do scalenia, nie zmuszaj go.

Scalanie może wydawać się przytłaczające, szczególnie gdy jest wiele sprzecznych plików, a znaczniki konfliktu pokrywają setki linii. Często przy szacowaniu projektów oprogramowania nie poświęcamy wystarczającej ilości czasu na ogólne rzeczy, takie jak porządne scalenie, więc wydaje się, że spędzanie kilku godzin na rozwiązywaniu każdego konfliktu to prawdziwy problem.

Na dłuższą metę planowanie z wyprzedzeniem i świadomość, nad czym pracują inni, są najlepszymi narzędziami do przewidywania konfliktów scalania i przygotowania się do ich poprawnego rozwiązania w krótszym czasie.

Mark E. Haase
źródło
6
Opcja diff3 jest świetną funkcją do łączenia. Jedyne GUI, na jakie natknąłem się, pokazuje, że jest to Perforce p4merge, które można zainstalować i używać niezależnie od innych narzędzi Perforce (z których nie korzystałem, ale słyszałem skargi).
alxndr
3
Po próbie zmiany bazy, która spowodowała konflikt scalania: $ git log --merge -p build.xml wyjście: fatal: --merge without MERGE_HEAD?
Ed Randall
co jeśli mam zmiany w jednym pliku z oddziału 1 i usunięcie tego pliku z oddziału 2. Jak mogę rozwiązać ten konflikt scalania? Czy jest jakiś sposób użycia git, w którym mogę je scalić, zachowując zmiany jednej gałęzi?
Honey
git config merge.conflictstyle diff3- Dziękuję Panu. To jest niesamowite i uwolniło mnie od prób znalezienia (i zapłacenia $$) dobrego GUI do łączenia w 3 kierunkach. IMO jest to lepsze, ponieważ pokazuje wspólnego przodka, a także lokalnego / zdalnego i pokazuje ostatnie wiersze dziennika zatwierdzenia, których (AFAIK) nie robi GUI. Zatwierdzenia zdecydowanie pomagają zidentyfikować kod, który należy do jakiej gałęzi.
ffxsam
Przekonałem się, że czasami konfliktowy styl diff3 powoduje ogromne porcje diff, które są w dużej mierze identyczne, podczas gdy domyślnie będą tworzyć mniejsze, łatwiejsze do zarządzania, porcje. Niestety nie mam odtwarzacza, którego mogę użyć do zgłoszenia błędu. Ale jeśli napotkasz ten problem, możesz rozważyć tymczasowe wyłączenie tej opcji.
Dave Abrahams,
348
  1. Sprawdź, które pliki są w konflikcie (Git powinien ci to powiedzieć).

  2. Otwórz każdy plik i sprawdź różnice; Git rozgranicza ich. Mamy nadzieję, że będzie oczywiste, którą wersję każdego bloku zachować. Być może będziesz musiał omówić to z innymi programistami, którzy popełnili kod.

  3. Po rozwiązaniu konfliktu w pliku git add the_file.

  4. Po rozwiązaniu wszystkich konfliktów wykonaj git rebase --continuedowolne polecenie Git po zakończeniu.

davetron5000
źródło
38
@ Justin Pomyśl o Git jako o śledzeniu treści, a nie o śledzeniu plików. Łatwo więc zauważyć, że zaktualizowana zawartość nie znajduje się w repozytorium i należy ją dodać. Ten sposób myślenia wyjaśnia również, dlaczego Git nie śledzi pustych folderów: Chociaż technicznie są to pliki, nie ma żadnych treści do śledzenia.
Gareth,
7
treść jest tam, występuje konflikt, ponieważ istnieją 2 wersje treści. Dlatego „git add” nie brzmi poprawnie. I to nie działa (git add, git commit), jeśli chcesz zatwierdzić tylko jeden plik po rozwiązaniu konfliktu („fatal: nie można wykonać częściowego zatwierdzenia podczas scalania.”)
Dainius
1
Tak, technicznie rzecz biorąc, odpowiada to na pytanie, które zostało zadane, ale nie jest użyteczną odpowiedzią, moim zdaniem, przepraszam. Jaki jest sens, aby jedna gałąź była taka sama jak inna? Oczywiście połączenie będzie miało konflikty.
Thufir,
5
Thulfir: kto powiedział coś o uczynieniu jednej gałęzi taką samą jak drugą? Istnieją różne scenariusze, w których konieczne jest połączenie, bez „tworzenia jednej gałęzi takiej samej jak drugiej”. Jednym z nich jest ukończenie gałęzi programistycznej i włączenie jej zmian do gałęzi master; następnie gałąź programistyczna może zostać usunięta. Innym jest, gdy chcesz dokonać zmiany podstawy rozwoju, aby ułatwić ostateczne połączenie z master.
Teemu Leisti,
4
@JustinGrant umieszcza git addpliki w indeksie; nic nie dodaje do repozytorium. git commitdodaje rzeczy do repozytorium. Takie użycie ma sens w przypadku scalania - scalanie automatycznie powoduje stopniowanie wszystkich zmian, które można scalić automatycznie; Twoim obowiązkiem jest scalenie pozostałych zmian i dodanie ich do indeksu po zakończeniu.
Mark E. Haase
105

Sprawdź odpowiedzi w pytaniu Przepełnienie stosu Przerwanie scalania w Git , szczególnie odpowiedź Charlesa Baileya, która pokazuje, jak przeglądać różne wersje pliku z problemami, na przykład:

# Common base version of the file.
git show :1:some_file.cpp

# 'Ours' version of the file.
git show :2:some_file.cpp

# 'Theirs' version of the file.
git show :3:some_file.cpp
Pat Notz
źródło
Sprawdź także opcję „-m”, aby „git checkout -m” - pozwala wyodrębnić różne muchy z powrotem do obszaru roboczego
qneill
To mnie uratowało. Spojrzenie na każdy plik osobno pozwoliło mi zapamiętać, o co chodzi w każdej gałęzi. Wtedy mógłbym podjąć decyzję o wyborze.
Rohmer
99

Konflikty scalania mają miejsce, gdy zmiany są wprowadzane do pliku w tym samym czasie. Oto jak to rozwiązać.

git CLI

Oto proste kroki, które należy zrobić, gdy wejdziesz w stan konfliktu:

  1. Zanotuj listę plików będących w konflikcie z: git status(w Unmerged pathssekcji).
  2. Rozwiązuj konflikty osobno dla każdego pliku, stosując jedną z następujących metod:

    • Użyj GUI, aby rozwiązać konflikty: git mergetool(najprostszy sposób).

    • Aby zaakceptować zdalnego / inna wersja, przeznaczenie: git checkout --theirs path/file. Spowoduje to odrzucenie wszelkich lokalnych zmian wprowadzonych dla tego pliku.

    • Aby zaakceptować wersję lokalną / naszą, użyj: git checkout --ours path/file

      Należy jednak zachować ostrożność, ponieważ zdalne zmiany powodowały konflikty z jakiegoś powodu.

      Powiązane: Jakie jest dokładne znaczenie „naszego” i „ich” w git?

    • Edytuj pliki będące w konflikcie ręcznie i poszukaj bloku kodu pomiędzy <<<<</ >>>>>a następnie wybierz wersję z góry lub z dołu =====. Zobacz: Jak przedstawiane są konflikty .

    • Konflikty ścieżek i nazw plików można rozwiązać za pomocą git add/ git rm.

  3. Na koniec przejrzyj pliki gotowe do zatwierdzenia, używając: git status .

    Jeśli nadal masz żadnych plików mocy Unmerged paths, a nie ręcznie rozwiązać konflikt, pozwól Git wie, że go rozwiązać przez: git add path/file.

  4. Jeśli wszystkie konflikty zostały pomyślnie rozwiązane, zatwierdź zmiany przez: git commit -ai wypchnij zdalnie jak zwykle.

Zobacz także: Rozwiązywanie konfliktu scalania z wiersza poleceń w GitHub

Aby zapoznać się z praktycznym samouczkiem, sprawdź: Scenariusz 5 - Naprawianie konfliktów scalania według Katacody .

DiffMerge

Z powodzeniem korzystałem z DiffMerge, który może wizualnie porównywać i scalać pliki w systemach Windows, macOS i Linux / Unix.

Graficznie pokazuje zmiany między 3 plikami i pozwala na automatyczne łączenie (jeśli jest to bezpieczne) i pełną kontrolę nad edytowaniem pliku wynikowego.

DiffMerge

Źródło obrazu: DiffMerge (zrzut ekranu systemu Linux)

Wystarczy go pobrać i uruchomić w repo jako:

git mergetool -t diffmerge .

System operacyjny Mac

W systemie macOS można zainstalować za pomocą:

brew install caskroom/cask/brew-cask
brew cask install diffmerge

I prawdopodobnie (jeśli nie jest dostarczony) potrzebujesz następującej dodatkowej prostej owijarki umieszczonej w ŚCIEŻCE (np. /usr/bin):

#!/bin/sh
DIFFMERGE_PATH=/Applications/DiffMerge.app
DIFFMERGE_EXE=${DIFFMERGE_PATH}/Contents/MacOS/DiffMerge
exec ${DIFFMERGE_EXE} --nosplash "$@"

Następnie możesz użyć następujących skrótów klawiaturowych:

  • - Alt- Up/, Downaby przejść do poprzednich / następnych zmian.
  • - Alt- Left/, Rightaby zaakceptować zmianę z lewej lub prawej strony

Alternatywnie możesz użyć opendiff (część Xcode Tools), który pozwala ci połączyć dwa pliki lub katalogi w celu utworzenia trzeciego pliku lub katalogu.

kenorb
źródło
79

Jeśli często popełniasz małe zatwierdzenia, zacznij od spojrzenia na komentarze zatwierdzenia za pomocą git log --merge. Następnie git diffpokaże konflikty.

W przypadku konfliktów obejmujących więcej niż kilka wierszy łatwiej jest zobaczyć, co się dzieje w zewnętrznym narzędziu GUI. Lubię opendiff - Git obsługuje również vimdiff, gvimdiff, kdiff3, tkdiff, meld, xxdiff, pojawiają się po wyjęciu z pudełka i możesz zainstalować inne: git config merge.tool "your.tool"ustawisz wybrane narzędzie, a następniegit mergetool po nieudanym scaleniu pokaże różnice w kontekście.

Za każdym razem, gdy edytujesz plik w celu rozwiązania konfliktu, git add filenamezaktualizujesz indeks, a Twój plik różnicowy już go nie pokaże. Gdy wszystkie konflikty zostaną rozwiązane, a ich pliki zostały git add-ed, git commitzakończy scalanie.

Paweł
źródło
8
Użycie „git add” jest tutaj prawdziwą sztuczką. Możesz nawet nie chcieć zatwierdzić (może chcesz ukryć), ale musisz wykonać polecenie „git add”, aby zakończyć scalanie. Myślę, że scaletool dokonuje dodania dla ciebie (chociaż nie ma go na stronie podręcznika), ale jeśli wykonujesz scalanie ręcznie, musisz użyć polecenia „git add”, aby je ukończyć (nawet jeśli nie chcesz zatwierdzać).
nobar
47

Zobacz, jak prezentowane są konflikty lub, w Git,git merge dokumentację, aby zrozumieć, jakie są znaczniki konfliktu scalania.

Ponadto sekcja Jak rozwiązać konflikty wyjaśnia, jak rozwiązać konflikty:

Po obejrzeniu konfliktu możesz zrobić dwie rzeczy:

  • Zdecyduj się nie łączyć. Jedyne, czego potrzebujesz, to zresetować plik indeksu do HEADzatwierdzenia, aby cofnąć 2. i wyczyścić zmiany drzewka roboczego dokonane przez 2. i 3 .; git merge --abortmożna do tego użyć.

  • Rozwiąż konflikty. Git zaznaczy konflikty w działającym drzewie. Edytuj pliki w odpowiednim kształcie, a git addnastępnie w indeksie. Użyj, git commitaby zamknąć ofertę.

Możesz rozwiązać konflikt za pomocą wielu narzędzi:

  • Użyj narzędzia wielofunkcyjnego. git mergetoolaby uruchomić graficzny program do łączenia, który przeprowadzi cię przez proces scalania.

  • Spójrz na różnice. git diffpokaże trójdrożny diff, podkreślając zmiany zarówno z wersji jak HEADi MERGE_HEAD.

  • Spójrz na różnice z każdej gałęzi. git log --merge -p <path>pokaże najpierw różnice dla HEADwersji, a następnie dla MERGE_HEADwersji.

  • Spójrz na oryginały. git show :1:filenamepokazuje wspólnego przodka, git show :2:filenamepokazuje HEADwersję i git show :3:filenamepokazuje MERGE_HEADwersję.

Możesz także przeczytać o znacznikach konfliktu scalania i sposobach ich rozwiązywania w sekcji książki Pro Git Podstawowe konflikty scalania .

Peter Mortensen
źródło
42

Chcę albo w całości moją wersję, albo chcę przejrzeć poszczególne zmiany i zdecydować o każdej z nich.

W pełni zaakceptuj moją lub jej wersję :

Zaakceptuj moją wersję (lokalną, naszą):

git checkout --ours -- <filename>
git add <filename>              # Marks conflict as resolved
git commit -m "merged bla bla"  # An "empty" commit

Zaakceptuj ich wersję (zdalną, ich):

git checkout --theirs -- <filename>
git add <filename>
git commit -m "merged bla bla"

Jeśli chcesz zrobić dla wszystkich plików konfliktu, uruchom:

git merge --strategy-option ours

lub

git merge --strategy-option theirs

Przejrzyj wszystkie zmiany i zaakceptuj je indywidualnie

  1. git mergetool
  2. Przejrzyj zmiany i zaakceptuj dowolną wersję dla każdej z nich.
  3. git add <filename>
  4. git commit -m "merged bla bla"

Domyślnie mergetooldziała w wierszu poleceń . Jak korzystać z narzędzia do łączenia linii poleceń powinno być osobnym pytaniem.

Możesz także zainstalować do tego celu narzędzie wizualne , np. meldI uruchomić

git mergetool -t meld

Otworzy wersję lokalną (naszą), wersję „podstawową” lub „scaloną” (aktualny wynik scalenia) i wersję zdalną (ich). Po zakończeniu zapisz połączoną wersję, uruchom git mergetool -t meldponownie, aż pojawi się komunikat „Żadne pliki nie wymagają scalenia”, a następnie przejdź do kroków 3. i 4.

Brak pomysłu
źródło
To polecenie: git checkout - theirs - <nazwa_pliku> zmienił WSZYSTKIE pliki na swoje, a nie tylko <nazwa_pliku>
Donato
Właściwie się myliłem. To tylko aktualizuje określony plik.
Donato
40

W przypadku użytkowników Emacsa, którzy chcą rozwiązać konflikty scalania częściowo:

git diff --name-status --diff-filter=U

pokazuje wszystkie pliki wymagające rozwiązania konfliktu.

Otwórz każdy z tych plików jeden po drugim lub wszystkie jednocześnie:

emacs $(git diff --name-only --diff-filter=U)

Odwiedzając bufor wymagający edycji w Emacsie, wpisz

ALT+x vc-resolve-conflicts

Otworzy to trzy bufory (mój, ich i bufor wyjściowy). Nawiguj, naciskając „n” (następny region), „p” (region podglądu). Naciśnij „a” i „b”, aby skopiować odpowiednio mój lub ich region do bufora wyjściowego. I / lub bezpośrednio edytuj bufor wyjściowy.

Po zakończeniu: naciśnij „q”. Emacs zapyta, czy chcesz zapisać ten bufor: tak. Po zakończeniu bufora oznacz go jako rozwiązany, uciekając przed przestępcą:

git add FILENAME

Po zakończeniu ze wszystkimi typami buforów

git commit

aby zakończyć scalanie.

eci
źródło
33

Premia:

Mówiąc o pull / fetch / merge w powyższych odpowiedziach, chciałbym podzielić się ciekawą i produktywną sztuczką,

git pull --rebase

To powyższe polecenie jest najbardziej użytecznym poleceniem w moim życiu git, które zaoszczędziło wiele czasu.

Przed przekazaniem nowo zatwierdzonej zmiany na zdalny serwer, spróbuj git pull --rebaseraczej git pullręczniemerge zatwierdzonej a ona automatycznie zsynchronizuje najnowsze zmiany na serwerze zdalnym (z funkcją pobierania + scalania) i umieści twoje lokalne zatwierdzenie na górze w dzienniku git. Nie musisz martwić się o ręczne wyciąganie / scalanie.

W przypadku konfliktu wystarczy użyć

git mergetool
git add conflict_file
git rebase --continue

Znajdź szczegóły na: http://gitolite.com/git-pull--rebase

Sazzad Hissain Khan
źródło
32

Po prostu, jeśli dobrze wiesz, że zmiany w jednym z repozytoriów nie są ważne i chcesz rozwiązać wszystkie zmiany na korzyść drugiego, użyj:

git checkout . --ours

aby rozwiązać zmiany na korzyść swojego repozytorium , lub

git checkout . --theirs

w celu rozwiązania zmian na korzyść drugiego lub głównego repozytorium .

W przeciwnym razie będziesz musiał użyć narzędzia do scalania GUI, aby przechodzić między plikami jeden po drugim, powiedzmy, że to narzędzie do scalania p4mergelub napisać nazwę, którą już zainstalowałeś

git mergetool -t p4merge

a po zakończeniu pliku będziesz musiał zapisać i zamknąć, aby otworzyć następny.

Mohamed Selim
źródło
2
Git Checkout. - dzięki rozwiązali mój problem
Ramesh Chand
jeśli wolisz ręcznie rozwiązywać konflikty, spróbuj otworzyć folder w programie Visual Studio Code, oznacza on pliki z konfliktami i koloruje linie konfliktu w każdym z nich
Mohamed Selim
31

Wykonaj następujące kroki, aby naprawić konflikty scalania w Git:

  1. Sprawdź status Git: status git

  2. Pobierz łatkę: git fetch ( sprawdź odpowiednią łatkę z Git commit)

  3. Kasa lokalna (tutaj temp1 w moim przykładzie tutaj): git checkout -b temp1

  4. Wyciągnij najnowszą zawartość z master: git pull --rebase origin master

  5. Uruchom narzędzie do łączenia i sprawdzaj konflikty i napraw je ... oraz sprawdź zmiany w oddziale zdalnym za pomocą bieżącego oddziału: git scaletool

  6. Sprawdź status jeszcze raz: status git

  7. Usuń niechciane pliki utworzone lokalnie przez scaletool, zwykle scaletool tworzy dodatkowy plik z rozszerzeniem * .orig. Usuń ten plik, ponieważ jest to tylko duplikat, napraw zmiany lokalnie i dodaj poprawną wersję swoich plików. git dodaj #your_changed_correct_files

  8. Sprawdź status jeszcze raz: status git

  9. Zatwierdź zmiany w tym samym identyfikatorze zatwierdzenia (pozwala to uniknąć nowego oddzielnego zestawu poprawek): git commit --amend

  10. Push do gałęzi master: git push (do repozytorium Git)

Rehabilitacyjny
źródło
28

Istnieją 3 kroki:

  1. Znajdź, które pliki powodują konflikty według poleceń

    git status
    
  2. Sprawdź pliki, w których można znaleźć konflikty oznaczone jako

    <<<<<<<<head
    blablabla
    
  3. Zmień go tak, jak chcesz, a następnie zatwierdź za pomocą poleceń

    git add solved_conflicts_files
    git commit -m 'merge msg'
    
Qijun Liu
źródło
Pracował dla mnie! Dzięki!
Nuwan Jayawardene
Musisz zwrócić uwagę, jeśli zrobisz to podczas rebase. Powinieneś użyć git rebase - kontynuuj zamiast git commit
Samuel Dauzon
27

Konflikty scalania można naprawić na wiele sposobów, które opisują inne.

Myślę, że prawdziwym kluczem jest wiedza o tym, jak przebiegają zmiany w lokalnych i zdalnych repozytoriach. Kluczem do tego jest zrozumienie gałęzi śledzenia. Przekonałem się, że uważam gałąź śledzenia za „brakujący element w środku” między mną, moim lokalnym, aktualnym katalogiem plików a pilotem zdefiniowanym jako pochodzenie.

Osobiście przyzwyczaiłem się do 2 rzeczy, które pomagają tego uniknąć.

Zamiast:

git add .
git commit -m"some msg"

Który ma dwie wady -

a) Wszystkie nowe / zmienione pliki zostaną dodane, co może obejmować pewne niepożądane zmiany.
b) Nie możesz najpierw przejrzeć listy plików.

Zamiast tego robię:

git add file,file2,file3...
git commit # Then type the files in the editor and save-quit.

W ten sposób bardziej rozważnie wybierasz pliki, które chcesz dodać, a także przeglądasz listę i zastanawiasz się więcej podczas korzystania z edytora wiadomości. Uważam, że poprawia to także moje komunikaty zatwierdzania, gdy korzystam z edytora pełnoekranowego zamiast z -mopcji.

[Aktualizacja - w miarę upływu czasu zmieniłem więcej na:

git status # Make sure I know whats going on
git add .
git commit # Then use the editor

]

Ponadto (i bardziej odpowiednie dla twojej sytuacji) staram się unikać:

git pull

lub

git pull origin master.

ponieważ pull oznacza scalenie, a jeśli masz lokalne zmiany, które nie chcesz scalić, możesz łatwo skończyć ze scalonym kodem i / lub konfliktami scalającymi dla kodu, który nie powinien zostać scalony.

Zamiast tego próbuję to zrobić

git checkout master
git fetch   
git rebase --hard origin/master # or whatever branch I want.

Pomocne może być również:

git branch, fork, fetch, merge, rebase and clone, jakie są różnice?

Michael Durrant
źródło
Hej, trochę rozumiem twoją odpowiedź. Ale odkąd dopiero zaczynam konflikty w github, myślę, że czegoś brakuje. Co dzieje się z lokalnymi modyfikacjami gdy robisz git checkout masteri git fetch i git rebase --hard origin/master
Suhaib
Uważam, że powinieneś dodać więcej szczegółów na temat tego, co robić. Kolejny przykład, który mnie dezorientuje, o którym wspomniałeś w odpowiedzi: my zrobimy git add ., czy to zapisze nasze lokalne modyfikacje, abyśmy mogli kontynuować git checkout master? czy są to dwa różne scenariusze?
Suhaib,
@MichaelDurrant $ git rebase --hard origin/master b5a30cc159ba8dd error: unknown option hard 'użycie: git rebase [-i] [opcje] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>] lub: git rebase [-i] [ opcje] [--exec <cmd>] [--onto <newbase>] --root [<branch>] lub: git rebase --continue | --abort | --skip | --edit-todo `
likejudo
24

Odpowiedź CoolAJ86 podsumowuje prawie wszystko. W przypadku zmiany obu gałęzi w tym samym fragmencie kodu konieczne będzie ręczne scalenie. Otwórz plik w konflikcie w dowolnym edytorze tekstu i powinieneś zobaczyć następującą strukturę.

(Code not in Conflict)
>>>>>>>>>>>
(first alternative for conflict starts here)
Multiple code lines here
===========
(second alternative for conflict starts here)
Multiple code lines here too    
<<<<<<<<<<<
(Code not in conflict here)

Wybierz jedną z alternatyw lub kombinację obu w taki sposób, aby nowy kod był, jednocześnie usuwając znaki równości i nawiasy kątowe.

git commit -a -m "commit message"
git push origin master
iankit
źródło
17
git log --merge -p [[--] path]

Nie zawsze wydaje mi się, że działa i zwykle kończy się wyświetlaniem każdego zatwierdzenia, które różniło się między dwiema gałęziami, dzieje się tak nawet wtedy, gdy używasz --do oddzielenia ścieżki od polecenia.

Aby obejść ten problem, otwieram dwie linie poleceń w jednym uruchomieniu

git log ..$MERGED_IN_BRANCH --pretty=full -p [path]

a w drugim

git log $MERGED_IN_BRANCH.. --pretty=full -p [path]

Zamiana $MERGED_IN_BRANCHna gałąź, którą scaliłem i [path]na plik będący w konflikcie. To polecenie rejestruje wszystkie zatwierdzenia, w postaci łatki, pomiędzy ( ..) dwoma zatwierdzeniami. Jeśli zostawisz jedną stronę pustą, jak w powyższych poleceniach, git automatycznie użyje HEAD(gałąź, w której się scalasz w tym przypadku).

To pozwoli ci zobaczyć, jakie zatwierdzenia poszły do ​​pliku w dwóch gałęziach po ich rozejściu. Zwykle znacznie ułatwia rozwiązywanie konfliktów.

Brian Di Palma
źródło
16

Za pomocą patience

Dziwi mnie, że nikt inny nie mówił o rozwiązywaniu konfliktów za patiencepomocą strategii rekurencyjnej scalania. W przypadku dużego konfliktu scalania przy użyciupatience zapewniło mi dobre wyniki. Chodzi o to, że będzie próbował dopasować bloki zamiast poszczególnych linii.

Jeśli na przykład zmienisz wcięcie programu, domyślna strategia scalania Git czasami pasuje do pojedynczych nawiasów, {które należą do różnych funkcji. Można tego uniknąć dzięki patience:

git merge -s recursive -X patience other-branch

Z dokumentacji:

With this option, merge-recursive spends a little extra time to avoid 
mismerges that sometimes occur due to unimportant matching lines 
(e.g., braces from distinct functions). Use this when the branches to 
be merged have diverged wildly.

Porównanie ze wspólnym przodkiem

Jeśli masz konflikt scalania i chcesz zobaczyć, co inni mieli na myśli podczas modyfikowania swojej gałęzi, czasem łatwiej jest porównać ich gałąź bezpośrednio ze wspólnym przodkiem (zamiast naszej gałęzi). Do tego możesz użyć merge-base:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch>

Zwykle chcesz zobaczyć tylko zmiany dla konkretnego pliku:

git diff $(git merge-base <our-branch> <their-branch>) <their-branch> <file>
Conchylicultor
źródło
W moim przypadku nie rozwiązało to dobrze konfliktów scalania, ponieważ z jakiegoś powodu zachowało duplikaty linii config w projektach C #. Chociaż był bardziej przyjazny niż CAŁY PLIK JEST INNY, co miałem wcześniej
Mathijs Segers
15

Od 12 grudnia 2016 r. Możesz łączyć oddziały i rozwiązywać konflikty na github.com

Dlatego jeśli nie chcesz używać wiersza polecenia ani narzędzi innych firm, które są oferowane tutaj ze starszych odpowiedzi , skorzystaj z natywnego narzędzia GitHub.

Ten post na blogu szczegółowo wyjaśnia, ale podstawowe jest to, że po „scaleniu” dwóch gałęzi za pomocą interfejsu użytkownika zobaczysz teraz opcję „rozwiąż konflikty”, która przeniesie Cię do edytora umożliwiającego radzenie sobie z tymi konfliktami scalania.

wprowadź opis zdjęcia tutaj

Maxwell
źródło
to nie pyta o github, dlatego głosowałem za bardzo słabą odpowiedzią.
mschuett
1
@ mschuett ma rację, pytanie brzmi „jak rozwiązywać konflikty w git”, a nie „jak rozwiązywać konflikty w github”. Jest różnica i już jest zbyt wielu ludzi, którzy myślą, że git i github to to samo, więc wszystko, co propaguje to uczucie, jest złe.
Patrick Mevzek,
15

Jeśli chcesz połączyć z gałęzi (testowej) do wzorcowej, możesz wykonać następujące kroki:

Krok 1 : Przejdź do oddziału

git checkout test

Krok 2 :

git pull --rebase origin master

Krok 3 : Jeśli występują jakieś konflikty, przejdź do tych plików, aby je zmodyfikować.

Krok 4 : Dodaj te zmiany

git add #your_changes_files

Krok 5 :

git rebase --continue

Krok 6 : Jeśli nadal występuje konflikt, wróć do kroku 3 ponownie. Jeśli nie ma konfliktu, wykonaj następujące czynności:

git push origin +test

Krok 7 : I wtedy nie ma konfliktu między testem a mistrzem. Możesz użyć scalania bezpośrednio.

Haimei
źródło
13

Zawsze wykonuję poniższe kroki, aby uniknąć konfliktów.

  • git checkout master (Przyjdź do gałęzi master)
  • git pull (zaktualizuj swój master, aby uzyskać najnowszy kod)
  • git checkout -b mybranch (Kasa nowego oddziału i zacznij pracę nad tym odgałęzieniem, aby twój mistrz zawsze pozostawał na szczycie pnia).
  • git add. ORAZ git commit ORAZ git push (w lokalnym oddziale po zmianach)
  • git checkout master (Wróć do swojego mistrza.)

Teraz możesz zrobić to samo i utrzymywać tyle lokalnych oddziałów, ile chcesz, i pracować jednocześnie, po prostu robię kasę git do twojego oddziału, gdy zajdzie taka potrzeba.

Chetan
źródło
12

Konflikty scalania mogą wystąpić w różnych sytuacjach:

  • Podczas uruchamiania „git fetch”, a następnie „git merge”
  • Podczas uruchamiania „git fetch”, a następnie „git rebase”
  • Podczas uruchamiania „git pull” (który jest faktycznie równy jednemu z wyżej wymienionych warunków)
  • Podczas uruchamiania „git stash pop”
  • Podczas stosowania łatek git (zatwierdzenia eksportowane do plików, które mają zostać przesłane, na przykład pocztą e-mail)

Aby rozwiązać konflikty, musisz zainstalować narzędzie do scalania zgodne z Git. Ja osobiście korzystam z KDiff3 i uważam, że jest miły i przydatny. Możesz pobrać jego wersję dla systemu Windows tutaj:

https://sourceforge.net/projects/kdiff3/files/

BTW, jeśli zainstalujesz rozszerzenia Git, w kreatorze instalacji jest opcja zainstalowania Kdiff3.

Następnie zainstaluj git configs, aby użyć Kdiff jako narzędzia do łączenia:

$ git config --global --add merge.tool kdiff3
$ git config --global --add mergetool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add mergetool.kdiff3.trustExitCode false

$ git config --global --add diff.guitool kdiff3
$ git config --global --add difftool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
$ git config --global --add difftool.kdiff3.trustExitCode false

(Pamiętaj, aby zastąpić ścieżkę rzeczywistą ścieżką pliku exe Kdiff.)

Następnie za każdym razem, gdy napotkasz konflikt scalania, wystarczy uruchomić polecenie:

$git mergetool

Następnie otwiera Kdiff3 i najpierw próbuje automatycznie rozwiązać konflikty scalania. Większość konfliktów zostałaby rozwiązana spontanicznie, a resztę trzeba naprawić ręcznie.

Oto jak wygląda Kdiff3:

Wpisz opis zdjęcia tutaj

Następnie, gdy skończysz, zapisz plik, a on przejdzie do następnego pliku z konfliktem i robisz to samo, dopóki wszystkie konflikty nie zostaną rozwiązane.

Aby sprawdzić, czy wszystko zostało pomyślnie scalone, po prostu ponownie uruchom komendę scaletool, powinieneś otrzymać ten wynik:

$git mergetool
No files need merging
akazemis
źródło
8

Te odpowiedzi to dodanie alternatywy dla użytkowników VIM, takich jak ja, którzy wolą robić wszystko w edytorze.


TL; DR

wprowadź opis zdjęcia tutaj


Tpope wymyślił tę świetną wtyczkę dla VIM, zwaną zbiegiem . Po zainstalowaniu możesz uruchomić, :Gstatusaby sprawdzić pliki, które powodują konflikty i:Gdiff otworzyć Git na trzy sposoby scalania.

Po połączeniu w 3-kierunkowy sposób zbieg pozwoli ci uzyskać zmiany w dowolnej z łączonych gałęzi w następujący sposób:

  • :diffget //2, uzyskaj zmiany z oryginalnej gałęzi ( HEAD ):
  • :diffget //3, uzyskaj zmiany z łączącej się gałęzi:

Po zakończeniu scalania pliku wpisz :Gwritescalony bufor. Vimcasts opublikowało świetny film szczegółowo wyjaśniający te kroki.

Vicente Bolea
źródło
6

Gitlense For VS Code

Możesz wypróbować Gitlense dla VS Code. Najważniejsze z nich to:

3. Łatwe rozwiązywanie konfliktów.

Już podoba mi się ta funkcja:

wprowadź opis zdjęcia tutaj

2. Bieżąca wina linii.

wprowadź opis zdjęcia tutaj

3. Wina rynny

wprowadź opis zdjęcia tutaj

4. Wina na pasku stanu

wprowadź opis zdjęcia tutaj

Istnieje wiele funkcji, które możesz sprawdzić tutaj .

Ilyas Karim
źródło
5

git fetch
git sprawdź swój oddział
git rebase master

W tym kroku spróbujesz naprawić konflikt przy użyciu preferowanego IDE

Możesz użyć tego linku, aby sprawdzić ho, aby rozwiązać konflikt w pliku
https://help.github.com/articles/resolving-a-merge-conflict-using-the-command-line/

git dodaj
git rebase - kontynuuj
git commit - popraw
git push origin HEAD: refs / draughts / master (push jak draughts)

Teraz wszystko jest w porządku i znajdziesz swoje zatwierdzenie w gerrit

Mam nadzieję, że pomoże to każdemu w tej sprawie.

Baini.Marouane
źródło
3

Wypróbuj kod Visual Studio Code do edycji, jeśli jeszcze tego nie zrobiłeś. Robi to po próbie scalenia (i pojawia się w konflikcie scalania). Kod VS automatycznie wykrywa konflikty scalania.

To może pomóc bardzo dobrze, pokazując jakie są zmiany wprowadzone do pierwotnego i należy przyjąć incominglub

current change(czyli oryginalny przed scaleniem) „?.

Pomogło mi i może również działać dla ciebie!

PS: Będzie działać tylko wtedy, gdy skonfigurowałeś git za pomocą swojego kodu i Visual Studio Code.

Kailash Bhalaki
źródło
2

Bezpieczniejszym sposobem rozwiązywania konfliktów jest użycie git-mediate (najczęściej sugerowane rozwiązania to imho podatne na błędy).

Zobacz ten post, aby uzyskać krótkie wprowadzenie na temat korzystania z niego.

yairchu
źródło
2

Dla tych, którzy używają Visual Studio (2015 w moim przypadku)

  1. Zamknij swój projekt w VS. Zwłaszcza w dużych projektach VS ma tendencję do wariowania podczas łączenia za pomocą interfejsu użytkownika.

  2. Wykonaj scalanie w wierszu polecenia.

    git Checkout target_branch

    git merge source_branch

  3. Następnie otwórz projekt w VS i przejdź do Team Explorer -> Oddział. Teraz pojawia się komunikat z informacją, że scalanie jest w toku, a konfliktowe pliki znajdują się bezpośrednio pod komunikatem.

  4. Kliknij plik powodujący konflikt, a pojawi się opcja Scal, porównaj, pobierz źródło, wybierz cel. Narzędzie do scalania w VS jest bardzo łatwe w użyciu.

Mikrofon
źródło
Używam VS Code 2017 do bardzo dużego projektu i nie muszę go zamykać.
Radzi
2

Jeśli używasz intelliJ jako IDE Spróbuj połączyć rodzica do swojego oddziału przez

git checkout <localbranch>
git merge origin/<remotebranch>

Pokaże wszystkie takie konflikty

A_MBPro: test anu $ git merge origin / Auto-scaling src / test / java / com /.../ TestClass.java CONFLICT (content): Scal konflikt w src / test / java / com /.../ TestClass.java

Zauważ teraz, że plik TestClass.java jest pokazany na czerwono w intelliJ Wyświetlany jest również status git

Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified:   src/test/java/com/.../TestClass.java

Otwórz plik w intelliJ, będzie miał sekcje z

  <<<<<<< HEAD
    public void testMethod() {
    }
    =======
    public void testMethod() { ...
    }
    >>>>>>> origin/<remotebranch>

gdzie HEAD to zmiany w lokalnym oddziale i pochodzenie / to zmiany ze zdalnego oddziału. Tutaj zachowaj potrzebne rzeczy i usuń niepotrzebne rzeczy, a następnie wykonaj zwykłe czynności. To jest

   git add TestClass.java
   git commit -m "commit message"
   git push
AJC
źródło
2

Używam kodu wizualnego Microsoft do rozwiązywania konfliktów. Jest bardzo prosty w użyciu. Trzymam mój projekt otwarty w obszarze roboczym. Wykrywa i podkreśla konflikty, a ponadto daje opcje GUI, aby wybrać dowolną zmianę, którą chcę zachować z HEAD lub przychodzących. wprowadź opis zdjęcia tutaj

Ammar Mujeeb
źródło