img

Как улавливать и разрешать конфликты в Git

Вот оно – слово, которое ненавидят все разработчики, - конфликт. Если вы работаете с Git (или с какими-то другими системами контроля версий), то вам никуда не деться от случайных конфликтов слияния. 

В процессе общения с разработчиками я часто слышу о том, что тема конфликтов слияния вызывает у них чувство тревоги и беспокойства. 

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

Конфликты слияния – это неотъемлемая часть жизни любого разработчика, и поэтому совсем не обязательно беспокоится по этому поводу. 

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

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

Как и когда возникают конфликты

Название говорит само за себя – «конфликты слияния» возникают, когда вы объединяете коммиты из разных источников. 

Учтите, что под «объединением» я имею в виду не только «слияние веток». Объединение может происходить при обычном или интерактивном перемещении, при выполнении операции копирования или извлечения изменений, или даже при повторном применении команды stash. 

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

Конечно, это происходит не всегда (и слава Богу!). В идеале, вы должны сталкиваться с такими ситуациями крайне редко. Но когда именно возникают конфликты слияния?

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

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

Настоящая классика: вы внесли изменения в одну и ту же строку в двух разных коммитов в двух разных ветках, и Git просто не знает, какое из них нужно оставить. 

Бывают и другие ситуации, когда вы, например, изменили файл в одной ветке, но при этом удалили его в другой. Но такие ситуации встречаются намного реже. 

Настольный графический интерфейс Git «Tower» может отлично визуализировать такие ситуации:

tower-conflict-wizard-1

Как узнать, когда произошел конфликт

Можете быть спокойны! Если возникнет конфликт, Git обязательно даст вам об этом знать. 

Для начала Git сообщит вам об этом прямо во время «происшествия», например, когда он не сможет выполнить слияние или переместить коммиты из-за конфликта. 

$ git merge develop
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
CONFLICT (modify/delete): error.html deleted in HEAD and modified in develop. Version develop of error.html left in tree.
Automatic merge failed; fix conflicts and then commit the result.

Как вы видите, я попытался выполнить слияние, и тем самым создал конфликт. Но Git очень четко и быстро сообщил мне о проблеме:

  • Конфликт возник в файле «index.html»
  • Еще один конфликт возник в файле «error.html»
  • И, как результат, из-за всех этих конфликтов операция слияния не смогла быть выполнена

В таком случае мы должны покопаться в коде самостоятельно и понять, что нам нужно сделать. 

Это, конечно, маловероятно, но, если вы вдруг пропустите эти предупреждающие сообщения, Git будет информировать вас об этом каждый раз, когда вы будете запускать команду git status.

$ git status
On branch main
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add/rm <file>..." as appropriate to mark resolution)
deleted by us:   error.html
both modified:   index.html

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

Как отменить конфликт в Git и начать сначала

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

Игнорировать их, конечно, нельзя, но «разрешить конфликт слияния» не всегда подразумевает то, что их надо именно разрешить. Вы можете их просто отменить!

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

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

Для этого у большинства команд есть специальный флаг --abort, например, git merge –abort и git rebase --abort:

$ git merge --abort
$ git status
On branch main
nothing to commit, working tree clean

Это должно вселить в вас уверенность в том, что вы просто не можете напортачить. Вы всегда можете остановиться, вернуться к предыдущему состоянию и начать сначала. 

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

Теперь, когда мы знаем, что мы не можем ничего «сломать», давайте посмотрим на конфликт изнутри. Это поможет нам раскрыть тайну этих маленьких негодников, потерять к ним уважение и обрести уверенность в своих силах.

Давайте в качестве примера возьмем содержимое файла «index.html» (на данный момент это конфликтующий файл):

contents-of-conflicted-file-1

Git оказался довольно любезным и выделил проблемную область вот в такие вот скобки: <<<<<<< HEAD … >>>>>>> [other/branch/name]. То, что мы видим сразу после первой скобки, возникло в нашей текущей ветке. Здесь строка ======= разделяет два конфликтующих изменения. 

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

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

Не исключено, что для этого вам придется поговорить с вашим товарищем по команде, который написал эти «другие» изменения, чтобы решить, какой код все же правильный. Может быть ваш, может его, а может вы придете к выводу, что нужно объединить и то, и другое. 

Весь этот процесс не требует никакого волшебства. Вы можете просто открыть текстовый редактор или IDE и начать вносить изменения. 

Однако вы можете счесть такой подход не самым эффективным. Тогда вы можете сэкономить свое время и усилия и воспользоваться специальными инструментами:

  • Инструменты графического пользовательского интерфейса (GUI) Git. Некоторые GUI могут оказаться полезными при разрешении конфликтов. Например, графический интерфейс Tower предлагает функцию под названием «Conflict Wizard», которая помогает визуализировать сложившуюся ситуацию и разрешить ее:

tower-conflict-wizard-in-action-1

  • Специальные инструменты слияния. В случае более сложных конфликтов полезно будет иметь под рукой специальный инструмент под названием «Diff & Merge Tool». Вы можете его настроить с помощью команды «git config» (более подробную информацию вы можете найти в документации вашего инструмента). Когда возникнет конфликт, вы можете его вызвать, просто набрав команду git mergetool. Ниже я привел пример. Это Koleidoscope для macOS:

merge-conflict-in-gui-1

После того, как вы разрешите конфликт и очистите файл (любым из приведенных способов), вы должны зафиксировать это в Git, как и любое другое изменение:

  • Когда мы разрешаем конфликт для какого-то (ранее) конфликтующего файла, мы должны ввести команду git add <filename>. 
  • После того, как мы разрешим все конфликты и добавим все необходимое в промежуточную область, мы должны завершить процесс разрешения, то есть зафиксировать все наши изменения. 

Как стать более уверенным и продуктивным

Много лет назад, когда я только начинал пользоваться системой контроля версий, я психовал с каждого возникающего конфликта слияния. Я думал, что «сломал» все окончательно.

Только после того, как я нашел время и разобрался, что же у этих конфликтов «под капотом», я научился уверенно и эффективно разрешать их. 

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

Ссылка
скопирована
Программирование
Скидка 25%
Python Advanced. Продвинутый курс
Освойте асинхронное и метапрограммирование, изучите аннотацию типов и напишите собственное приложение на FastAPI. Улучшите свои навыки Python, чтобы совершить быстрый рост вашего грейда до уровня middle.
Получи бесплатный
вводный урок!
Пожалуйста, укажите корректный e-mail
отправили вводный урок на твой e-mail!
Получи все материалы в telegram и ускорь обучение!
img
Еще по теме:
img
За последние годы микрослужбы прошли путь от обычного переоцененного модного словечка до вещи, которую вы, как специалист по про
img
Введение Резидентные базы данных (или хранилища в памяти) по большей части делают упор на хранилище данных в памяти, а не на жес
img
  Многие люди рассуждают так: «зачем, ну зачем мне изучать еще один язык программирования?» Для них это лишнее, и они стараютс
img
Введение Объекты в Kubernetes – это базовые постоянные сущности, которые описывают состояние кластера Kubernetes. Модули – это э
img
  Довольно часто мы встречаемся с компонентами архитектуры программного обеспечения, которые являются частью любой системы, но п
img
  Ключевые отличия между JDK, JRE и JVM: JDK – это набор средств для разработки программного обеспечения, JRE – это програ
Комментарии
ЛЕТНИЕ СКИДКИ
40%
50%
60%
До конца акции: 30 дней 24 : 59 : 59