У меня есть локальные файлы, я извлекаю их из удаленной ветки и возникают конфликты. Я знаю, что хотел бы сохранить свои локальные изменения и игнорировать удаленные изменения, вызывающие конфликты. Есть ли команда, которую я могу использовать, чтобы сказать «пометить все конфликты как разрешенные, использовать локальные»?
Как я могу отменить удаленные изменения и пометить файл как исправленный?
Ответы (2)
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
.
git add --all
добавляет все файлы в репозиторий, поэтому это может добавить больше файлов, чем предполагалось, если только ваши .gitignore
шаблоны не находятся в идеальном состоянии. git add -u
, вероятно, больше подходит для этой ситуации, у вас меньше шансов внести изменения в отслеживаемые файлы, которые вы не хотите добавлять при разрешении слияния.
- person CB Bailey; 15.01.2010
git checkout --ours .
. .
важен; передача имени файла (в данном случае всего каталога) позволяет выбрать один из двух различных режимов работы checkout
, один из которых переключает ветви, а другой перемещает файлы из индекса в рабочую копию. Согласен, это очень запутанно. Вы также можете сделать git checkout --ours -- <filename>
, чтобы извлекать отдельный файл за раз.
- person Brian Campbell; 15.01.2010
git
для очистки лишних файлов в рабочем дереве - это git clean -f
kernel.org/pub/software/scm/git/docs/git-clean.html (будьте осторожны, это опасная команда). git clean
удалит все файлы, о которых git не знает; -f
необходимо, потому что git clean
опасно, поэтому вам нужна опция force, чтобы сообщить ему, что вы действительно это имеете в виду. Если у вас есть файлы в вашем .gitignore
, которые вы тоже хотите очистить (например, .o
файлы), вы можете использовать git clean -xf
. И если вы тоже хотите получить каталоги, git clean -fd
или git clean -xfd
.
- person Brian Campbell; 15.01.2010
That's very important, and easy to miss
‹- Ага. Я скучал по этому
- person James Webster; 13.08.2013
ours
и theirs
противоположны тому, что вы могли подумать.
- person ErikE; 23.09.2015
deleted by us
? При попытке выполнить git commit --ours .
я получаю ошибку: путь 'file.ext' не имеет нашей версии, что понятно, но есть ли способ сделать commit
и delete
file.ext
без использования git rm
?
- person Gabrielius; 24.11.2015
git checkout --ours .
, и он без предупреждения перезаписал все мои незафиксированные локальные изменения. Совершенно другое поведение, чем git checkout branchname
. Пришлось восстанавливать изменения с трудом. Могу я предложить вам поставить предупреждение о таком поведении? См. Также: Вот безумная идея: если у вас есть безобидное действие и опасное действие, не помечайте их одной и той же командой. а>
- person machine yearning; 30.11.2017
git reflog
есть все, что есть. Перед тем, как нажимать, мне нужно очистить свои коммиты, но я все равно просматриваю все изменения, так что накладных расходов практически нет.
- person maaartinus; 02.05.2018
Убедитесь в происхождении конфликта: если это результат git merge
, см. Брайан Кэмпбелл ответ.
Но если это результат git rebase
, чтобы отменить удаленные (их) изменения и использовать локальные изменения, вам нужно будет сделать:
git checkout --theirs -- .
См. «Почему значения« ours
»и« theirs
»меняются местами», чтобы узнать, как ours
и theirs
меняются местами во время перебазирование (поскольку ветка восходящая ветвь выписан).