Простой инструмент "принять их" или "принять мой" на весь файл с помощью git

Мне не нужен инструмент визуального слияния, и я также не хочу, чтобы это противоречивый файл и вручную выбирал между HEAD (мой) и импортированным изменением (их). Большую часть времени я либо хочу, чтобы все их изменения или все мои. Обычно это происходит потому, что мои изменения сделали это upsteam и возвращаются ко мне через тягу, но могут слегка изменяться в разных местах.

Есть ли инструмент командной строки, который избавится от маркеров конфликта и будет выбирать все так или иначе в зависимости от моего выбора? Или набор команд git, которые я могу сделать для каждого из них.

# accept mine
alias am="some_sequence;of;commands"
alias at="some_other_sequence;of;commands"

Делать это довольно раздражает. "Принимаю мой", я пробовал:

[email protected] ~/linus $ git merge test-branch
Auto-merging Makefile
CONFLICT (content): Merge conflict in Makefile
Automatic merge failed; fix conflicts and then commit the result.

[email protected] ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

[email protected] ~/linus $ git reset --hard HEAD Makefile 
fatal: Cannot do hard reset with paths.

Как я должен избавиться от этих маркеров изменений?

Я могу сделать:

git reset HEAD Makefile; rm Makefile; git checkout Makefile

Но это кажется довольно крутым, должен быть лучший способ. И в этот момент я не уверен, что git даже думает, что произошло слияние, поэтому я не думаю, что это обязательно даже работает.

Иными словами, "принимать их" одинаково беспорядочно. Единственный способ понять это - сделать:

git show test-branch:Makefile > Makefile; git add Makefile;

Это также дает мне сообщение об ошибке, которое содержит конфликты: Makefile в нем дважды.

Кто-нибудь может указать, как сделать эти два действия более простым способом? Благодаря

Ответ 1

Решение очень простое. git checkout <filename> пытается проверить файл с индексом и, следовательно, сбой при слиянии.

Что вам нужно сделать (например, проверка фиксация):

Чтобы проверить свою версию, вы можете использовать одну из следующих функций:

git checkout HEAD -- <filename>

или

git checkout --ours -- <filename>

или

git show :2:<filename> > <filename> # (stage 2 is ours)

Чтобы проверить другую версию, вы можете использовать одну из следующих функций:

git checkout test-branch -- <filename>

или

git checkout --theirs -- <filename>

или

git show :3:<filename> > <filename> # (stage 3 is theirs)

Вам также необходимо запустить "add", чтобы пометить его как разрешенное:

git add <filename>

Ответ 2

Попробуйте следующее:

Чтобы принять их изменения: git merge --strategy-option theirs

Чтобы принять ваши: git merge --strategy-option ours

Ответ 3

На основе ответа Jakub вы можете настроить следующие псевдонимы git для удобства:

accept-ours = "!f() { git checkout --ours -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"
accept-theirs = "!f() { git checkout --theirs -- \"${@:-.}\"; git add -u \"${@:-.}\"; }; f"

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

Добавьте их в раздел [alias] вашего ~/.gitconfig или запустите

git config --global alias.accept-ours '!f() { git checkout --ours -- "${@:-.}"; git add -u "${@:-.}"; }; f'
git config --global alias.accept-theirs '!f() { git checkout --theirs -- "${@:-.}"; git add -u "${@:-.}"; }; f'

Ответ 4

Основываясь на ответе на кинан, вот те же псевдонимы, модифицированные так, чтобы они могли обрабатывать пробелы и начальные тире в именах файлов:

accept-ours = "!f() { [ -z \"[email protected]\" ] && set - '.'; git checkout --ours -- \"[email protected]\"; git add -u -- \"[email protected]\"; }; f"
accept-theirs = "!f() { [ -z \"[email protected]\" ] && set - '.'; git checkout --theirs -- \"[email protected]\"; git add -u -- \"[email protected]\"; }; f"

Ответ 5

Идеальная ситуация для разрешения конфликтов - это когда вы заранее знаете, каким образом вы хотите их разрешить, и можете передать опции стратегии рекурсивного слияния -Xours или -Xtheirs. За пределами этого я вижу три сценарных:

  1. Вы хотите просто сохранить одну версию файла (это, вероятно, следует использовать только для непересекающихся двоичных файлов, так как в противном случае конфликтующие и неконфликтующие файлы могут не синхронизироваться друг с другом).
  2. Вы хотите просто решить все конфликты в определенном направлении.
  3. Вам необходимо разрешить некоторые конфликты вручную, а затем разрешить все остальные в определенном направлении.

Для решения этих трех сценариев вы можете добавить следующие строки в ваш файл .gitconfig (или эквивалентный):

[merge]
  conflictstyle = diff3
[mergetool.getours]
  cmd = git-checkout --ours ${MERGED}
  trustExitCode = true
[mergetool.mergeours]
  cmd = git-merge-file --ours ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keepours]
  cmd = sed -I '' -e '/^<<<<<<</d' -e '/^|||||||/,/^>>>>>>>/d' ${MERGED}
  trustExitCode = true
[mergetool.gettheirs]
  cmd = git-checkout --theirs ${MERGED}
  trustExitCode = true
[mergetool.mergetheirs]
  cmd = git-merge-file --theirs ${LOCAL} ${BASE} ${REMOTE} -p > ${MERGED}
  trustExitCode = true
[mergetool.keeptheirs]
  cmd = sed -I '' -e '/^<<<<<<</,/^=======/d' -e '/^>>>>>>>/d' ${MERGED}
  trustExitCode = true

Инструмент get(ours|theirs) просто сохраняет соответствующую версию файла и отбрасывает все изменения из другой версии (поэтому слияние не происходит).

Инструмент merge(ours|theirs) повторно выполняет трехстороннее слияние из локальной, базовой и удаленной версий файла, выбирая разрешение конфликтов в заданном направлении. Это имеет некоторые оговорки, в частности: он игнорирует параметры diff, которые были переданы команде слияния (например, алгоритм и обработка пробелов); выполняет слияние из исходных файлов (поэтому любые ручные изменения в файле отбрасываются, что может быть как хорошим, так и плохим); и имеет то преимущество, что его нельзя спутать с маркерами diff, которые должны быть в файле.

Инструмент keep(ours|theirs) просто редактирует маркеры diff и вложенные разделы, обнаруживая их по регулярному выражению. Преимущество этого в том, что он сохраняет параметры diff из команды merge и позволяет вам разрешать некоторые конфликты вручную, а затем автоматически разрешать остальные. Недостатком является то, что если в файле есть другие маркеры конфликта, это может привести к путанице.

Все они используются при запуске git mergetool -t (get|merge|keep)(ours|theirs) [<filename>] где, если <filename> не указано, обрабатывает все конфликтующие файлы.

Вообще говоря, если вы знаете, что нет никаких различий, которые могли бы сбить с толку регулярное выражение, варианты команды keep* являются наиболее мощными. Если вы оставите параметр mergetool.keepBackup установленным или true, то после слияния вы можете *.orig файл *.orig с результатом слияния, чтобы проверить, имеет ли это смысл. В качестве примера я запускаю следующее после mergetool просто для проверки изменений перед фиксацией:

for f in 'find . -name '*.orig''; do vimdiff $f ${f%.orig}; done

Примечание: если merge.conflictstyle не является diff3 то /^|||||||/ шаблона /^|||||||/ в правиле sed должен быть /^=======/.