
Переходим на MQL5 Algo Forge (Часть 4): Работа с версиями и выпуск релизов
Введение
Наш переход на MQL5 Algo Forge продолжается, и, вслед за настройкой рабочего процесса с собственными репозиториями, мы обратились к одной из главных причин этого перехода — возможности лёгкого использования кода сообщества. В части 3 мы рассмотрели, как добавить в свой проект публичную библиотеку из чужого репозитория.
Эксперимент с подключением библиотеки SmartATR к советнику SimpleCandles наглядно показал, что прямой путь — простое клонирование — не всегда удобен, особенно если код требует доработок. Мы детально отработали корректный рабочий процесс через создание форка, который стал нашей личной копией чужого репозитория для исправления ошибок и модификаций, с возможностью в будущем предложить эти изменения автору через Pull Request.
Несмотря на некоторые ограничения интерфейса MetaEditor, комбинация с веб-интерфейсом хранилища MQL5 Algo Forge позволила успешно выполнить всю цепочку действий от клонирования до коммита правок и финального соединения проекта с внешней библиотекой. Таким образом, мы не только решили конкретную задачу, но и рассмотрели универсальный шаблон действий для интеграции любых сторонних компонентов.
В сегодняшней статье мы более детально рассмотрим этап публикации в репозитории сделанных правок, совокупность которых образует некоторое законченное решение — будь то добавление новой функциональности к проекту или исправление обнаруженной ошибки. Это — фиксация или релиз новой версии продукта. Посмотрим, как можно организовать этот процесс, и какие возможности предоставляет нам в этом хранилище MQL5 Algo Forge.
Поиск ветки
В предыдущих частях мы рекомендовали использовать отдельную ветку репозитория для внесения набора правок, решающих конкретную задачу. Однако, после завершения работы над ней, ветку желательно влить в какую-то другую (основную) ветку и удалить. В противном случае, репозиторий может превратиться в сплошные заросли камыша, в которых будет легко заблудиться даже владельцу репозитория. Поэтому отработанные ветки надо удалять. Но иногда может возникать необходимость вернуть код в состояние, в котором он находился непосредственно перед удалением определённой ветки. Как это можно сделать?
Прежде всего, давайте проясним, что ветка — это просто последовательность коммитов, упорядоченных по времени. Технически ветка представляет собой указатель на какой-то коммит, считающийся последним в цепочке последовательных коммитов. Поэтому удаление ветки не удаляет коммиты. В худшем случае они могут начать считаться относящимися к другой ветке, или даже объединяться в один суммарный коммит, но всё равно они так или иначе продолжают существовать в репозитории (за редкими исключениями). Поэтому возможность вернуться в состояние "перед удалением ветки" это всё равно, что вернуться к одному из коммитов, расположенному в какой-то существующей ветке. Тогда вопрос состоит в том, как найти этот нужный коммит.
Давайте посмотрим на состояние репозитория SimpleCandles, в котором он оказался после внесения правок, упомянутых в части 3:
Мы видим историю сделанных коммитов и цветную визуализацию взаимосвязей различных веток слева. У каждого коммита показан его хеш (точнее, часть хеша) — некоторое большое уникальное число, по которому этот коммит можно отличить от всех других. Для уменьшения длины его записи это число показывается в шестнадцатеричном виде (например, b04ebd1257).
Такое дерево коммитов для каждого репозитория можно увидеть на отдельной странице репозитория веб-интерфейса хранилища MQL5 Algo Forge. Этот скриншот был сделан уже некоторое время назад, поэтому если сейчас зайти на эту страницу, то мы увидим уже несколько другую картину: в дереве коммитов будут присутствовать новые коммиты, переплетение веток тоже будет иным, из-за добавленных коммитов слияния.
Также напротив некоторых коммитов мы видим названия веток. Они показываются у самых последних коммитов в каждой ветке. На приведенном скриншоте можно насчитать шесть различных веток: main, develop, convert-to-utf8, article-17608-close-manager, article-17607 и article-19436-forge3. Последняя упомянутая ветка — это ветка изменений, вносимых при написании предыдущей части 3. Но когда велась работа над частью 2, мы тоже создали отдельную ветку для планируемых изменений. Она называлась article-17698-forge2, и теперь она уже удалена, поэтому ни у какого коммита рядом нет этого названия ветки. Где же нам найти её?
Если посмотреть на полный комментарий к коммиту 58beccf233, то в нем упоминается название этой ветки и сообщается, что она была влита в ветку develop:
Итак, нужный коммит найден, но находить его таким образом неудобно. Более того, если бы мы не воспользовались механизмом Pull Request для слияния веток, а выполняли бы их через консольные команды git merge, то мы могли бы указать свой произвольный комментарий к коммиту слияния. Тогда найти этот коммит стало бы ещё сложнее, так как в его комментарий название ветки могло и не попасть.
Теперь у нас есть возможность переключиться на этот коммит, приведя наш локальный репозиторий в состояние, как после этого коммита. Для этого мы можем использовать хеш нужного коммита в команде git chekout. Однако тут есть свои нюансы. Если мы попробуем выполнить переключение на этот коммит в MetaEditor, выбрав его из истории, открываемой при нажатии на пункт контекстного меню проекта "Git Log":
... то получим сообщение об ошибке:
Возможно, это неспроста. Давайте разберёмся подробнее в происходящем. Начнём с того, что познакомимся с новыми понятиями "тег" и "указатель HEAD".
Что такое теги
Тег (или метка) в системе контроля версий Git — это дополнительное имя, присвоенное какому-то коммиту. Также можно назвать тег указателем или ссылкой на конкретную версию кода в репозитории, так как он действительно указывает на определённый коммит, Использование тега позволяет в любой момент вернуться к состоянию кода, соответствующего данному коммиту с тегом. Теги помогают отметить важные моменты в разработке проекта, например, релиз версии, этап завершённой работы или стабильную версию. В веб-интерфейсе хранилища MQL5 Algo Forge теги выбранного репозитория можно посмотреть на отдельной странице.
В Git есть два типа тегов: лёгкие и аннотированные. Легкие теги имеют только имя, а аннотированные могут содержать дополнительную информацию: автора, дату, комментарии и даже подпись. В большинстве случаев используются легкие теги.
Чтобы создать тег через веб-интерфейс, можно зайти на страницу любого коммита (например, этого) и, нажав на кнопку Operations, выбрать пункт "Create tag":
Но не будем пока этого делать, вернёмся к созданию тега позже.
Для создания тега через консольные команды Git используется команда git tag. Для создания лёгкого тега достаточно указать один параметр — имя создаваемого тега:
git tag <имя-тега>
# Например
git tag v1.0
Для создания аннотированного тега потребуется указать дополнительные параметры:
git tag -a <имя-тега> -m "Описание тега"
# Например:
git tag -a v1.0 -m "Релиз версии 1.0"
Помимо пометки версий кода, предназначенного для публикации или запуска (релизов), теги используются для передачи сигнала конвейерам CI/CD о том, что необходимо выполнить какие-то прописанные заранее действия при появлении коммита с тегом определённого вида, или пометки значимых этапов в разработке проекта — например, завершения крупных функций, исправления критических ошибок, но не означающих выход новой версии.
Указатель HEAD
Сказав про теги, стоит упомянуть и про такую вещь, как указатель HEAD. По поведению он похож на тег с фиксированным именем HEAD, который автоматически перемещается на последний коммит в текущей извлечённой ветке. Также HEAD может называться «маркером текущей ветки» или «указателем на активную ветку». Он отвечает на вопрос "Где мы находимся в нашем репозитории в данный момент?". Но он не является тегом как таковым.
Физически этот указатель хранится в файле .git/HEAD в репозитории. Содержимое HEAD может содержать либо символическую ссылку (тег, название ветки), либо хеш коммита. При переключении между ветками указатель HEAD автоматически обновляется, чтобы указывать на последний коммит в текущей ветке. Когда мы добавляем новый коммит, то Git не только создаёт объект коммита, но и перемещает на него указатель HEAD.
Таким образом, имя "HEAD" можно использовать в консольных командах Git вместо хеша последнего коммита или названия текущей ветки, а используя специальные символы '~' и '^', можно ссылаться на коммиты, находящиеся позади последнего коммита. Например, "HEAD~2" будет обозначать коммит, находящийся на два коммита позади (то есть раньше) последнего коммита. Но мы сейчас не будем углубляться в такие тонкости.
Для дальнейшего нам надо упомянуть ещё про два возможных состояния, в которых может находиться репозиторий кода. Обычное состояние называется "attached HEAD" и означает, что новые создаваемые коммиты будут возникать спереди последнего коммита текущей ветки. В этом состоянии все правки добавляются в ветке последовательно и бесконфликтно.
Другое состояние, называемое "detached HEAD", возникает, когда указатель HEAD начинает указывать на коммит, который не является последним в какой-либо ветке. Это может произойти, например, при:- переключении репозитория на конкретный прошлый коммит (например, командой git checkout <commit-hash>);
- переключении репозитория по имени тега (например, git checkout tags/<tag-name>);
- переключении репозитория на ветку, которая пока ещё присутствует в вышестоящем репозитории, но уже удалена в локальном репозитории (например, git checkout origin/<branch-name>).
Такого состояния надо по возможности избегать, так как любые изменения, сделанные в этом состоянии, не связаны с какой-либо веткой и могут быть потеряны при переключении на другую ветку. Но если мы не планируем вносить изменения в этом состоянии, то ничего страшного в нём нет.
Пока тегов нет
Вернёмся теперь к попытке переключить наш локальный репозиторий на конкретный коммит, который когда-то был последним в удалённой ветке article-17698-forge2.
Дело в том, что переключение репозитория на состояние конкретного прошлого коммита не является в Git чем-то повседневным. При нормальной работе нам не понадобится выполнять подобную операцию. Но если всё-таки мы решили это сделать, то репозиторий, переключенный на конкретный коммит, по хешу переходит в упомянутое выше состояние "detached HEAD". Теперь он встроен в ветку develop, и после него в этой ветке уже есть другие более свежие коммиты, то есть этот коммит не является последним в ветке.
Тем не менее, если мы воспользуемся консольными командами для выполнения такой операции переключения, то результат будет получен. Однако Git будет честно предупреждать о состоянии "detached HEAD":
Внимательные читатели могут заметить, что на последнем скриншоте мы переключались на коммит с хешем 58beccf233, а в результате Git показывает, что указатель HEAD находится на коммите с хешем 58beccf. Куда делись последние три цифры? Всё в порядке, они никуда не пропали. Просто Git может правильно понимать в командах не только полный хеш, но и какую-то его часть. Поэтому в разных интерфейсах работы с Git мы можем встретить хеши, сокращённые до разного количества символов (как правило, от 4 до 10).
При желании мы всегда можем увидеть полый хеш коммита, например, выполнив команду git log. Он будет содержать 40 цифр:
Но благодаря случайной генерации хеша для каждого нового коммита, даже несколько первых цифр в записи этого числа с очень высокой вероятностью не будут больше повторяться в репозитории . Поэтому указания лишь небольшой части хеша достаточно, чтобы Git правильно понял, какой коммит мы имеем в виду в исполняемой команде.
Использование кодировки UTF-8
Упомянем ещё один интересный аспект. В более ранних версиях редактор MetaEditor использовал для сохранения исходных кодов кодировку UTF-16LE. Но файлы, записанные в этой кодировке, почему-то считались Git бинарными, а не текстовыми. Поэтому мы не могли посмотреть при коммите, какие именно строки кода были изменены (хотя в Visual Studio Code всё равно могли). Максимум, что показывалось, — это размеры файлов до и после правок в рамках данного коммита.
Вот как это выглядело в веб-интерфейсе хранилища MQL5 Algo Forge:
Сейчас новые файлы, создаваемые в MetaEditior, сохраняются в кодировке UTF-8, и даже использование символов национальных алфавитов не приводит к автоматическому переключению на кодировку UTF-16LE. Поэтому есть смысл озаботиться конвертацией старых файлов, которые перекочевали в новое хранилище с чуть более древних времен в кодировку UTF-8. После выполнения такого преобразования, начиная со следующего коммита, можно видеть конкретные изменённые строки и символы. Например, в веб-интерфейсе хранилища MQL5 Algo Forge это может выглядеть примерно так:
Но это было отступление, давайте вернёмся к обсуждению публикации новой версии кода в репозитории.
Возвращаемся к главной задаче
Итак, среди веток нашего репозитория выделим две ветки: article-17608-close-manager и article-17607. Изменения, сделанные в них, ещё не влиты в ветку develop, поскольку работы по связанным с ветками задачам ещё не завершены. То есть эти ветки ещё будут развиваться, поэтому вливать правки из них в develop пока рано. Мы хотим продолжить одну из них (article-17607), довести до некоторого логического завершения, и после этого слить с веткой develop. Достигнутое состояние кода пометим тегом с номером версии.
Для этого нам сначала нужно будет подготовить выбранную ветку к дальнейшему внесению правок, так как за время её существования параллельно были внесены правки в других ветках. Эти правки уже перенесены в ветку develop. Поэтому надо позаботиться о том, чтобы эти правки из develop поскорее попали бы и в нашу выбранную ветку.
Влить правки из develop в article-17607 можно разными способами. Например, мы можем через веб-интерфейс создать Pull Request и повторить процесс слияния, который описывали в прошлой части. Но так следует поступать в тех случаях, когда новый, непроверенный код мы хотим влить в ветку, содержащую рабочий проверенный код. Сейчас ситуация обратная: из ветки с проверенным, рабочим кодом мы хотим перенести правку в ветку с новым, ещё непроверенным кодом. Поэтому вполне допустимо для выполнения слияния воспользоваться консольными командами Git. Воспользуемся консолью и будем контролировать ход процесса в Visual Studio Code.
Прежде всего, проверим текущее состояние репозитория. В разделе системы контроля версий мы видим историю коммитов, с указанием имён веток. Текущая ветка сейчас article-19436-forge3, в которой были сделаны последние правки. Справа в терминале виден результат консольной команды git status:
Результат выполнения команды подтверждает, что наш репозиторий сейчас действительно находится в ветке article-19436-forge3 и её состояние синхронизировано с одноимённой веткой в вышестоящем репозитории.
Переключаемся на ветку article-17607, используя команду git checkout article-17607:
И следующей командой git merge develop выполняем слияние текущей ветки с веткой develop:
Поскольку внешние изменения затрагивали те места в коде, которые мы не меняли при работе в ветке article-17607, то при слиянии никаких конфликтов не возникло. В результате был создан новый коммит слияния веток.
Выполним команду git push для отправки информации об изменениях в вышестоящий репозиторий:
Проверим хранилище MQL5 Algo Forge и увидим, что сделанные нами шаги по слиянию веток благополучно перенеслись в вышестоящий репозиторий:
Последний коммит на скриншоте — это коммит слияния веток develop и article-17607.
Посмотрите также на свободный конец ветки article-19436-forge3, который не соединён ни с какой другой веткой. Правки из этой ветки пока не влиты в ветку develop, так как они ещё не завершены. Поэтому просто не будем сейчас на них обращать внимание, когда придет время, мы сможем продолжить эту ветку.
На этом подготовка к продолжению разработки в ветке article-17607 завершена и можно переходить к работе над кодом. Решение задачи, для которой была создана эта ветка, изложено в другой статье. Здесь же мы не будем повторяться, а перейдём сразу к описанию действий по закреплению достигнутого после решения задачи состояния кода.
Выполняем слияние
Перед публикацией какого-то состояния кода нам нужно его перенести в основную ветку. Наша основная ветка — это main. В неё будут вливаться правки из ветки разработки —develop. А в ветку разработки будут вливаться правки веток отдельных задач разработки. Мы пока что не готовы перенести новый код в ветку main, поэтому ограничимся только переносом правок в ветку develop. Для демонстрации возможностей этого механизма выбор той или иной ветки, играющей роль основной, не является столь важным.
Посмотрим на состояние репозитория SimpleCandles, в котором он оказался после завершения работы над выбранной задачей:
Как видно, последний по времени коммит сделан в ветке article-17607. Создадим через веб-интерфейс хранилища MQL5 Algo Forge запрос на слияние (Pull Request) этой ветки в ветку develop, как это было описано ранее:
Проверим, что всё получилось так, как задумано. Посмотрим снова на страницу истории коммитов с деревом веток:
Видим, что коммит с хешем 432d8a0fd7 уже не помечен, как последний коммит в ветке article-17607. Зато перед ним появился новый коммит с хешем 001d35b4a7, который отмечен как последний в ветке develop. Поскольку этот коммит фиксирует слияние двух веток, то будем дальше называть его коммитом слияния.
Зайдем на страницу коммита слияния и создадим новый тег. В начале статьи мы уже показывали, где это можно сделать, а теперь пришло время осуществить создание:
В появившемся окошке введем название "v0.1", потому что это ещё далеко не финальная версия. Мы пока не знаем еще, сколько добавлений будет сделано в этот проект, но хочется надеяться, что немало. Поэтому такой маленький номер версии — это скорее напоминание самим себе, что впереди ещё много работы. Кстати, не похоже, чтобы веб-интерфейс хранилища позволял создавать аннотированные теги.
Итак, тег успешно создан, результат можно увидеть на следующей странице:
или на отдельной странице тегов репозитория:
Если мы выполним команду обновления локального репозитория (git pull), то созданный тег появится в нём. Однако в интерфейсе MetaEditor увидеть теги репозитория пока негде, поэтому покажем, как они отображаются в Visual Studio Code. Если навести мышь на нужный коммит в дереве коммитов, то во всплывающей подсказке будет видна цветная метка с именем связанного тега:
Теперь, когда тег создан, мы можем либо успокоиться на этом и использовать это имя в команде git checkout для перехода именно в это состояние кода, либо пойти дальше и создать релиз на основе этого состояния.
Создаём релиз
Релизы — это механизм маркировки и распространения конкретных версий нашего программного обеспечения вне зависимости от используемого языка программирования. Если коммиты и ветки — это "рабочий процесс" разработки, то релизы — это его "официальные результаты", которые мы хотим опубликовать. Основные цели использования этого механизма таковы:
- Версионирование. Мы отмечаем конкретные состояния кода в репозитории как обладающие определённой стабильностью, то есть отсутствием ошибок (по крайней мере явных) при реализованной функциональности. Другие пользователи смогут использовать именно такие версии кода.
- Распространение бинарных файлов. К релизам можно прикреплять скомпилированные и прочие файлы (.ex5, .dll, .zip) избавляя пользователей от необходимости самостоятельной компиляции, если у них нет в этом особой необходимости.
- Информирование пользователей. К релизу желательно добавлять описание, как правило, включающее в себя списки сделанных изменений, новых возможностей, исправленных ошибок и прочую информацию, касающуюся выпуска этой конкретной версии. Основная задача описания — дать понять пользователю, стоит ли обновляться до этой версии.
Релиз создаётся на основе какого-либо существующего тега, либо в процессе создания релиза одновременно создаётся и новый тег. Мы тег уже создали, поэтому создадим новый релиз на его основе. Для этого на странице тегов репозитория кликнем на пункт "New release" у нужного тега:
- название релиза, ветку и тег из этой ветки (новый или ранее выбранный);
- описание релиза (Release notes) — что добавлено нового, что исправлено, какие известные проблемы были решены;
- прикрепленные файлы, например, скомпилированные программы, документация или ссылки на внешние источники.
Мы можем сохранить релиз как черновик и вносить в его свойства какие-то изменения в дальнейшем, или сразу опубликовать его. Публикация не помешает внесению ещё каких-либо исправлений или дополнений, например, в описание релиза. После этого мы и все другие пользователи смогут видеть опубликованный релиз на странице релизов нашего репозитория:
Всё! Новая версия опубликована и готова к использованию. Чуть позже мы отредактировали имя релиза, которое не обязано совпадать с используемым тегом, и добавили ссылку на упоминаемую выше статью с описанием решения поставленной задачи.
Заключение
На этом мы немного приостановимся и окинем взглядом проделанную работу. Мы не просто изучили технические аспекты работы с системой контроля версий, а прошли полный путь трансформации — от разрозненных правок к целостному и структурированному процессу управления кодом. Особое значение имеет освоенный нами финальный этап — оформление завершенных работ в виде официальных версий полноценного продукта, готового к представлению пользователям. Пусть наш конкретный рассматриваемый репозиторий ещё не достиг такого уровня зрелости, но мы предприняли все усилия, чтобы быть готовыми к подобному переходу.
Рассмотренный подход принципиально меняет восприятие проекта. Из простого набора исходных файлов он превращается в упорядоченную систему с четкой историей изменений и фиксации рабочих состояний системы, позволяющую в любой момент вернуться к стабильной версии. Это полезно всем — и разработчикам, и пользователям готовых решений.
Таким образом, овладение описанным инструментарием выводит работу с хранилищем MQL5 Algo Forge на качественно новый уровень, открывая возможности для более сложных и масштабных проектов в будущем.
Спасибо за внимание, до следующих встреч!Предупреждение: все права на данные материалы принадлежат MetaQuotes Ltd. Полная или частичная перепечатка запрещена.
Данная статья написана пользователем сайта и отражает его личную точку зрения. Компания MetaQuotes Ltd не несет ответственности за достоверность представленной информации, а также за возможные последствия использования описанных решений, стратегий или рекомендаций.




- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования