Учебник по разрешению конфликтов слияния в Git

Что такое конфликт при слиянии в Git?

Система управления версиями Git является одним из инструментов, который обеспечивает работу в команде и вклад в проекты разработчиков. Разработчики обычно работают на отдельных ветках и, успевая, сливают изменения с главной веткой. такой тип командной работы очень продуктивен и эффективен для выявления ошибок. иногда разработчики работают с одинаковым кусом кода, и когда они пытаются объединить изменения, возникают конфликты.


Простой пример конфликта в Git

Рисунок выше дает идеальный пример того, как происходит типичный конфликт слияния в Git. Главная ветка содержит файл с текстом “HELLO, WORLD!”. Пользователь abid создает ответвление от главной ветки и изменяет текст на “HELLO, CAT!”. Пока abid вносит изменения, оригинальная главная ветка также подвергается модификации и становится “HELLO, DOG!”. Слияние этих веток приведет к возникновению конфликта слияния и остановке процесса.  

Команда `git merge` предназначена для объединения двух веток и автоматического решения конфликтов. Однако время от времени возникают конфликты, когда два человека изменяют одну и ту же строку кода или удаляют важные файлы, над которыми работал другой разработчик. Git отмечает эти изменения и останавливает процесс слияния. В этом случае конфликт не решается автоматически; вместо этого разработчик должен внести изменения вручную или использовать инструменты для решения конфликта.

Типы слияния

Git merge и rebase – два способа интеграции коммитов из целевой ветки в исходную. Кроме того, Git merge может выполнять либо быстрое слияние (fast-forward), либо слияние без быстрого прохода (no-fast-forward). Если голова целевой ветки находится в исходной ветке, то по умолчанию тип слияния будет быстрое слияние, и если она отсутствует, то слияние без быстрого прохода. Git rebase – это другой тип слияния, который перестраивает историю коммитов целевой ветки. 

Быстрое слияние (Fast-forward Merge)

По умолчанию Git-соединение использует быстрое перемещение для интеграции пропущенных коммитов в целевую ветку. Например, оно используется для обновления локальной ветки с удаленного сервера с помощью команды pull. Быстрое перемещение не вызывает проблем с объединением, так как Git его не применит, если в исходной ветке отсутствует конец целевой ветки.

Небыстрое перемещение

Небыстрое перемещение также называется трёхсторонним или истинным объединением. Оно создает новый коммит на целевой ветке, интегрируя изменения из обоих ветвей. Изменения смешиваются после последнего общего коммита в обеих ветвях. В нашем случае это после коммита C. Такого рода объединение вызовет конфликт Git, если исходная ветка находится в споре с целевой веткой. На рисунке выше создан коммит объединения (X), который интегрирует исходную и целевую ветки, где K и E являются родителями коммита объединения.

Ребайз

Git-ребайз является немного по-другому, чем другие типы. Он изменяет последовательность коммитов целевой ветки. Ребайз интегрирует исходную ветку так, что целевая ветка содержит все изменения из исходной ветки, затем все коммиты целевой ветки после последнего общего коммита. В нашем случае последним общим коммитом является C, в то время как D и E являются коммитами исходной ветки. Коммит K* такой же, как K, но с другим идентификатором коммита. Вместо связывания C, он будет связан с E. Так же, как и в случае небыстрого перемещения, если есть соотносимость проблем между исходной и целевой веткой, Git вызовет проблему для урегулирования конфликта перед окончательным оформлением ребайза.

Типы конфликтов при объединении Git

В Git есть два типа конфликтов при слиянии: в начале и во время процесса слияния – Atlassian. В этом разделе мы узнаем обоих типах и способах решения каждого сценария.

В начале слияния

Гит merge может потерпеть неудачу в начале, если есть изменения в рабочем каталоге или области предварительного сохранения. Она провальна в начале, чтобы предотвратить запись изменений, входящих в состав сливаемых коммитов. Это происходит из-за конфликтов с локальными изменениями, а не с другими ветками или разработчиками. Чтобы устоить локальное состояние, вы можете использовать команды, такие как git stash, git commit, git checkout, или git reset.

Во время слияния

Ошибка во время слияния означает, что конфликт есть между исходной и целевой веткой, где многие разработчики изменили одный и тот же файл. Если автоматическое слияние терпит неудачу, Git запросит вас о решении проблем вручную. Также вы можете использовать внешние инструменты, чтобы помочь вам визуализировать и интегрировать изменения.

Команды для решения конфликтов Git Merge

В этом разделе мы узнаем о различных встроенных командах для визуализации и решения конфликтов Git merge.

Общие команды

Команда Git status является самой часто испоьзуемой для отображения состояния измененных файлов, области предварительного сохранения и коммитов. Во время процесса слияния она используется для идентификации конфликтных файлов.

git status

Журнал Git с опцией –merge выдает список коммитов, которые находятся в конфликте с источной веткой.

git log --merge

по умолчанию опция git diff покажет различия между некоммитированными изменениями и предыдущими коммитами. Git diff используется для сравнения ветвей, коммитов и файлов. Он полезен для предотвращения будущих конфликтов при слиянии.

git diff

Команды для сбоев при слиянии в начале

Команда checkout используется для отмены изменений или переключения на новую или старую ветку.

git checkout

Команда Git reset используется для возврата изменений в рабочем каталоге и области предварительной коммитации.

git reset --mixed

Команды для конфликтов во время слияния

Опция –abort остановит процесс слияния и вернет изменения к исходному состоянию до начала слияния.

git merge --abort

Команда Git reset обычно используется во время процесса слияния, чтобы возвратить конфликтные файлы к исходному состоянию.

git reset

Решение конфликта удаленного-измененного файла

Гит-конфликт произойдет, если вы удалили файл в текущей ветке, а кому-то else изменил его в другой ветке. В этом случае вы можете либо добавить файл и коммитить,

git add <filename>

либо удалить файл и коммитить.

git rm <filename>

Визуальные инструменты слияния

Инструменты слияния являются удобными визуальными средствами для определения и разрешения всех типов конфликтов слияния. Некоторые инструменты поддерживают дополнительные функции, такие как сравнение изменений, операции Git и управление проектами и репозиториями. Существует два типа инструментов Git слияния: только для терминала и с графическим интерфейсом. Инструменты на основе терминала открываются в PowerShell или Bash, а инструменты с графическим интерфейсом открываются в оконном окружении. 

Чтобы просмотреть список установленных и действительных инструментов, используйте:

git mergetool --tool-help

Список состоит из всех действительных инструментов, которые можно установить и интегрировать с командами git.

Например, у нас по умолчанию установлены vim и nvim, и если вы хотите увидеть разницу между незакомmitted файлом и предыдущим коммитом, введите:

git difftool --tool=vimdiff3

Инструмент vimdiff3 подсвечивает изменения и позволяет сравнивать коммиты внутри терминала. 

Различие между двумя версиями одного файла в Vimdiff3

Meld

Meld — это свободный и открытый источник инструмент, который поднимает разрешение конфликтов слияния на другой уровень. Чтобы интегрировать его с Git, вам сначала нужно скачать и установить программу с официального сайта. Затем добавьте его в глобальную конфигурацию, чтобы по умолчанию Git запускал Meld для разрешения конфликтов.  

Команды конфигурации ниже применимы только для пользователей Windows. Единственное, что вам нужно изменить, это путь к установленному файлу Meld для Mac или Linux.

git config --global merge.tool meld git config --global mergetool.meld.path "C:/Program Files (x86)/Meld/Meld.exe" git config --global diff.tool meld git config --global difftool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"

После установки значений по умолчанию, вы можете ввести git difftool в локальном каталоге Git, чтобы запустить версию Meld для Windows, или вы можете использовать git mergetool, чтобы решить конфликты слияния, как показано ниже.

Решение конфликта слияния с помощью Meld

VSCode

VSCode обеспечивает лучшую и наиболее популярную методологию для решения конфликтов слияния. Когда Git не может слиять файлы автоматически, VSCode выделит конфликтного кода и предоставит четыре варианта решения: принять текущие изменения, принять идущие изменения, принять оба изменения или сравнить изменения. Вы можете использовать эти варианты, чтобы убрать свой файл и решить все ожидающие вопросы.

Решение конфликта слияния с помощью VSCode

Если вы ищете полноценное решение для ваших операций Git, попробуйте GitKraken. У него есть бесплатный клиент, расширение VSCode и встроенный инструмент для решения конфликтов слияния.

Как решать конфликт слияния в Git

В этом разделе мы посмотрим, как создать конфликт при слиянии в Git, а затем устранить его. Tutorial разделен на две части. В первой части мы узнаем, как решать конфликты Git локально; во второй части мы будем разбираться, как устранять конфликты с удаленным сервером (GitHub).

Локальный Конфликт Слияния

Создание конфликтов при слиянии поможет нам узнать, каким образом они возникают. Затем мы можем использовать творческие способы для решения этих проблем или даже предотвратить их возникновение в будущем.

Теперь мы создадим Git репозиторий с单个文件 и создадим нашу первую коммит, чтобы начать.

  1. Создайте папку с именем datacamp.
  2. Перейдите в datacamp.
  3. Инициализируйте Git.
  4. Создайте файл README.md с указанным заголовком.
  5. Добавьте файл в каталог и создайте коммит с использованием аргумента -am.
mkdir datacamp cd datacamp git init echo "# How to Resolve Git Merge Conflict" > README.md git add README.md git commit -m "first commit" >>> [main (root-commit) 8199ea2] first commit >>> 1 file changed, 1 insertion(+) >>> create mode 100644 README.md

Далее мы создадим новый веток readme и изменим заголовок из “..Git Merge..” на “..Git..”. Добавьте файл и создайте коммит с использованием аргумента -am.

git checkout -b readme echo "# How to Resolve Git Conflict" > README.md git commit -am "new branch conflict added" >>> [readme 155f694] new branch conflict added >>> 1 file changed, 1 insertion(+), 1 deletion(-)

Вернитесь на основную ветку и добавьте новую строку в файл README.md с использованием >>. Сохраните изменения и создайте коммиты, тем самым успешно сформировав конфликт между двумя версиями одного и того же файла.

git checkout main echo "New change in base branch" >> README.md git commit -am " a line added to base branch Readme file" >>> [main f1f1874] a line added to base branch Readme file >>> 1 file changed, 1 insertion(+)

Как видим, при слиянии ветки readme Git вызвал сообщение, утверждая, что автоматическое слияние не удалось, и мы должны сделать изменения вручную, а затем заcommitted результат.

git merge readme >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.

С решением проблемы вручную мы открываем и редактируем файл в Блокноте. На изображении ниже показана стрелка с HEAD, разделитель и стрелка другого направления с readme. Часть HEAD показывает существующие изменения в основном ветке, а часть readme — это ветка, которую мы хотим объединить, и которая состоит из другого заголовка. 

Разрешение конфликта слияния вручную 

Чтобы решить проблему, мы удалим часть ветки readme, стрелки и разделитель. Конечная версия файла должна выглядеть чисто, как показано ниже. 

Конфликт разрешен 

После того как мы добавим файл и создадим коммит, конфликт слияния будет разрешен. Это самый обычный и простой способ решения проблем. Вы также можете использовать интегрированную среду разработки (IDE) для более быстрого решения проблем.

git commit -am "conflict resolved in file README.md" >>> [main 9994a29] conflict resolved in file README.md

Удаленный конфликт слияния

Для создания и разрешения удаленного конфликта слияния нам нужно создать новый репозиторий на GitHub.

Создание нового репозитория на GitHub

Далее, добавьте удаленное имя (исходник) с адресом в репозиторий и отправьте все изменения из локального репозитория на удаленный основной支干 используя up스ream.

git remote add origin https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git git push --set-upstream origin main >>> Enumerating objects: 12, done. >>> Counting objects: 100% (12/12), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (12/12), 998 bytes | 499.00 KiB/s, done. >>> Total 12 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), done. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> * [new branch] main -> main >>> branch 'main' set up to track 'origin/main'.

Чтобы создать конфликт, нам нужно сделать изменения в удаленной и локальной README.md файлы. Вы можете использовать GitHub редактор файлов, чтобы изменить “..Git merge..” на “..Sit-Merge..” и затем связать изменения.

Изменения в GitHub редакторе

Потом, в локальном репозитории, измените файл README.md, чтобы добавить простой заголовок и связать изменения.

echo "# How to Resolve Merge Conflicts in Git Tutorial" > README.md git commit -am "local branch changes in README.md" >>> [main c677a13] local branch changes in README.md >>> 1 file changed, 1 insertion(+), 4 deletions(-)

В конце концов, отправьте изменения на удаленный сервер. Обратите внимание, что Git выдал ошибку с указаниями на то, как устранить проблему.

git push >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> ! [rejected] main -> main (fetch first) >>> error: failed to push some refs to 'https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git' >>> hint: Updates were rejected because the remote contains work that you do >>> hint: not have locally. This is usually caused by another repository pushing >>> hint: to the same ref. You may want to first integrate the remote changes >>> hint: (e.g., 'git pull ...') before pushing again. >>> hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Мы будем следовать самым простым советом, чтобы взять файл с удаленного сервера, прежде чем отправить.

Подтягивание файла не удалось из-за конфликта при слиянии в файле README.md. Мы могли бы исправить это вручную с использованием Notepad, но на этот раз мы будем использовать вizualное tooл, чтобы нам помочь с этим процессом.

git pull >>> remote: Enumerating objects: 5, done. >>> remote: Counting objects: 100% (5/5), done. >>> remote: Compressing objects: 100% (2/2), done. >>> remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 >>> Unpacking objects: 100% (3/3), 681 bytes | 75.00 KiB/s, done. >>> From https://github.com/kingabzpro/DataCamp-Git-Merge-Guide >>> aaf149d..49b7d14 main -> origin/main >>> Auto-merging README.md >>> CONFLICT (content): Merge conflict in README.md >>> Automatic merge failed; fix conflicts and then commit the result.

Утилита слияния Meld идентифицирует затронутые файлы и показывает их в графической оболочке Meld.

git mergetool >>> Merging: >>> README.md >>> Normal merge conflict for 'README.md': >>> {local}: modified file >>> {remote}: modified file

Есть три колонки: README_LOCAL_473.md, README.md и README_LOCAL_473.md. Если вы считаете, что изменения на удаленном сервере являются правильными, то нажмите на черную стрелку в колонке удаленного сервера; и если вы хотите, чтобы локальные изменения сохранялись, нажмите на черную стрелку в локальной колонке. Это так просто.

Решение конфликта с использованием инструмента слияния Meld

После внесения изменений сохраните файл и выполните提交. Как вы можете видеть, отправка файла на удаленный сервер не вызывает ошибку слияния конфликта.

git commit -am "remote main branch conflict resolved" git push >>> Enumerating objects: 16, done. >>> Counting objects: 100% (16/16), done. >>> Delta compression using up to 4 threads >>> Compressing objects: 100% (6/6), done. >>> Writing objects: 100% (10/10), 1.08 KiB | 550.00 KiB/s, done. >>> Total 10 (delta 2), reused 0 (delta 0), pack-reused 0 >>> remote: Resolving deltas: 100% (2/2), completed with 1 local object. >>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git >>> 49b7d14..8f5c3aa main -> main

Мы успешно решили как локальные, так и удаленные конфликты слияния. Эти конфликты ежедневно разрешают специалисты по данным и инженеры по машинному обучению. Чтобы улучшить навыки в операциях с Git, пройдите курс Введение в Git.

Заключение

Решение конфликтов слияния Git является сложной и очень рискованной задачей, так как можете испортить программное обеспечение слиянием неверного кода. Инструменты слияния обеспечивают дружественную для пользователя среду с безопасным способом обнаружения и решения конфликтов слияния. В этом учебнике мы узнали, почему возникают конфликты Git и как их решать. Также мы охватили различные типы слияний и конфликтов, полезные команды Git и вьюзальные инструменты. В последнем разделе мы создали конфликт слияния и решили его в локальном и удаленном репозитории.

Если вы новичок в Git и хотите узнать, как он работает, тогда прочитайте: Учебник Git и GitHub.

Source:
https://www.datacamp.com/tutorial/how-to-resolve-merge-conflicts-in-git-tutorial