Rozwiązywanie konfliktu Git z plikami binarnymi

464

Korzystam z Git w systemie Windows (msysgit), aby śledzić zmiany w niektórych pracach projektowych.

Dzisiaj pracowałem na innym komputerze (ze zdalnym repozytorium brian) i teraz próbuję scalić zmiany dokonane dzisiaj z powrotem w mojej zwykłej lokalnej wersji na moim laptopie.

Na laptopie git pull brian masterściągałem zmiany do mojej lokalnej wersji. Wszystko było w porządku oprócz głównego dokumentu InDesign - to pokazuje konflikt.

Wersja na PC ( brian) to najnowsza wersja , którą chcę zachować, ale nie wiem, jakie polecenia każą repozytorium użyć tej wersji.

Próbowałem bezpośrednio skopiować plik na mój laptop, ale wydaje się, że to przerywa cały proces scalania.

Czy ktoś może skierować mnie we właściwym kierunku?

Kevin Wilson
źródło

Odpowiedzi:

853

git checkoutakceptuje opcję --ourslub --theirsdla takich przypadków. Więc jeśli masz konflikt scalania i wiesz, że chcesz tylko plik z gałęzi, w której się scalasz, możesz:

$ git checkout --theirs -- path/to/conflicted-file.txt

użyć tej wersji pliku. Podobnie, jeśli wiesz, że chcesz swojej wersji (a nie tej, którą się scalasz), możesz jej użyć

$ git checkout --ours -- path/to/conflicted-file.txt
mipadi
źródło
47
Musiałem uruchomić 'git reset HEAD path / to / conflicted-file.txt' na pliku przed użyciem --ours, w przeciwnym razie nie miałoby to żadnego efektu.
Zitrax,
6
@Zitrax Czy różnicowałeś plik po uruchomieniu git checkout --ours? Strona podręcznika sugeruje (IMHO), że kasa --ours / - ich usunie zmianę z listy „oba zmodyfikowane, wymagają scalenia” i doda ją do indeksu, i myślę, że to nie jest poprawne. Wierzę, że będziesz musiał biec git addpo kasie.
Tim Keating
15
Uwaga: nadal chcesz wykonać polecenie „git add conflicted-file.txt ” i „git commit”. Przydało się, gdy próbowałem, komunikat zatwierdzenia został wstępnie wypełniony notatką o konflikcie.
Edward Falk,
2
frazowanie „gałęzi, w której się scalasz” jest niebezpiecznie zbliżone do „gałęzi, w której się scalasz”, myślę, że po prostu porzucenie przyimka byłoby lepsze: „gałąź, w której się scalasz”, co odzwierciedlałoby także polecenie git (tj git merge branch_name.).
andrybak
13
Kilka ważnych punktów, których zawsze brakuje w objaśnieniach tego tematu. Podczas wykonywania zmiany bazy zamiast scalania znaczenie --theiri --ourssą zamieniane, tj. --Their == aktualnie wyewidencjonowana gałąź, a --ours to gałąź, zwykle gałąź zdalna lub specyfikacja ścieżki, którą próbujesz scalić z bieżącą Oddział. W [space]--[space]disambiguates do ścieżki specyfikacji pomiędzy nazwą oddziału i ścieżkę ciemno, że zarówno zdarzyć istnieć o tej samej nazwie opcji (np istniejąca nazwa oddziału jest „abc” i katalog istnieje nazywany „abc”).
BoiseBaked,
147

Musisz ręcznie rozwiązać konflikt (kopiowanie pliku), a następnie zatwierdzić plik (bez względu na to, czy skopiowałeś go, czy używałeś wersji lokalnej) w ten sposób

git commit -a -m "Fix merge conflict in test.foo"

Git zwykle automatycznie zatwierdza po scaleniu, ale gdy wykryje konflikty, których nie może rozwiązać samodzielnie, stosuje wszystkie wymyślone łaty, a resztę pozostawia do rozwiązania i ręcznego zatwierdzenia. Strona Git Merge , kurs Crash Git-SVN lub ten wpis na blogu mogą rzucić nieco światła na to, jak to powinno działać.

Edycja: Zobacz post poniżej, tak naprawdę nie musisz samodzielnie kopiować plików, ale możesz z nich korzystać

git checkout --ours -- path/to/file.txt
git checkout --theirs -- path/to/file.txt

wybierz żądaną wersję pliku. Kopiowanie / edycja pliku będzie konieczne tylko wtedy, gdy chcesz mieszać obie wersje.

Proszę zaznaczyć odpowiedź mipadi jako prawidłową.

VolkA
źródło
1
Dziękuję za to. Nie byłem pewien, czy istnieje jakiś wbudowany sposób na oznaczenie pliku jako „poprawnego”. Wyjaśnia, dlaczego nie mogłem znaleźć nieistniejącego polecenia!
Kevin Wilson,
Tak, to trochę nieintuicyjne - coś w rodzaju rozwiązania git byłoby fajne, ale byłoby też dodatkowym krokiem ...
VolkA
120

Możesz również przezwyciężyć ten problem

git mergetool

co powoduje gitutworzenie lokalnych kopii skonfliktowanego pliku binarnego i odrodzenie na nim domyślnego edytora:

  • {conflicted}.HEAD
  • {conflicted}
  • {conflicted}.REMOTE

Oczywiście nie można pożytecznie edytować plików binarnych w edytorze tekstu. Zamiast tego skopiuj nowy {conflicted}.REMOTEplik {conflicted}bez zamykania edytora. Następnie po zamknięciu edytor gitzobaczy, że nieokreślona kopia robocza została zmieniona, a konflikt scalania został rozwiązany w zwykły sposób.

RobM
źródło
8
Jeśli pliki są duże lub w ogóle nie chcesz ryzykować otwierania pliku binarnego w edytorze tekstu, możesz nacisnąć ctrl + c po znaku zachęty scalania („ Hit return to start merge resolution tool”), a git pozostawi dodatkowe pliki na swoim miejscu. Następnie możesz je zmodyfikować lub połączyć w zewnętrzne narzędzie (przydatne w formatach dokumentów binarnych, takich jak LibreOffice / OpenOffice / MSWord) i zapisać wynik z powrotem do oryginalnej nazwy pliku. Aby poinformować gita, że ​​konflikt został rozwiązany, git addoryginalna nazwa pliku, a następnie możesz zakończyć zatwierdzanie scalania.
Felix
18

Aby rozwiązać problem, utrzymując wersję w bieżącym oddziale (zignoruj ​​wersję z gałęzi, w której się scalasz), po prostu dodaj i zatwierdź plik:

git commit -a

Aby rozwiązać problem, zastępując wersję w bieżącej gałęzi wersją z gałęzi, w której się scalasz, musisz najpierw pobrać tę wersję do katalogu roboczego, a następnie dodać / zatwierdzić:

git checkout otherbranch theconflictedfile
git commit -a

Wyjaśnione bardziej szczegółowo

Joshua Flanagan
źródło
1
Wolę ten wariant niż zaakceptowaną odpowiedź, ponieważ jest on bardziej intuicyjny, zwłaszcza biorąc pod uwagę, że znaczenie tych „--ours” i „--theirs” jest zamieniane w przypadku zmiany bazy.
Antony Hatchkins
11

Odpowiedź mipadi nie do końca działała, musiałem to zrobić:

git checkout --ours path / to / file.bin

lub, aby zachować scalanie wersji:

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

następnie

git dodaj ścieżkę / do / pliku.bin

A potem mogłem ponownie zrobić „git scaletool” i przejść do następnego konfliktu.

kris
źródło
6

Z git checkoutdokumentów

git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...

--ours
--theirs
Podczas sprawdzania ścieżek z indeksu sprawdź etap # 2 ( ours) lub # 3 (theirs ) pod kątem nie połączonych ścieżek.

Indeks może zawierać niepołączone wpisy z powodu poprzedniego nieudanego scalenia. Domyślnie, jeśli spróbujesz wyewidencjonować taki wpis z indeksu, operacja pobierania zakończy się niepowodzeniem i nic nie zostanie wyewidencjonowane. Użycie -fspowoduje zignorowanie tych niepołączonych wpisów. Zawartość z określonej strony scalania można sprawdzić w indeksie za pomocą --ourslub --theirs. Za pomocą -mzmian dokonanych w działającym pliku drzewa można odrzucić, aby odtworzyć oryginalny wynik scalenia będącego w konflikcie.

użytkownik456814
źródło
4

Zetknąłem się z podobnym problemem (chciałem pobrać zatwierdzenie, które zawierało niektóre pliki binarne, które powodowało konflikty po scaleniu), ale natknąłem się na inne rozwiązanie, które można wykonać w całości za pomocą git (tj. Bez konieczności ręcznego kopiowania plików). Pomyślałem, że dołączę to tutaj, więc przynajmniej pamiętam, kiedy następnym razem będę go potrzebować. :) Kroki wyglądają tak:

% git fetch

Pobiera najnowsze zatwierdzenia z zdalnego repozytorium (w zależności od konfiguracji może być konieczne określenie nazwy oddziału), ale nie próbuje się połączyć. Zapisuje zatwierdzenie w FETCH_HEAD

% git checkout FETCH_HEAD stuff/to/update

Spowoduje to pobranie kopii plików binarnych, które chcę, i zastąpienie zawartości drzewa roboczego wersją pobraną ze zdalnej gałęzi. git nie próbuje scalać, więc kończy się dokładna kopia pliku binarnego ze zdalnej gałęzi. Gdy to zrobisz, możesz dodać / zatwierdzić nową kopię tak jak zwykle.

Brian Webster
źródło
4

Ta procedura ma na celu rozwiązanie konfliktów plików binarnych po przesłaniu żądania ściągnięcia do Github:

  1. W przypadku Github okazało się, że żądanie ściągnięcia ma konflikt z plikiem binarnym.
  2. Teraz wróć do tego samego oddziału git na komputerze lokalnym.
  3. Ty (a) ponownie tworzysz / ponownie kompilujesz ten plik binarny i (b) zatwierdzasz wynikowy plik binarny do tej samej gałęzi git.
  4. Następnie ponownie wypychasz tę samą gałąź git do Github.

W Github na żądanie ściągnięcia konflikt powinien zniknąć.

David M Lee
źródło
Właśnie takiej procedury potrzebuję
Huifang Feng
2

Jeśli plik binarny to coś więcej niż dll lub coś, co można edytować bezpośrednio jak obraz, lub plik mieszany (i nie musisz wyrzucać / wybierać jednego lub drugiego pliku), prawdziwe scalenie wyglądałoby tak:

Proponuję poszukać narzędzia różnicującego zorientowanego na plik binarny, na przykład istnieją pewne darmowe na przykład dla plików graficznych

i porównaj je.

Jeśli nie ma narzędzia do porównywania plików, to jeśli masz oryginalny generator pliku bin (to znaczy, istnieje dla niego edytor ... jak blender 3d, możesz następnie ręcznie sprawdzić te pliki, również przejrzyj dzienniki i zapytaj drugą osobę, co powinieneś dołączyć) i zrób pliki wyjściowe za pomocą https://git-scm.com/book/es/v2/Git-Tools-Advanced-Merging#_manual_remerge

$ git show :1:hello.blend > hello.common.blend $ git show :2:hello.blend > hello.ours.blend $ git show :3:hello.blend > hello.theirs.blend

tyoc213
źródło
1

Natknąłem się na dwie strategie zarządzania różnicowaniem / scalaniem plików binarnych za pomocą Git w systemie Windows.

  1. Tortoise git pozwala skonfigurować narzędzia porównywania / scalania dla różnych typów plików na podstawie ich rozszerzeń. Zobacz 2.35.4.3. Zaawansowane ustawienia Diff / Merge http://tortoisegit.org/docs/tortoisegit/tgit-dug-settings.html . Ta strategia oczywiście polega na dostępności odpowiednich narzędzi porównywania / scalania.

  2. Korzystając z atrybutów git, możesz określić narzędzie / komendę do konwersji pliku binarnego na tekst, a następnie pozwolić na to domyślne narzędzie do porównywania / scalania. Widzieć http://git-scm.com/book/it/v2/Customizing-Git-Git-Attributes . W artykule podano nawet przykład wykorzystania metadanych do różnicowania obrazów.

Mam obie strategie do pracy z plikami binarnymi modeli oprogramowania, ale poszliśmy z Tortoise Git, ponieważ konfiguracja była łatwa.

BoJohDoh
źródło
0

Korzystam z Git Workflow dla programu Excel - https://www.xltrail.com/blog/git-workflow-for-excel , aby rozwiązać większość problemów związanych z scalaniem plików binarnych. Ta aplikacja typu open source pomaga mi wydajnie rozwiązywać problemy bez poświęcania zbyt wiele czasu i pozwala mi bez problemu wybrać odpowiednią wersję pliku.

Siddhartha Thota
źródło
0

moja sprawa wydaje się być błędem .... używając git 2.21.0

Zrobiłem pull ... narzekałem na pliki binarne:

warning: Cannot merge binary files: <path>
Auto-merging <path>
CONFLICT (content): Merge conflict in <path>
Automatic merge failed; fix conflicts and then commit the result.

A potem nic w żadnej z odpowiedzi tutaj nie skutkowało jakimkolwiek wyjściem, który miałby sens.

Jeśli spojrzę na plik, który mam teraz ... to ten, który edytowałem. Jeśli to zrobię:

git checkout --theirs -- <path>
git checkout --ours -- <path>

Otrzymuję wynik:

Updated 0 paths from the index

i wciąż mam swoją wersję pliku. Jeśli mam rm, a następnie kasę, zamiast tego powie 1, ale nadal daje mi moją wersję pliku.

git Fibletool mówi

No files need merging

i mówi status git

    All conflicts fixed but you are still merging.
    (use "git commit" to conclude merge)

Jedną z opcji jest cofnięcie zatwierdzenia ... ale miałem pecha i miałem wiele zmian, a ten zły był pierwszy. Nie chcę tracić czasu na powtarzanie tego.

aby rozwiązać to szaleństwo:

Właśnie pobiegłem

git commit

która traci wersję zdalną i prawdopodobnie marnuje miejsce na przechowywanie dodatkowego pliku binarnego ... wtedy

git checkout <commit where the remote version exists> <path>

co zwraca mi wersję zdalną

następnie ponownie edytowałem plik ... a następnie zatwierdzaj i wypychaj, co prawdopodobnie oznacza marnowanie miejsca na inną kopię pliku binarnego.

Piotr
źródło
W moim przypadku po próbie git checkout --ours <path>otrzymania Updated 0 paths from the index . Naprawiłem to za pomocą git add <path>polecenia, które robi to samo.
Andriy