Как я могу отменить удаленные изменения и пометить файл как «разрешенный»?

197

У меня есть несколько локальных файлов, я вытаскиваю из удаленной ветки и возникают конфликты. Я знаю, что хотел бы сохранить свои локальные изменения и игнорировать удаленные изменения, вызывающие конфликты. Есть ли команда, которую я могу использовать, чтобы фактически сказать «пометить все конфликты как разрешенные, используйте локальные»?

Том Демилль
источник
1
Ответ, приведенный ниже, был очень полезным для меня. Есть несколько тонких замечаний, которые действительно проясняют для меня вещи, я рекомендую всем неопытным пользователям GIT прочитать все комментарии под постом ниже, и спасибо Брайану!
Том Демилль

Ответы:

332

git checkoutимеет --oursвозможность проверить версию файла, который вы имели локально (в отличие --theirsот версии, которую вы извлекли). Вы можете перейти, .чтобы git checkoutсказать это, чтобы проверить все в дереве. Затем вам нужно пометить конфликты как разрешенные, что вы можете сделать git add, и зафиксировать свою работу после того, как закончите:

git checkout --ours .  # checkout our local version of all files
git add -u             # mark all conflicted files as merged
git commit             # commit the merge

Обратите внимание .на git checkoutкоманду. Это очень важно и легко пропустить. git checkoutимеет два режима; один, в котором он переключает ветви, и другой, в котором он извлекает файлы из индекса в рабочую копию (иногда сначала вытягивая их в индекс из другой ревизии). Это отличает то, передали ли вы имя файла; если вы не передали имя файла, он пытается переключить ветки (хотя, если вы не передаете и ветку, он просто попытается снова проверить текущую ветку), но он отказывается это делать, если есть измененные файлы. что это повлияет. Итак, если вы хотите поведение, которое будет перезаписывать существующие файлы, вам нужно передать .или имя файла, чтобы получить второе поведение git checkout.

Это также хорошая привычка иметь при передаче имени файла смещение --, например git checkout --ours -- <filename>. Если вы этого не сделаете, а имя файла совпадает с именем ветви или тега, Git подумает, что вы хотите проверить эту ревизию вместо того, чтобы проверить это имя файла, и, таким образом, использовать первую форму checkoutкоманды ,

Я немного подробнее расскажу о том, как конфликты и слияния работают в Git. Когда вы объединяете чужой код (который также происходит во время извлечения; извлечение - это, по сути, извлечение, за которым следует слияние), существует несколько возможных ситуаций.

Самое простое, что вы на одной ревизии. В этом случае вы «уже в курсе», и ничего не происходит.

Другая возможность состоит в том, что их ревизия просто является вашей наследницей, и в этом случае у вас по умолчанию будет «быстрое слияние», при котором ваше HEADобновление будет обновлено до их фиксации, без слияния (это можно отключить, если вы очень хочу записать слияние, используя --no-ff).

Затем вы попадаете в ситуации, когда вам действительно нужно объединить две ревизии. В этом случае есть два возможных результата. Во-первых, слияние происходит чисто; все изменения находятся в разных файлах или в одних и тех же файлах, но достаточно далеко друг от друга, чтобы оба набора изменений можно было применить без проблем. По умолчанию, когда происходит чистое слияние, оно автоматически фиксируется, хотя вы можете отключить это с помощью, --no-commitесли вам нужно отредактировать это заранее (например, если вы переименуете функцию fooв bar, а кто-то еще добавит новый код, который вызывает foo, она слится чисто , но создайте сломанное дерево, так что вы можете захотеть очистить его как часть коммита слияния, чтобы избежать каких-либо битых коммитов).

Последняя возможность состоит в том, что существует реальное слияние и возникают конфликты. В этом случае Git будет делать столько слияния , как он может, и создавать файлы с маркерами конфликтов ( <<<<<<<, =======и >>>>>>>) в вашей рабочей копии. В индексе (также известном как «промежуточная область»; место, в котором хранятся файлы git addперед их фиксацией), у вас будет 3 версии каждого файла с конфликтами; Существует исходная версия файла от предка двух ветвлений, которые вы объединяете, версия HEAD(с вашей стороны слияния) и версия из удаленной ветки.

Чтобы разрешить конфликт, вы можете либо отредактировать файл, который находится в вашей рабочей копии, удалив маркеры конфликта и исправив код, чтобы он работал. Или вы можете проверить версию с одной или других сторон слияния, используя git checkout --oursили git checkout --theirs. После того, как вы поместили файл в нужное вам состояние, вы указываете, что завершили слияние файла, и он готов к фиксации с помощью git add, а затем вы можете зафиксировать слияние с git commit.

Брайан Кэмпбелл
источник
7
Вы, вероятно, должны заметить, что git add --allвсе файлы добавляются в хранилище, так что это может добавить больше файлов, чем предполагалось, если ваши .gitignoreшаблоны не находятся в идеальном состоянии. git add -uВероятно, больше подходит для этой ситуации, у вас меньше шансов отредактировать отслеживаемые файлы, которые вы не хотите добавлять при разрешении слияния.
CB Bailey
Ой, извини. Это то, что я имел в виду. Исправил это сейчас.
Брайан Кэмпбелл
1
спасибо за ваш подробный ответ. Я на самом деле попробовал git checkout --ours и получил сообщение об ошибке (которое сейчас не помню). Рассматриваемые файлы являются dll (у нас есть несколько, которые мы ДЕЛАЕМ, в основном, ссылки третьих сторон), и я хотел просто сказать: «Хорошо, моя копия - это те, которые я хочу, но ошибка была что-то вроде« не могу оформить заказ во время слияния » ..... Я сохраню эту статью в качестве ссылки, и в следующий раз, когда это произойдет, попробуйте еще раз и посмотрите, работает ли она или могу ли я опубликовать это сообщение. Еще раз спасибо
Том Демилль
но ваше объяснение многое проясняет для меня по поводу процесса, спасибо еще раз ... Последующий вопрос: Есть ли способ получить git для удаления файлов .orig, как только я очистил слияние?
Том Демилль
2
Вам нужно сделать git checkout --ours .. Это .важно; Передача имени файла (в данном случае всего каталога) позволяет выбрать один из двух режимов работы: checkoutодин переключает ветви и другой перемещает файлы из индекса в рабочую копию. Я согласен, это очень запутанно. Вы также git checkout --ours -- <filename>можете проверить отдельный файл за раз.
Брайан Кэмпбелл
23

Убедитесь происхождения конфликта: если это результат git merge, см Брайан Кэмпбелл «s ответ .

Но если это результат a git rebase, чтобы отбросить удаленные (их) изменения и использовать локальные изменения, вам необходимо выполнить:

git checkout --theirs -- .

См. « Почему значения« ours»и« theirs»поменялись местами», чтобы увидеть, как oursи как theirsони меняются во время перебазирования (потому что ветвь вверх по течению проверена).

VonC
источник