Выберите стратегию слияния Git для определенных файлов («наши», «мои», «их»)

207

Я нахожусь в середине перебазирования после git pull --rebase. У меня есть несколько файлов, которые имеют конфликты слияния. Как я могу принять "их" изменения или "мои" изменения для определенных файлов?

$ 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

Обычно я просто открываю файл или инструмент слияния и вручную принимаю все «их» или «мои» изменения. Однако я подозреваю, что мне не хватает удобной команды git.

Также обратите внимание, что я смогу выбрать стратегию слияния для каждого файла только тогда, когда увижу, какие файлы попадают в конфликты и, возможно, конфликты.

Стивен Векслер
источник
@AbeVoelker Я не думаю, что это решает мою проблему. Я хочу выбрать стратегию слияния для конкретных файлов. Кроме того, обратите внимание, что я буду знать, какую стратегию слияния использовать, только когда я перезагружаюсь, и видеть, какие файлы столкнулись с конфликтами и каковы конфликты.
Стивен Векслер
Я отредактировал этот вопрос, чтобы он был более общим: stackoverflow.com/questions/278081/… . Может быть, мы можем закрыть этот вопрос как дубликат этого? Это уместно?
@ TheShadow Это кажется мне разумным.
Стивен Векслер
Я не был уверен, что было бы уместно изменить название другого вопроса на то, что я сделал, потому что я взял часть о разрешении двоичных файлов. Я вернул другой вопрос к тому, что было раньше, поэтому этот текущий вопрос все еще добавляет ценности.

Ответы:

251

Для каждого конфликтующего файла вы можете указать

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

Из git checkoutдокументов

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

--ours
--theirs
При проверке путей из индекса, проверьте этап № 2 ( ours) или № 3 ( theirs) для неотключенных путей.

Индекс может содержать необъединенные записи из-за предыдущего неудачного слияния. По умолчанию, если вы попытаетесь извлечь такую ​​запись из индекса, операция извлечения не будет выполнена и ничего не будет извлечено. Использование -fбудет игнорировать эти необработанные записи. Содержимое определенной стороны слияния можно извлечь из индекса с помощью --oursили --theirs. С помощью -mизменений, внесенных в файл рабочего дерева, можно отказаться, чтобы заново создать исходный конфликтующий результат слияния.


источник
9
Можно ли принять их для всех файлов, которые остались в архиве?
aslakjo
42
@aslakjo git rebase -s recursive -X <ours/theirs>или git merge -s recursive -X <ours/theirs>. Имейте в виду, что для ребазинга «наши» и «их» полностью противоположны тому, что они есть во время слияния. Возможно, вы могли бы просто использовать глобус файла / оболочки, например git checkout --theirs -- *.txt.
2
Большое спасибо, @Cupcake, неожиданное обращение ours/theirsс rebase сводило меня с ума !! (Теперь имеет смысл подумать о том, как на самом деле работает ребаз, но совсем не интуитивно.)
Дэн Ленски,
2
@DanLenski rebase в целом - это просто очень сложный инструмент, который люди могут понять вначале, но как только вы поймете, как он работает, вы сможете делать с ним все действительно мощные вещи.
1
На самом деле @VincentSels, вам нужно замаскировать символ *, иначе оболочка попытается его развернуть. так что в вашем случае git checkout --outs -- "**/*.csproj"будет делать то, что вы имеете в виду. То же самое верно, например, для git lfs track "*.jpg". Если у вас есть несколько jpg-файлов в вашем CWD без кавычек, отслеживаются только они.
eFloh
117

Несмотря на то, что на этот вопрос дан ответ, приведем пример того, что означает «их» и «наш» в случае git rebase vs merge. Смотрите эту ссылку

Git Rebase
theirs - это текущая ветка в случае rebase . Таким образом, приведенный ниже набор команд фактически принимает ваши текущие изменения ветки через удаленную ветку.

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

Git Merge
Для слияния , смысл theirsи oursобратный. Таким образом, чтобы получить тот же эффект во время слияния , т. Е. Сохранить текущие изменения ветви ( ours) над удаленной ветвью слияния ( theirs).

# assuming branch-a is our current version
$ git merge -X ours branch-b  # <- ours: branch-a, theirs: branch-b
Abe
источник
2
ну, это довольно важное различие! Спасибо за разъяснение.
verboze
26

Обратите внимание , что git checkout --ours|--theirsбудет перезаписывать файлы целиком , выбирая либо theirsилиours вариант, который может быть или не может быть то , что вы хотите сделать (если у вас есть какие - либо не-конфликтующие изменения , приходящие с другой стороны, они будут потеряны).

Если вместо этого вы хотите выполнить трехстороннее объединение файла и разрешить только конфликтующие блоки, используя --ours|--theirs, оставив при этом бесконфликтные блоки с обеих сторон, вы можете прибегнуть к помощи git merge-file; подробности смотрите в этом ответе .

jakub.g
источник
1
Относительно «неконфликтующих изменений», которые будут потеряны - это относится только к файлам, в которых есть неконфликтующие изменения в определенных строках, где-то в том же файле, или ко всем изменениям из всех файлов в выровненных историях?
ktamlyn
2
@ktamlyn под «неконфликтующими изменениями» я имел в виду изменения в одном и том же файле. Например, example.txtв oursверсии есть два измененных фрагмента (части) , один конфликтует (также изменен в theirsредакции), другой не конфликтует. Если вы это сделаете git checkout --theirs example.txt, он будет просто вслепую читать весь файл при theirsревизии, и несогласованная часть различий будет потеряна.
Jakub.g
1
Спасибо! Это было необходимым разъяснением для меня, хотя «изменения в одном файле» в этом контексте имеют наибольшее значение.
ktamlyn
Это должен быть принятый ответ, ну, хотя он и не дает ответа, но указывает на важную проблему в другом предложенном решении.
Томасяны
1
Если вы хотите вернуться к исходному конфликтующему файлу, вы можете запустить git checkout --merge <path>.
Эндрю Китон