Продолжаю публиковать цикл статей о SCM — управлении конфигурацией ПО.
3 предыдущие заметки можно прочитать в этом же блоге.
Сегодня расскажу о том, с чем работает большинство читателей — о контроле версий.
Disclaimer
Далее будут описаны основные техники, реализованные в подавляющем большинстве систем контроля версий. Как они реализуются в приложениях, которые использует читатель, оставим на откуп многочисленным руководствам пользователя, how-to, FAQ и прочим документам, коих можно найти без труда. Главное – понять, по каким принципам и зачем оно работает именно так.
О чем речь?
Система контроля версий – это программное обеспечение, позволяющее создавать версии элементов и работать с этими версиями, как с самостоятельными элементами. В англоязычных источниках используется термин version control systems, сокращенно VCS. Работа с версиями предполагает как создание самих версий, так и структуры для их хранения. Как правило, это или цепочки, или деревья.
Слияние Excel и Word
- файлы;
- директории;
- hard- и softlinks.
Ветвление и слияние версий
Как уже было сказано, системы контроля должны предоставлять структуры для хранения версий. Самым распространенным представлением подобной структуры является дерево версий. Это такая организация версий элемента, при которой на основе любой версии элемента конфигурации может быть создано несколько наборов последовательностей его версий.
При этом отдельный набор версий, происходящий из произвольной версии, называется веткой. И поскольку ветка содержит версии, то каждая из версий может быть источником для создания других веток. Короче, дерево.
Название модели говорит само за себя: у растений (элементов) появляются почки и листья (версии), из них, в свою очередь, ветки. На ветках – листья (другие версии) и другие ветки. На них, опять же, произрастает всё та же растительность. В результате растет дерево, у которого крона – это множество версий. Один элемент – одно дерево.
Зачем нужна вся эта конструкция? Неужели нельзя просто наращивать версии одну за другой? Конечно, можно. Однако это сразу ограничит возможности использования подобной системы. Если версии появляются одна за одной, то в один момент времени создать новую версию сможет только один из пользователей, работающих с системой, остальные вынуждены будут подождать.
Более того, когда появится новая версия, каждому надо будет соединить свои изменения с текущими наработками. И так – пока все желающие не поместят свои наработки в цепочку версий. При этом каждый должен будет убедиться, что слияние версий не привело к поломке системы.
И, кроме того, пока все изменения не будут помещены таким образом под контроль, всем из ожидающих придется сохранять промежуточные результаты где-то локально, не смешивая с тем, что находится в настоящий момент в работе. И ладно, если пара человек работает над десятком элементов – они всегда смогут договориться. А если масштабы гораздо больше? Добавим десяток человек (даже не увеличивая количества элементов) – и подобные простые цепочки полностью застопорят работу. В общем, линейная структура версий порождает множество сложностей.
Использование процесса слияния для создания однотипных документов в MS Word
Итак, ясно, что без веток не обойтись. Но ведь не растить же ветку на малейший чих разработчика? Посмотрим, в каких же случаях отращиваются ветки. Типовые примеры веток таковы:
- ветка для запроса на изменения — заводится для версий, создаваемых в ходе работы по запросу на изменение («девелоперская», или «сиарная», ветка);
- интеграционная ветка — служит промежуточным хранилищем для процесса стабилизации;
- релизная ветка — для выкладывания версий при стабилизации конфигурации (см. соответствующий раздел первой части статьи). Какие-то версии на ветке могут быть в дальнейшем объявлены частью базовой конфигурации;
- отладочная («дебажная») ветка — для кратковременного хранения версий, в основном, для целей проверки каких-либо решений.
Схема 1. Дерево версий элемента element.c
На схеме 1 изображен пример дерева версий. У файла element.c создана релизная ветка release_1.x, куда складываются стабилизированные версии этого элемента (1-5). Для сохранения дельты по каждому запросу на изменения заводится отдельная ветка со специальным форматом имени. В нашем случае формат имеет вид rec_, где номер_записи – это ID запроса на изменение в системе отслеживания.
Для объединения дельты от разных разработчиков создаются интеграционные ветки с названиями вида int__, где суффикс хранит описание интеграции или номер стабилизируемой конфигурации. Также можно увидеть ветку для отладки, чаще всего они именуются как dbg__ — на неё выкладываются проверочные варианты изменений.
Подробнее про отращивание каждой ветки из примера будет рассказано ниже по тексту.
Каждый проект может иметь свои способы создания и именования веток, однако основные из них были перечислены выше. Если используются продуктовые линейки, то становится необходимым использование всех перечисленных видов.
Дерево версий растет и ширится, и рано или поздно надо результаты работы объединять. Например, разработчик отрастил ветку у одного из элементов для работы над запросом на изменение. На неё он положил несколько версий, и последняя является той, которая содержит отлаженный и протестированный код. В то же время есть релизная ветка, где лежат версии, выпускаемые в рамках базовых конфигураций и стабильных релизов. Необходимо соединить результаты.
Для этого используется механизм слияния версий. Как правило, он подразумевает создание новой версии элемента, для которой в качестве основы берется базовая версия на выбранной ветке (база), и к ней применяются изменения, содержащиеся в выбранной сторонней версии (источнике). В англоязычных источниках используется термин merge («мёрж»).
Ветка с версией-источником может быть отращена как от версии-источника, так и от его более ранних предков. Существующие VCS позволяют делать слияние как вручную, так и автоматически. Причем второй способ является основным. Ручное слияние запрашивается лишь в случае конфликтов.
Конфликты слияния возникают в случае, если в обоих версиях элемента меняется один и тот же фрагмент. Такая ситуация возникает когда предок версии-источника не является версией, от которой будет раститься новая версия. Типичным примером такого конфликта может служить история изменений (revision history), которая добавляется в начало файла исходников, чтобы в каждой версии можно было сразу видеть, кто последним менял и что было сделано. В случае слияния версий, отращенных от разных источников, эта строчка точно будет вызывать конфликт, и решается он лишь вставкой обеих строчек в историю. Когда возникает более сложный случай – разработчик или эксперт в затронутом коде должен внимательно вручную произвести нужные изменения.
К вопросу об общих предках и о слиянии изменений: кроме ручного и автоматического, слияние может быть произведено двухпозиционным и трёхпозиционным способом. Двухпозиционное слияние производится простым сравнением двух версий и сложением их дельты (разницы между версиями элемента). Алгоритм работает по принципу diff’а или приближенно к нему: взять дельту и вставить/удалить/изменить нужные строки.
Трехпозиционное слияние учитывает «общего предка» обеих версий и высчитывает дельту исходя из истории изменения элемента в соответствующих ветках. Соответственно, при возникновении конфликта слияния разработчику предлагается 3 версии элемента – общий предок и 2 варианта, что с этим предком стало с течением времени и изменений. Такой подход помогает оценить степень и важность дельты на обеих ветках и принять решение о необходимости интеграции конфликтного куска часто даже без участия авторов изменений.
После того как слияние проведено, информация о нём должна быть сохранена, если это возможно. Как правило, большинство зрелых VCS имеют возможность сохранить «стрелки слияния» – метаинформацию о том, откуда, куда и в каком момент времени сливались изменения и кто это делал.
Пример ветвления и слияния
Рассмотрим пример – дерево версий элемента на схеме 2, продемонстрировав порядок отращивания и слияния веток на нём. Как уже можно догадаться, дерево целиком взято со схемы 1, но к нему добавлены стрелки слияния.
Схема 2. Пример слияния изменений между разными ветками
Итак, в проекте производится некий продукт, в который входит файл element.c. Для того чтобы хранить стабилизированные версии, в команде принято соглашение о том, что все стабильные или базовые версии хранятся на ветке «release_1.x». Это будет называть «релизная ветка». Наш элемент не исключение, и на релизной ветке создается начальная версия 1.
Для простоты обозначения будем описывать ветки, как если бы это были директории на диске. Соответственно, первую версию назовем /release_1.x/1.
Далее, кто-то из менеджеров в системе отслеживания запросов на изменение (далее будем называть эту систему просто «багтрекер») завел запись номер 98, где описал новую функциональность, требуемую продукту. И, конечно же, назначил ответственным за эту задачу одного из пользователей – пусть это будет user2. user2 подумал немного и начал эту задачу решать, а по истечении какого-то времени решил выложить получившиеся исходники под контроль версий. Согласно стандартам именования, принятым в рамках проекта (CM-политикам), ветку для внесения изменений в нашем проекте называют rec_[_]. Поэтому новая ветка была названа rec98_user2, а от комментариев её создатель воздержался. Работа кипит, появляется версия /release_1.x/rec98_user2/1, а потом и /release_1.x/rec98_user2/2.
На этом пока оставим разработчика user2, пусть думает над задачей. Ведь пока он работал, в багтрекере, была зарегистрирована запись (CR) за номером 121, в которой описали новую ошибку, найденную тестерами. Запись эта была назначена на пользователя user1, и он начал успешно описанную ошибку исправлять. По мере исправления он решил завести ветку для сохранения результатов.
Новую ветку, согласно проектным политикам, пользователь назвал rec121_user1. Заметим, что на момент начала работы и создания ветки кто-то уже добавил очередную стабильную версию на релизную ветку – /release_1.x/2. Поэтому ветка отращивается от последней на тот момент версии (второй). Ветка создана – можно складывать версии. Конечный результат – версия /release_1.x/rec121_user1/2.
Что дальше? Ошибка исправлена, протестирована (эту плоскость работ мы пока оставим за кадром) – пора делать эти изменения частью стабильной конфигурации и, возможно, новой базовой конфигурацией. Здесь начинает работу CM-инженер или тот участник команды, который выполняет эту роль. С помощью лома и кувалды команды слияния он создает новую версию на релизной ветке — /release_1.x/3. Обратите внимание на стрелочку с номером 1 – она отображает как раз процесс слияния.
Вернемся к пользователю user2 – он как раз надумал сделать некоторые изменения для своей задачи, однако решил сначала на скорую руку проверить, что получится и дать коллегам посмотреть на своё решение. Для этого он создает отладочную ветку. CM-политика проекта говорит, что она должна называться dbg_[_]. Соответственно, новая ветка будет именоваться /release_1.x/rec98_user2/dbg_user2.
На ней пользователь и создает версию /release_1.x/rec98_user2/dbg_user2/1. Было решено взять полученное решение в основной код, поэтому автор сделал слияние новой дельты и той версии, от которой отращивалась ветка. Вместе с тем, пользователь почистил и оптимизировал код, чтобы было не стыдно отдавать на интеграцию – в результате получилась версия /release_1.x/rec98_user2/3. Ну а яркая стрелочка под номером 2 наглядно обрисовывает процесс слияния.
Однако user2 узнает, что за время его работы была исправлена серьезная ошибка, на которую был заведен CR #121. И это исправление может повлиять на работу новой функциональности. Принимается решение соединить обе дельты и посмотреть, что из этого получится. Делается слияние версий /release_1.x/rec98_user2/3 и /release_1.x/rec121_user1/2 с образованием версии /release_1.x/rec98_user2/4.
Ну и стрелочка слияния номер 3 также появляется. Эта новая версия проверяется на работоспособность и наличие ошибок, и принимается решение – надо интегрировать! Снова берет свои инструменты CM-инженер и делает версию /release_1.x/4, рисуя к ней соответствующую стрелку номер 4 (любое совпадение цифр – случайно).
Однако, жизнь не стоит на месте. Пока наши два разработчика вносили и сливали вместе дельту, другие участники команды уже изменили тот же самый файл. Было заведено два CR’а – 130 и 131, назначенных затем на пользователя user3. Он их успешно закончил и сделал две ветки – по одной на запись.
Поскольку задачи ставились и решались в разное время, то и ветки для их решения отращивались от разных версий на релизной ветке. В итоге получились версии /release_1.x/rec130_user3/1 и /release_1.x/rec131_user3/1, отращенные от версии /release_1.x/3.
Есть изменения – надо их объединить, стабилизировать и сделать базовой конфигурацией, если всё нормально. Для этой цели CM-инженером, который в системе контроля версий проходит под оперативным псевдонимом user7, создается интеграционная ветка, имеющая в данном проекте вид int__. Стало быть, появляется ветка /release_1.x/int_user7_1.5. На неё сливаются вместе обе дельты.
Сначала изменения для записи 130, с образованием версии /release_1.x/int_user7_1.5/1. Затем – для записи 131, для неё создается версия 2 на той же ветке. Для всех операций рисуются стрелочки слияния.
Финальный аккорд CM-инженера – слияние версии /release_1.x/int_user7_1.5/2 на релизную ветку с образованием версии /release_1.x/5. Впоследствии эта ветка станет частью базовой конфигурации продукта.
Вот такое вот немаленькое описание маленькой картинки. Один рисунок стоит сотен слов – правду говорят.
У внимательного читателя в голове наверняка крутится вопрос – если у нас всё делается через ветки и стрелки слияния – откуда взялась версия /release_1.x/2? Ведь к ней не ведет ни одной стрелки ни от одной ветки! Закономерный вопрос. Ответ – тоже закономерен. Да, бывают ситуации, когда изменения вносятся напрямую на релизную ветку.
Например, была найдена страшная ошибка, внесенная вместе с первой версией – забыли внести в раздел revision history комментарий о том, кто же внёс изменения! Конечно, это шутка, никто не будет нарушать политику ради вот таких вот мелочей. Однако – и такое случается. Главное – точно знать, кто создал новую версию и зачем он это сделал.
Лучше всего, если система контроля версий позволяет ограничивать права на создание версий для каждой ветки в отдельности. В этом случае мы дополнительно обезопасим проект тем, что дадим права на добавление версий на релизной ветке только CM-инженеру. По крайней мере, с подобным ограничением будет проще найти крайнего :).
После изложенного выше, надо ли говорить, что возможность работы с ветками является фактически базовой функциональностью любой зрелой системы контроля версий? Без веток система контроля версий может считаться таковой только с формальной точки зрения – просто потому, что она умеет хранить и выдавать версии, но не более.
Метки
Итак, дерево версий растет, работа команды идет своим чередом. Возникает необходимость стабилизировать результаты работы и определить базовую конфигурацию, которую в любой момент времени любой участник команды сможет взять из системы контроля версий. Стабилизация производится путем слияния версий – об этом будет рассказано чуть ниже. А вот на установлении базиса остановимся подробнее.
Получение базовой конфигурации – это по сути своей выявление набора стабильных версий и определение способа их однозначной идентификации. Для этих целей в системах контроля версий существует механизм «навешивания меток». Метка – это цифро-буквенное обозначение, однозначно определяющее конфигурацию. Имея метку, нужно всегда уметь точно и недвусмысленно выделить конфигурацию.
В англоязычных источниках в основном используются термины label и tag.
Если метка – это обозначение для конфигурации, то и каждая из версий конфигурации должна однозначно определяться этой меткой. Таким образом, по метке будет выбираться элемент в той своей версии, которая помечена нужным образом.
Реализация концепции меток может различаться в разных системах. В одних (от CVS до ClearCase) метка – это атрибут версии элемента. Например, на схеме 2 метка бы вешалась прямо на одну из версий, т.е. была бы просто биркой рядом с кружком. В других системах (Subversion) под меткой понимается всего лишь одна из разновидностей веток. Каждому – своё, главное, чтобы вкладываемый смысл оставался тот же.
Что ещё хотелось бы отметить: одна конфигурация может быть помечена несколькими метками. Например, рассмотренные в первой части статьи компоненты могут метиться как компонентными метками (для определения базовых конфигураций компонентов), так и продуктовыми – для того чтобы официально становиться частью базовой конфигурации продукта. Получается, что базовая конфигурация каждой компоненты помечается, как минимум, два раза – один раз компонентной меткой, второй – продуктовой.
В целом, метки – это средство обозначения конфигураций, поэтому по большей части они являются инструментом работы CM-инженеров. Разработчики лишь используют уже сделанные метки для того, чтобы регулярно получать базис для дальнейшей работы.
Итог
Выше было показано, какми основными функциями обладает любая система контроля версий. Как они реализованы в конкретныо взятых приложениях — каждый может посмотреть в используемой лично им системе.
Взгляните на свои инструменти ещё раз, всежим взглядом и сравните с тем, что описано.
По традиции — список рекомендуемых материалов для самостоятельного вдумчивого чтения.
- en.wikipedia.org/wiki/Comparison_of_revision_control_software — большое сравнение существующих систем контроля версий
- www.cmcrossroads.com/bradapp/acme/branching — хорошая статья по политикам ведения веток, рассмотрено много разных шаблонов ветвления, подходящих для разных проектов.
- www.infoq.com/articles/agile-version-control — толковая статья о том, как можно организовать отращивание бранчей и их слияние при использовании agile-методик. Спасибо sse за ссылку.
Для полноты картины использования систем контроля версий осталось рассказать о распределении этого контроля между командами разработки, расположенными в разных географических точках. Но об этом — в следующей заметке.
P.S. Публикую в «Управлении проектами», а не в «Системах управления версиями», просто чтобы публиковать весь цикл заметок единообразно.
Источник: habr.com
Делопроизводство на компьютере
Диалоговое окно, управляющее процессом слияния, доступно при выборе команды Слияние в меню Сервис (Tools, Mail Merge) (рис. 69).
Рис. 69. Слияние документов
Как правило, первым шагом в процессе слияния является создание формы данных, которая содержит данные, предназначенные для Объединения. Эта форма автоматически создается как таблица. Каждый ряд представляет отдельную запись, содержащую связанные между собой данные, в то время как каждая колонка объединяет в себе отдельную категорию данных, называемую полем.
Первая строка называется заголовком и содержит имена полей. Каждое имя должно начинаться с буквы. Пробелы и знаки пунктуации недопустимы.
Обычно в качестве основного-документа используется заранее созданная форма делового письма, содержащая постоянный текст (например, приглашения на конференцию).
Источник данных является таблицей, каждая строка которой представляет собой запись, содержащую информацию о клиентах.
Источник данных может являться файлом Word, Access, Outlook или Excel.
Примером источника данных может служить таблица, созданная в предыдущем упражнении (файл Список_ а дресо в .dос ).
Источник: delcomp.ru
3.2 Ветвление в Git — Основы ветвления и слияния
Давайте рассмотрим простой пример рабочего процесса, который может быть полезен в вашем проекте. Ваша работа построена так:
- Вы работаете над сайтом.
- Вы создаете ветку для новой статьи, которую вы пишете.
- Вы работаете в этой ветке.
В этот момент вы получаете сообщение, что обнаружена критическая ошибка, требующая скорейшего исправления. Ваши действия:
- Переключиться на основную ветку.
- Создать ветку для добавления исправления.
- После тестирования слить ветку содержащую исправление с основной веткой.
- Переключиться назад в ту ветку, где вы пишете статью и продолжить работать.
Основы ветвления
Предположим, вы работаете над проектом и уже имеете несколько коммитов.
Рисунок 18. Простая история коммитов
Вы решаете, что теперь вы будете заниматься проблемой #53 из вашей системы отслеживания ошибок. Чтобы создать ветку и сразу переключиться на неё, можно выполнить команду git checkout с параметром -b :
$ git checkout -b iss53 Switched to a new branch «iss53»
Это то же самое что и:
$ git branch iss53 $ git checkout iss53
Рисунок 19. Создание нового указателя ветки
Вы работаете над своим сайтом и делаете коммиты. Это приводит к тому, что ветка iss53 движется вперед, так как вы переключились на неё ранее ( HEAD указывает на неё).
$ vim index.html $ git commit -a -m ‘Create new footer [issue 53]’
Рисунок 20. Ветка iss53 двигается вперед
Тут вы получаете сообщение об обнаружении уязвимости на вашем сайте, которую нужно немедленно устранить. Благодаря Git, не требуется размещать это исправление вместе с тем, что вы сделали в iss53 . Вам даже не придется прилагать усилий, чтобы откатить все эти изменения для начала работы над исправлением. Все, что вам нужно — переключиться на ветку master .
Но перед тем как сделать это — имейте в виду, что если рабочий каталог либо индекс содержат незафиксированные изменения, конфликтующие с веткой, на которую вы хотите переключиться, то Git не позволит переключить ветки. Лучше всего переключаться из чистого рабочего состояния проекта. Есть способы обойти это (припрятать изменения (stash) или добавить их в последний коммит (amend)), но об этом мы поговорим позже в разделе Припрятывание и очистка главы 7. Теперь предположим, что вы зафиксировали все свои изменения и можете переключиться на ветку master :
$ git checkout master Switched to branch ‘master’
С этого момента ваш рабочий каталог имеет точно такой же вид, какой был перед началом работы над проблемой #53, и вы можете сосредоточиться на работе над исправлением. Важно запомнить: когда вы переключаете ветки, Git возвращает состояние рабочего каталога к тому виду, какой он имел в момент последнего коммита в эту ветку. Он добавляет, удаляет и изменяет файлы автоматически, чтобы состояние рабочего каталога соответствовало тому, когда был сделан последний коммит.
Теперь вы можете перейти к написанию исправления. Давайте создадим новую ветку для исправления, в которой будем работать, пока не закончим исправление.
$ git checkout -b hotfix Switched to a new branch ‘hotfix’ $ vim index.html $ git commit -a -m ‘Fix broken email address’ [hotfix 1fb7853] Fix broken email address 1 file changed, 2 insertions(+)
Рисунок 21. Ветка hotfix основана на ветке master
Вы можете прогнать тесты, чтобы убедиться, что ваше исправление делает именно то, что нужно. И если это так — выполнить слияние ветки hotfix с веткой master для включения изменений в продукт. Это делается командой git merge :
$ git checkout master $ git merge hotfix Updating f42c576..3a0874c Fast-forward index.html | 2 ++ 1 file changed, 2 insertions(+)
Заметили фразу «fast-forward» в этом слиянии? Git просто переместил указатель ветки вперед, потому что коммит C4 , на который указывает слитая ветка hotfix , был прямым потомком коммита C2 , на котором вы находились до этого. Другими словами, если коммит сливается с тем, до которого можно добраться двигаясь по истории прямо, Git упрощает слияние просто перенося указатель ветки вперед, так как нет расхождений в изменениях. Это называется «fast-forward».
Теперь ваши изменения включены в коммит, на который указывает ветка master , и исправление можно внедрять.
Рисунок 22. master перемотан до hotfix
После внедрения вашего архиважного исправления, вы готовы вернуться к работе над тем, что были вынуждены отложить. Но сначала нужно удалить ветку hotfix , потому что она больше не нужна — ветка master указывает на то же самое место. Для удаления ветки выполните команду git branch с параметром -d :
$ git branch -d hotfix Deleted branch hotfix (3a0874c).
Теперь вы можете переключиться обратно на ветку iss53 и продолжить работу над проблемой #53:
$ git checkout iss53 Switched to branch «iss53» $ vim index.html $ git commit -a -m ‘Finish the new footer [issue 53]’ [iss53 ad82d7a] Finish the new footer [issue 53] 1 file changed, 1 insertion(+)
Рисунок 23. Продолжение работы над iss53
Стоит обратить внимание на то, что все изменения из ветки hotfix не включены в вашу ветку iss53 . Если их нужно включить, вы можете влить ветку master в вашу ветку iss53 командой git merge master , или же вы можете отложить слияние этих изменений до завершения работы, и затем влить ветку iss53 в master .
Основы слияния
Предположим, вы решили, что работа по проблеме #53 закончена и её можно влить в ветку master . Для этого нужно выполнить слияние ветки iss53 точно так же, как вы делали это с веткой hotfix ранее. Все, что нужно сделать — переключиться на ветку, в которую вы хотите включить изменения, и выполнить команду git merge :
$ git checkout master Switched to branch ‘master’ $ git merge iss53 Merge made by the ‘recursive’ strategy. index.html | 1 + 1 file changed, 1 insertion(+)
Результат этой операции отличается от результата слияния ветки hotfix . В данном случае процесс разработки ответвился в более ранней точке. Так как коммит, на котором мы находимся, не является прямым родителем ветки, с которой мы выполняем слияние, Git придётся немного потрудиться. В этом случае Git выполняет простое трёхстороннее слияние, используя последние коммиты объединяемых веток и общего для них родительского коммита.
Рисунок 24. Использование трёх снимков при слиянии
Вместо того, чтобы просто передвинуть указатель ветки вперёд, Git создаёт новый результирующий снимок трёхстороннего слияния, а затем автоматически делает коммит. Этот особый коммит называют коммитом слияния, так как у него более одного предка.
Рисунок 25. Коммит слияния
Теперь, когда изменения слиты, ветка iss53 больше не нужна. Вы можете закрыть задачу в системе отслеживания ошибок и удалить ветку:
$ git branch -d iss53
Основные конфликты слияния
Иногда процесс не проходит гладко. Если вы изменили одну и ту же часть одного и того же файла по-разному в двух объединяемых ветках, Git не сможет их чисто объединить. Если ваше исправление ошибки #53 потребовало изменить ту же часть файла что и hotfix , вы получите примерно такое сообщение о конфликте слияния:
$ git merge iss53 Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result.
Git не создал коммит слияния автоматически. Он остановил процесс до тех пор, пока вы не разрешите конфликт. Чтобы в любой момент после появления конфликта увидеть, какие файлы не объединены, вы можете запустить git status :
$ git status On branch master You have unmerged paths. (fix conflicts and run «git commit») Unmerged paths: (use «git add . » to mark resolution) both modified: index.html no changes added to commit (use «git add» and/or «git commit -a»)
Всё, где есть неразрешённые конфликты слияния, перечисляется как неслитое. В конфликтующие файлы Git добавляет специальные маркеры конфликтов, чтобы вы могли исправить их вручную. В вашем файле появился раздел, выглядящий примерно так:
Это означает, что версия из HEAD (вашей ветки master , поскольку именно её вы извлекли перед запуском команды слияния) — это верхняя часть блока (всё, что над ======= ), а версия из вашей ветки iss53 представлена в нижней части. Чтобы разрешить конфликт, придётся выбрать один из вариантов, либо объединить содержимое по-своему. Например, вы можете разрешить конфликт, заменив весь блок следующим:
В этом разрешении есть немного от каждой части, а строки >>>>>> полностью удалены. Разрешив каждый конфликт во всех файлах, запустите git add для каждого файла, чтобы отметить конфликт как решённый. Добавление файла в индекс означает для Git, что все конфликты в нём исправлены.
Если вы хотите использовать графический инструмент для разрешения конфликтов, можно запустить git mergetool , который проведет вас по всем конфликтам:
$ git mergetool This message is displayed because ‘merge.tool’ is not configured. See ‘git mergetool —tool-help’ or ‘git help config’ for more details. ‘git mergetool’ will now attempt to use one of the following tools: opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge Merging: index.html Normal merge conflict for ‘index.html’: : modified file : modified file Hit return to start merge resolution tool (opendiff):
Если вы хотите использовать инструмент слияния не по умолчанию (в данном случае Git выбрал opendiff , поскольку команда запускалась на Mac), список всех поддерживаемых инструментов представлен вверху после фразы «one of the following tools». Просто введите название инструмента, который хотите использовать.
Примечание