Rozwiąż konflikty scalania Git na korzyść ich zmian podczas ściągania

1225

Jak rozwiązać konflikt scalania git na korzyść wycofanych zmian?

Zasadniczo muszę usunąć wszystkie sprzeczne zmiany z działającego drzewa bez konieczności przechodzenia przez wszystkie konflikty z git mergetoolzachowaniem wszystkich zmian wolnych od konfliktów. Najlepiej robić to podczas ciągnięcia, a nie później.

sanmai
źródło
2
Duplikat git pull ze zdalnego .. czy mogę zmusić go do zastąpienia zamiast zgłaszania konfliktów? Możesz zobaczyć tam to samo rozwiązanie.
Dan Dascalescu
3
@DanDascalescu Zaakceptowana odpowiedź nie zawiera odpowiedzi na te pytania, więc wyraźnie nie jest to duplikat. Co więcej, to drugie pytanie jest dość dwuznaczne: bardzo trudno jest powiedzieć, o co się pyta. W sumie nie mogę się z tobą zgodzić. Co masz na myśli?
sanmai
2
@sanmai Masz dwie odpowiedzi - i zaakceptowałeś jedną z nich. Czy możesz lepiej wyjaśnić, czego oczekujesz w odpowiedzi i o ile więcej szczegółów chcesz tutaj?
Edward Thomson,
2
@EdwardThomson cóż, tak naprawdę myślałem, aby dać tę reputację na pierwszą odpowiedź, ale jeśli zapytasz, mogę poczekać i zobaczyć, czy pojawi się lepsza odpowiedź
sanmai

Odpowiedzi:

1217
git pull -s recursive -X theirs <remoterepo or other repo>

Lub po prostu dla domyślnego repozytorium:

git pull -X theirs

Jeśli jesteś już w stanie konfliktu ...

git checkout --theirs path/to/file
Taryfy Pascala
źródło
40
Pamiętaj, że -s recursivetutaj jest to zbędne, ponieważ jest to domyślna strategia scalania. Możesz więc to uprościć git pull -X theirs, co w zasadzie jest równoważne z git pull --strategy-option theirs.
5
Jeśli to zrobię, wrócę do MERGINGstanu. Mogę wtedy git merge --aborti spróbować ponownie, ale za każdym razem kończę się połączeniem. … Wiem jednak, że został przekazany rebase do mojego górnego biegu, więc może to powoduje?
Benjohn
22
Ostrożnie z git checkout --theirs path/to/file. Użyłem go podczas rebase i uzyskałem nieoczekiwane wyniki. Znaleziono wyjaśnienie w dokumencie: Zauważ, że podczas git rebase i git pull --rebase, nasze i ich mogą się zamieniać; --ours podaje wersję z gałęzi, na której zmiany są oparte, a - theirs podaje wersję z gałęzi, która zawiera twoją pracę, która jest zmieniana.
Vuk Djapic,
10
Zauważ, że git checkout --theirs/--ours pathstrona podręcznika man stwierdza, że ​​działa dla nie połączonych ścieżek . Więc jeśli nie było konfliktu na ścieżce, jest już scalone, to polecenie nic nie zrobi. Może to powodować problemy, gdy chcesz na przykład „ich” wersję całego podfolderu. W takim przypadku bezpieczniej byłoby zrobić git checkout MERGE_HEAD pathlub użyć skrótu zatwierdzenia.
fsw
4
git pull -X theirstworzy zatwierdzenie scalania, jeśli występują konflikty (np. jeśli inny program uruchamiający podbiegł git push -fdo pilota). Jeśli nie chcesz zatwierdzać scalania, uruchom zamiast tego git fetch && git reset --hard origin/master.
Dan Dascalescu
985

Można użyć „ich” Strategia rekurencyjną opcji :

git merge --strategy-option theirs

Od mężczyzny :

ours
    This option forces conflicting hunks to be auto-resolved cleanly by 
    favoring our version. Changes from the other tree that do not 
    conflict with our side are reflected to the merge result.

    This should not be confused with the ours merge strategy, which does 
    not even look at what the other tree contains at all. It discards 
    everything the other tree did, declaring our history contains all that
    happened in it.

theirs
    This is opposite of ours.

Uwaga: ponieważ strona mężczyzna mówi, w „nasze” scalanie opcja strategia jest bardzo różni się od „nasze” seryjnej strategii .

Ikke
źródło
Oto bardziej szczegółowe wyjaśnienie: lostechies.com/joshuaflanagan/2010/01/29/…
mPrinC
227
Również git checkout --theirsdo obsługi pojedynczego pliku będącego w konflikcie
dvd
48
To nie działa, jeśli jesteś już w stanie rozwiązania konfliktu. W takim przypadku uważam, że najlepszym sposobem na rozwiązanie tego jest git checkout <ref to theirs> -- the/conflicted.file; a następnie git addich zmiany.
ThorSummoner,
54
@ThorSummoner W takim przypadku istnieje git checkout - ich ścieżka / pliku / pliku. W ten sposób nie musisz ręcznie szukać poprawnego skrótu.
Ikke,
8
@Ikke To powinna być w zasadzie własna odpowiedź (i zaakceptowana odpowiedź), jeśli mnie o to poprosisz.
ThorSummoner
473

Jeśli jesteś już w stanie konfliktu i chcesz po prostu zaakceptować wszystkie :

git checkout --theirs .
git add .

Jeśli chcesz zrobić odwrotnie:

git checkout --ours .
git add .

Jest to dość drastyczne, więc upewnij się, że naprawdę chcesz wyczyścić wszystko w ten sposób, zanim to zrobisz.

wiele do nauczenia się
źródło
47
lub nie używaj .i określ plik (i) zamiast kropki, którą chcesz pobrać. prawdopodobnie mniej „drastyczny” i dokładnie to, co chcesz zrobić.
manroe
10
to nie działa, jeśli plik został usunięty z drugiej gałęzi: „<plik>” nie ma swojej wersji
Japster24
3
Głosowałbym więcej, gdybym mógł, co jakiś czas wracam do tej odpowiedzi.
tarikki
6
Użyj git add -uzamiast tego, aby pominąć pliki, które nie są pod kontrolą wersji.
Sudipta Basak
3
Hipotetyczny przypadek, trzy zmiany w pliku, jedna sprzeczna, dwie bez konfliktu, czy to rozwiązanie zastosowałoby zmiany niesprzeczne i rozwiązałoby naszą sprzeczną zmianę? Czy może wystarczyłaby tylko nasza wersja ignorując sprzeczne z nią zmiany?
pedromarce
222

OK, więc wyobraź sobie scenariusz, w którym właśnie byłem:

Próbujesz merge, a może i cherry-pick, i jesteś zatrzymany

$ git cherry-pick 1023e24
error: could not apply 1023e24... [Commit Message]
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

Teraz widzisz plik będący w konflikcie i naprawdę nie chcesz zachować swoich zmian. W moim przypadku powyżej plik był w konflikcie tylko w nowej linii, którą moje IDE dodało automatycznie. Aby cofnąć zmiany i zaakceptować ich, najprostszym sposobem jest:

git checkout --theirs path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

W przeciwieństwie do tego (aby zastąpić wersję przychodzącą wersją):

git checkout --ours path/to/the/conflicted_file.php
git add path/to/the/conflicted_file.php

Zaskakujące, że nie mogłem znaleźć tej odpowiedzi bardzo łatwo w sieci.

Theodore R. Smith
źródło
15
Zauważ, że jeśli wykonasz git statuspomiędzy checkouti add, plik nadal będzie wyświetlany jako „oba zmodyfikowane”.
biskup
Czy wiesz, czy można to zrobić dla wszystkich plików w stanie konfliktu? Jeśli tak, byłoby to miłe rozszerzenie twojej odpowiedzi.
Drew Noakes
2
Robię to: git reset --hard a następnie git pull [remote server name] [branch name] -Xtheirs(cofa scalanie, a następnie ciągnie nowe elementy na moje) - nie jestem pewien, czy tego właśnie chcesz.
ssaltman
38

W git pull -X theirsodpowiedzi mogą tworzyć brzydkie scalającej, lub wydania

błąd: lokalne zmiany następujących plików zostaną zastąpione przez scalenie:

Jeśli chcesz po prostu zignorować wszelkie lokalne modyfikacje plików z repozytorium, na przykład na kliencie, który zawsze powinien być kopią lustrzaną źródła, uruchom to (zamień masterna gałąź, którą chcesz):

git fetch && git reset --hard origin/master

Jak to działa? git fetchrobi, git pullale bez łączenia . Następnie git reset --harddopasowuje działające drzewo do ostatniego zatwierdzenia. Wszystkie lokalne zmiany w plikach w repozytorium zostaną odrzucone , ale nowe pliki lokalne pozostaną same.

Dan Dascalescu
źródło
1
+1 - git fetch && git reset --hard {remote}/{branch}rozwiązało mój problem. Musiałem całkowicie porzucić własne zmiany na korzyść „ich” stanu gałęzi, ale git pull -X theirsdusiły się w niektórych plikach przeniesionych / o zmienionej nazwie. Dzięki!
Ivaylo Slavov
22

Po połączeniu git, jeśli masz konflikty i chcesz albo swoje, albo ich

git checkout --theirs .
git checkout --ours .
Mohit Kanojia
źródło
Jak miałbym to zrobić w rozbiciu na poszczególne porcje? Powyższe działa na poziomie pliku, wyrzucając wszystkie nie powodujące konfliktu fragmenty, które może mieć plik powodujący konflikt.
Jani
21

Aby rozwiązać wszystkie konflikty z wersją w określonej gałęzi:

git diff --name-only --diff-filter=U | xargs git checkout ${branchName}

Tak więc, jeśli jesteś już w stanie scalenia i chcesz zachować wersję główną plików w konflikcie:

git diff --name-only --diff-filter=U | xargs git checkout master
Ariel Alvarez
źródło
A jak to się tłumaczy dla osób korzystających z systemu Windows bez dostępu do xargsów rurowych?
tsemer,
Czy nie pominie całkowicie twoich zmian? Nawet te, które nie są w stanie konfliktu?
Valentin Heinitz
Tak właśnie skończyłem. Niestety to następnie wymaga albo git cherry-pick --continue czy jest git commit --allow-emptypolecenie popełnienia tych zmian, i wydaje się, że żaden system, za którym wymagane jest polecenie, które sprawia, że automatyzację ten ból. Obecnie rozwiązuję ten problem, sprawdzając, czy .git/COMMIT_EDITMSGplik istnieje , ale wydaje się to hacking i kruche, i nie jestem jeszcze przekonany, że zawsze działa.
Konrad Rudolph
Jest to dobre, oznacza to, że jeśli ręcznie rozwiążesz niektóre (i zrobisz git add), możesz przez to rozwiązać zbiorczo. git checkout --ours/ też git checkout --theirsjest przydatne.
rcoup
18

Proszę nie, że czasami to nie zadziała :

git checkout - nasza ścieżka / do / pliku

lub

git checkout - ich ścieżka / do / pliku

Zrobiłem to zamiast tego, zakładając, że HEAD należy do nas, a MERGE_HEAD należy do nich

git checkout HEAD -- path/to/file

lub:

git checkout MERGE_HEAD -- path/to/file

Gdy to zrobimy i będziemy dobrze:

git add .

Jeśli chcesz dowiedzieć się więcej, zobacz wspaniały wpis torek tutaj: git checkout - nasze pliki nie usuwają plików z listy nie połączonych plików

Nicolas D.
źródło
12

Użytkownicy IDE Code (zintegrowany Git):

Jeśli chcesz zaakceptować wszystkie nadchodzące zmiany w pliku konfliktu, wykonaj następujące czynności.

1. Go to command palette - Ctrl + Shift + P
2. Select the option - Merge Conflict: Accept All Incoming

Podobnie możesz zrobić dla innych opcji, takich jak Akceptuj wszystkie oba, Akceptuj wszystkie bieżące itp.,

SridharKritha
źródło
2
Wydaje się, że działa to tylko dla jednego pliku, ale nie dla wszystkich plików z konfliktami.
Yoryo
1

Miałem długo działającą next-versiongałąź z mnóstwem usunięć plików, które się zmieniły develop, plików dodanych w różnych miejscach obu gałęzi itp.

Chciałem wziąć całą zawartość next-versionoddziału develop, wszystko w jednym wielkim zatwierdzeniu scalania.

Kombinacja powyższych poleceń, która działała dla mnie, była:

git merge -X theirs next-version
# lots of files left that were modified on develop but deleted on next-version
git checkout next-version .
# files removed, now add the deletions to the commit
git add .
# still have files that were added on develop; in my case they are all in web/
git rm -r web

Nie nowa odpowiedź, po prostu łączenie fragmentów z wielu odpowiedzi, częściowo po to, aby upewnić się, że możesz potrzebować wszystkich tych odpowiedzi.

Gordon
źródło
1

Jeśli jesteś już w stanie konfliktu i nie chcesz pobierać ścieżki pojedynczo. Możesz spróbować

git merge --abort
git pull -X theirs
Lee Chee Kiam
źródło
-1

od https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging

Zasadniczo spowoduje to fałszywe scalenie. Będzie rejestrować nowy zatwierdzenie scalania z oboma oddziałami jako rodzicami, ale nawet nie spojrzy na gałąź, w której się scalasz. Po prostu zapisze w wyniku scalenia dokładny kod w bieżącej gałęzi.

$ git merge -s ours mundo

Scalenie wykonane przez strategię „naszą”.

$ git diff HEAD HEAD~

Widać, że nie ma różnicy między gałęzią, w której byliśmy, a wynikiem połączenia.

Często może to być przydatne, aby Git pomyślał, że gałąź jest już scalona podczas późniejszego scalania. Załóżmy na przykład, że rozgałęziłeś gałąź wydania i zrobiłeś nad nią trochę pracy, którą w pewnym momencie będziesz chciał z powrotem połączyć z gałęzią master. W międzyczasie niektóre poprawki na masterie muszą zostać przeniesione do twojej gałęzi wydania. Możesz scalić gałąź poprawki błędów z gałęzią wydania, a także scalić naszą gałąź z gałęzią master (nawet jeśli poprawka już istnieje), więc kiedy później ponownie scalisz gałąź wydania, nie będzie żadnych konfliktów z poprawką.

Sytuacja okazała się przydatna, jeśli chcę, aby master odzwierciedlał zmiany w nowej gałęzi tematów. Zauważyłem, że -Xtheirs nie łączą się bez konfliktów w niektórych okolicznościach ... np

$ git merge -Xtheirs topicFoo 

CONFLICT (modify/delete): js/search.js deleted in HEAD and modified in topicFoo. Version topicFoo of js/search.js left in tree.

W tym przypadku znalazłem rozwiązanie

$ git checkout topicFoo

from topicFoo, pierwsze scalenie w master przy użyciu strategii -s nasza, spowoduje to utworzenie fałszywego zatwierdzenia, które jest stanem topicFoo. $ git merge - nasz mistrz

sprawdź utworzone zatwierdzenie scalania

$ git log

teraz sprawdź gałąź master

$ git checkout master

połącz gałąź tematów z powrotem, ale tym razem skorzystaj ze strategii rekurencyjnej -Xtheirs, teraz zobaczysz gałąź główną ze stanem topicFoo.

$ git merge -X theirs topicFoo
Amos Folarin
źródło