Wybierz strategię scalania Git dla określonych plików („nasz”, „mój”, „ich”)

207

Jestem w trakcie rebasingu po git pull --rebase. Mam kilka plików, które mają konflikty scalania. Jak mogę zaakceptować „ich” zmiany lub „moje” zmiany dla określonych plików?

$ git status
# Not currently on any branch.
# You are currently rebasing.
#   (fix conflicts and then run "git rebase --continue")
#   (use "git rebase --skip" to skip this patch)
#   (use "git rebase --abort" to check out the original branch)
#
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:  CorrectlyMergedFile
#
# Unmerged paths:
#   (use "git reset HEAD <file>..." to unstage)
#   (use "git add <file>..." to mark resolution)
#
#       both modified: FileWhereIWantToAcceptTheirChanges
#       both modified: FileWhereIWantToAcceptMyChanges

Zwykle po prostu otwieram plik lub narzędzie do scalania i ręcznie akceptuję wszystkie „ich” lub „moje” zmiany. Podejrzewam jednak, że brakuje mi wygodnego polecenia git.

Zauważ też, że będę mógł wybrać strategię scalania dla każdego pliku tylko wtedy, gdy zobaczę, które pliki uderzają w konflikty i być może takie są konflikty.

Steven Wexler
źródło
@AbeVoelker Nie sądzę, że to rozwiązuje mój problem. Chcę wybrać strategię scalania dla określonych plików. Zauważ też, że będę wiedział tylko, jakiej strategii scalania użyć, kiedy będę w mojej bazie, i zobaczę, które pliki dotknęły konfliktów i jakie są konflikty.
Steven Wexler
I edytowane to pytanie jest bardziej ogólna: stackoverflow.com/questions/278081/... . Może możemy zamknąć to pytanie jako duplikat tego? Czy to właściwe?
@TheShadow Wydaje mi się to rozsądne.
Steven Wexler
Nie byłem pewien, czy należy zmienić tytuł drugiego pytania na to, co zrobiłem, ponieważ wyjąłem część dotyczącą rozwiązywania plików binarnych. Drugie pytanie przywróciłem do tego, co było poprzednio, więc to aktualne pytanie wciąż stanowi wartość dodaną.

Odpowiedzi:

251

Dla każdego otrzymanego pliku będącego w konflikcie możesz określić

git checkout --ours -- <paths>
# or
git checkout --theirs -- <paths>

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.


źródło
9
Czy jest możliwe zaakceptowanie wersji dla wszystkich plików, które pozostały zmienione?
aslakjo,
41
@aslakjo git rebase -s recursive -X <ours/theirs>lub git merge -s recursive -X <ours/theirs>. Należy pamiętać, że w przypadku bazy „nasze” i „ich” są odwrócone od tego, czym są podczas łączenia. Prawdopodobnie możesz po prostu użyć globu pliku / powłoki, np git checkout --theirs -- *.txt.
2
Wielkie dzięki, @Cupcake, nieoczekiwane odwrócenie ours/theirsz rebase doprowadzało mnie do szaleństwa !! (Teraz myślę o tym, jak działa rebase, ale wcale nie jest intuicyjny).
Dan Lenski
2
@DanLenski rebase w ogóle jest po prostu bardzo trudnym narzędziem, które ludzie mogą zrozumieć na początku, ale kiedy już zrozumiesz, jak to działa, możesz robić z nim wszelkiego rodzaju naprawdę potężne rzeczy.
1
@ VincentSels faktycznie, musisz zamaskować znak *, w przeciwnym razie powłoka spróbuje go rozwinąć. więc w twoim przypadku git checkout --outs -- "**/*.csproj"zrobisz to, co masz na myśli. To samo dotyczy np git lfs track "*.jpg". Jeśli masz jakieś pliki jpg w swoim CWD, bez cudzysłowów, tylko te będą śledzone.
eFloh
117

Pomimo odpowiedzi na to pytanie, stanowi przykład tego, co „ich” i „nasze” oznaczają w przypadku git rebase vs scalanie. Zobacz ten link

Git Rebase
theirs jest tak naprawdę aktualną gałęzią w przypadku rebase . Tak więc poniższy zestaw poleceń akceptuje bieżące zmiany gałęzi w oddziale zdalnym.

# see current branch
$ git branch
... 
* branch-a
# rebase preferring current branch changes during conflicts
$ git rebase -X theirs branch-b

Git Merge
W przypadku scalania znaczenie theirsi oursjest odwrócone. Tak więc, aby uzyskać ten sam efekt podczas scalania , tzn. Zachowaj bieżące zmiany gałęzi ( ours) nad łączoną gałęzią zdalną ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b
Abe
źródło
2
to całkiem ważne rozróżnienie! dzięki za wytłumaczenie.
verboze
26

Zauważ, że git checkout --ours|--theirsbędzie nadpisać pliki całkowicie , wybierając albo theirsalboours wersja, która może być lub może nie być, co chcesz zrobić (jeśli masz jakiekolwiek zmiany nie kolidowały pochodzących z drugiej strony, zostaną one utracone).

Jeśli zamiast tego chcesz wykonać trzykrotne scalenie pliku i rozwiązywać tylko konfliktowe porcje za pomocą --ours|--theirs, zachowując bezkonfliktowe porcje po obu stronach, możesz skorzystać z git merge-file; zobacz szczegóły w tej odpowiedzi .

jakub.g
źródło
1
Jeśli chodzi o „zmiany, które nie powodują konfliktu”, które zostaną utracone - dotyczy to tylko plików, w których nie ma konfliktu zmian w określonych liniach w innym miejscu w tym samym pliku, lub wszystkich zmian ze wszystkich plików w wyrównanych historiach?
ktamlyn
2
@ktamlyn przez „zmiany nie powodujące konfliktu” Miałem na myśli zmiany w tym samym pliku. Na przykład, istnieją dwa zmienione hunks (części) w example.txtw ourswersji jedno jest skonfliktowany (też zmienić w theirsrewizji), drugi to nie kolidowały. Jeśli to zrobisz git checkout --theirs example.txt, po prostu ślepo odczyta cały plik podczas theirsrewizji, a niezróżnicowana część diff zostanie utracona.
jakub.g
1
Dzięki! To było dla mnie konieczne wyjaśnienie, mimo że „zmiany w tym samym pliku” mają w tym kontekście największy sens.
ktamlyn
To powinna być zaakceptowana odpowiedź, choć nie daje ona odpowiedzi, ale wskazuje na ważną kwestię w drugim proponowanym rozwiązaniu.
tomasyany
1
Jeśli chcesz wrócić do oryginalnego pliku będącego w konflikcie, możesz uruchomić git checkout --merge <path>.
Andrew Keeton