Простой инструмент "принять их" или "принять мой" на весь файл с помощью 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
. За пределами этого я вижу три сценарных:
- Вы хотите просто сохранить одну версию файла (это, вероятно, следует использовать только для непересекающихся двоичных файлов, так как в противном случае конфликтующие и неконфликтующие файлы могут не синхронизироваться друг с другом).
- Вы хотите просто решить все конфликты в определенном направлении.
- Вам необходимо разрешить некоторые конфликты вручную, а затем разрешить все остальные в определенном направлении.
Для решения этих трех сценариев вы можете добавить следующие строки в ваш файл .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
должен быть /^=======/
.