Есть ли способ заставить Git пометить файл как конфликтующий?

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


person Christian Neverdal    schedule 06.05.2010    source источник


Ответы (6)


Вы можете получить содержимое файла с маркерами конфликта, используя git checkout --conflict=merge -- file, но если вы очистили индекс, используя git add file (или если GUI сделал это за вас), это не сработает.

Есть git update-index --unresolve, но он халтурный и работает не очень надежно. Я думаю, что восстанавливаемого им состояния будет недостаточно для git-mergetool.

Вам, вероятно, придется повторить слияние или использовать git update-index --cacheinfo, чтобы вручную установить версию этапов... git-stash может помочь вам сохранить правильно разрешенные конфликты.

person Jakub Narębski    schedule 07.05.2010
comment
Хех, я только что написал этот ответ. ;-) - person ebneter; 07.05.2010
comment
что в этом хакерского и ненадежного? - person Christian Neverdal; 10.05.2010
comment
git update-index --unresolve был создан в древние времена, чтобы позволить восстановить git diff --ours и т. д. после (случайного) git add подтверждения разрешения конфликта. Он заполняет версию HEAD (не версию с автоматически разрешаемыми конфликтами) на этапе № 2, заполняет версию MERGE_HEAD на этапе № 3 и ничего не помещает в этап № 1, предковую версию. - person Jakub Narębski; 11.05.2010
comment
Итак... ответ: нет, это невозможно, Git может легко повредить репозиторий. Хороший. (Я нахожусь в ситуации, когда файл был зафиксирован с удаленного компьютера, к которому в настоящее время ни у кого нет доступа. Повторное слияние физически невозможно. - person Adam; 16.10.2012
comment
@ Адам: Это не должно иметь значения. Перед выполнением слияния git всегда загружает (извлекает) коммиты в текущий репозиторий, поэтому вместо выполнения git pull <repo> вы можете выполнить git merge <repo>, который является ярлыком для git merge <repo>/<branch>, а <repo>/<branch> является веткой удаленного отслеживания. - person Jakub Narębski; 16.10.2012
comment
@JakubNarębski В репозитории есть файлы, зафиксированные с конфликтами ВНУТРИ (я полагаю: кто-то сделал git pull, и было так много изменений, что они не видели, как сообщение CONFLICT прокручивается вверху экрана. Затем они совершили некоторые другие изменения, и репозиторий BANG! теперь поврежден). Теперь невозможно заставить git рассматривать их как конфликтующие файлы. В конце концов, я воспользовался текстовым редактором (и потратил МНОГО времени), переписав затронутые файлы :(. - person Adam; 17.10.2012
comment
Если кто-то совершает смесь конфликтующего слияния и фактической работы, я не понимаю, как это тот случай, когда Git может легко повредить репозиторий. Git сохранил дословную копию состояния, которое запросил этот коммиттер, независимо от того, насколько безумным было это состояние. В конце концов, я бы, вероятно, переделал слияние, а затем сделал git diff с переделанным слиянием и этой испорченной фиксацией слияния. Мы надеемся, что этот diff содержит примерно тот набор изменений, который изначально предназначался для фиксации, поэтому вам не нужно заново создавать всю эту работу вручную. - person Mikko Rantalainen; 29.04.2013
comment
Если индекс чист из-за ошибочного добавления неразрешенного файла, вы можете просто сбросить его: git reset file; git checkout --conflict=merge file. - person Gingi; 25.02.2014
comment
@Джинджи Потрясающе!! Как раз то, что я искал. Я давно хотел узнать, как это сделать. Вы должны сделать это ответом - я бы проголосовал за него! - person fourpastmidnight; 18.05.2016

Если индекс уже находится в состоянии конфликта, просто извлеките файл с флагом --conflict=merge:

git checkout --conflict=merge file

Если индекс чист из-за [ошибочного] добавления неразрешенного файла, просто сбросьте его перед проверкой:

git reset file
git checkout --conflict=merge file

Это позволит вам возобновить разрешение конфликтов в обычном режиме (например, git mergetool).

ПРИМЕЧАНИЕ. Превращение комментария к ответу @jakub-narębski в отдельный ответ по запросу @fourpastmidnight. :)

person Gingi    schedule 18.05.2016

Самым элегантным решением было бы предотвратить эту проблему с самого начала:
git config --global mergetool.[tool].cmd [command-line call]
git config --global mergetool.[tool].trustExitCode false

person Christian Neverdal    schedule 18.05.2010
comment
да. Это заставит Git каждый раз спрашивать, был ли файл успешно слит, вместо того, чтобы полагаться на то, что сам инструмент слияния правдиво сообщает об успехе или неудаче. - person Christian Neverdal; 12.07.2013
comment
значит ли это, что он не будет «git add» файлы, если вы не ответите «да»? У меня также есть «mergetool.prompt = false», это повлияет на это? - person Superole; 11.11.2013
comment
Это верно. Я думаю, что mergetool.prompt должен быть правдой. - person Christian Neverdal; 11.11.2013

Насколько мне известно, вы не сможете выполнить фиксацию, пока файл все еще содержит маркеры конфликта.... что не совсем так:
В OP упоминается, что вы можете ( Я копирую сюда его прошлый бин), но этого будет недостаточно, чтобы инструмент слияния снова сработал:

Auto-merged README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
lynx:~/test_clone$ ls
README
lynx:~/test_clone$ git add README
lynx:~/test_clone$ git commit -a
Created commit 46ee062: It works!
lynx:~/test_clone$ ls
README
lynx:~/test_clone$ cat README
<<<<<<< HEAD:README
testingtesting
=======
hmm
>>>>>>> 881d60f5f738bc5716f5c9a9384e262b535717fd:README
lynx:~/test_clone$

Как комментирует Чарльз Бейли и иллюстрирует этот SO answer, инструмент слияния запрошен, так как в индексе есть 3 экземпляра одного и того же файла :

Для неслитного файла в конфликте git делает доступными общую базу, локальную и удаленную версии файла в индексе. (Здесь они считываются git mergetool для использования в инструменте 3-way diff.) Вы можете использовать git show для их просмотра:

# common base:
git show :1:afile.txt

# 'ours'
git show :2:afile.txt

# 'theirs'
git show :3:afile.txt

git add (с любым содержимым, включая маркеры конфликта) автоматически удалит 2 из них, гарантируя, что mergetool не будет вызываться снова.

person VonC    schedule 06.05.2010
comment
Действительно можете. Простое выполнение git add ‹file› удалит маркер, после чего вы сможете выполнить фиксацию. pastebin.com/KKLtCZ35 - person Christian Neverdal; 06.05.2010
comment
@Christian: интересно (я изменил ответ, чтобы отразить это), но обнаружит ли git mergetool это и повторно инициирует слияние? - person VonC; 06.05.2010
comment
git определяет, что файл конфликтует, если он имеет несколько записей в индексе, а не только одну обычную. git помещает маркеры конфликта в версию рабочего дерева, чтобы помочь пользователю разрешить конфликт, но это не то, как git считает файл не объединенным. Вызов git add указывает git добавить версию рабочего дерева файла в индекс, удалив все остальные записи. После git add, поскольку теперь есть только одна запись в индексе, файл больше не является «неразрешенным», поэтому вы можете его зафиксировать. - person CB Bailey; 07.05.2010
comment
@Christian: завершил мой ответ после комментария Чарльза. - person VonC; 07.05.2010
comment
@CharlesBailey Можно ли добавить дополнительную запись для файла в индекс, чтобы преднамеренно заставить git интерпретировать файл как конфликтующий? Я думаю, что в некоторых ситуациях было бы неплохо сфабриковать конфликтующие версии в индексе после запуска пользовательского драйвера слияния... - person Mikko Rantalainen; 29.04.2013

@VonC: Сначала я не создал учетную запись (у меня есть сейчас), поэтому я не мог оставить комментарий. Вызов git mergetool не обнаруживает его, кажется:

Auto-merged README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
lynx:~/test_clone$ ls
README
lynx:~/test_clone$ git add README
lynx:~/test_clone$ git commit -a
Created commit 46ee062: It works!
lynx:~/test_clone$ ls
README
lynx:~/test_clone$ cat README
>>>>>> 881d60f5f738bc5716f5c9a9384e262b535717fd:README
lynx:~/test_clone$ git mergetool
merge tool candidates:  opendiff emerge vimdiff
No files need merging
lynx:~/test_clone$

git mergetool может принимать имя файла, но это тоже не работает:

Auto-merged README
CONFLICT (content): Merge conflict in README
Automatic merge failed; fix conflicts and then commit the result.
caracal:~/test_clone2$ git mergetool
merge tool candidates:  opendiff emerge vimdiff
Merging the files: README

Normal merge conflict for 'README':
  {local}: modified
  {remote}: modified
Hit return to start merge resolution tool (emerge): 
caracal:~/test_clone2$ ls
#*merge*#145962bz#  README  README~  README.orig
caracal:~/test_clone2$ git mergetool
merge tool candidates:  opendiff emerge vimdiff
No files need merging
caracal:~/test_clone2$ git mergetool README
merge tool candidates:  opendiff emerge vimdiff

README: file does not need merging
caracal:~/test_clone2$ ls
#*merge*#145962bz#  README  README~  README.orig
caracal:~/test_clone2$ 

Также обратите внимание, что я не делал коммитов после выхода из git mergetool.

person Christian Neverdal    schedule 06.05.2010
comment
Только что закончил свой ответ после комментария Чарльза. - person VonC; 07.05.2010
comment
с/рысь:.*\$/\n#/g - person user1133275; 29.05.2017

Пожалуйста, используйте git update-index --unresolve

Начиная с git 1.7, он использует информацию о разрешении-отмене из индекса для восстановления всех 3 этапов (1: базовый, 2: наш, 3: их): https://github.com/git/git/commit/8aa38563b22c84b06ea1fff9638cc1f44fda726f

person Dmitry Oksenchuk    schedule 18.01.2015