Простой инструмент для «принятия их» или «принять мой» для всего файла с помощью git - PullRequest
355 голосов
/ 27 мая 2009

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

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

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

Делать это довольно раздражает. Для «принять мое» я попытался:

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

randy@sabotage ~/linus $ git checkout Makefile 
error: path 'Makefile' is unmerged

andy@sabotage ~/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.

Может кто-нибудь указать, как сделать два вышеуказанных действия более простым способом? Спасибо

Ответы [ 5 ]

551 голосов
/ 27 мая 2009

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

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

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

git checkout HEAD -- <filename>

или

git checkout --ours -- <filename>

или

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

Для проверки другой версии вы можете использовать one из:

git checkout test-branch -- <filename>

или

git checkout --theirs -- <filename>

или

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

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

git add <filename>
67 голосов
/ 09 сентября 2014

Попробуйте это:

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

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

48 голосов
/ 07 августа 2012

На основе ответа Якуба вы можете настроить следующие псевдонимы 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'
16 голосов
/ 21 июня 2013

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

accept-ours = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --ours -- \"$@\"; git add -u -- \"$@\"; }; f"
accept-theirs = "!f() { [ -z \"$@\" ] && set - '.'; git checkout --theirs -- \"$@\"; git add -u -- \"$@\"; }; f"
0 голосов
/ 14 мая 2019

Идеальная ситуация для разрешения конфликтов - это когда вы заранее знаете, каким образом вы хотите их разрешить, и можете передать опции стратегии рекурсивного слияния -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 с результатом слияния, чтобы убедиться, что он имеет смысл. Например, после mergetool я запускаю следующее, чтобы проверить изменения перед фиксацией:

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...