Git сегодня — это самая распространенная и самая популярная система контроля версий. Пожалуй, 99% всех нынешних проектов используют Git: от Linux Kernel до наивных библиотек на JavaScript, состоящих из одного файла и одной функции.
Ядро Linux — огромный и очень сложный проект. В разработку ядра вовлечено большое количество участников-программистов по всему миру. Координировать изменения в этом проекте было бы просто невозможно, не будь у них эффективного решения, которое позволило бы всему этому сообществу работать независимо друг от друга.
Сейчас это кажется простым и очевидным решением. Однако путь к нему был долгим и тернистым.
tech
1998 год — важный год для Linux. На проект обратили внимание крупные вендоры, в него приходило всё больше и больше разработчиков. В то время в проекте действовала достаточно простая модель внесения изменений: разработчики отправляли Линусу Торвальдсу свои патчи, и он принимал решение, включить тот или иной код, или нет. Торвальдсу эта модель нравилась, ведь в этом случае он контролировал все изменения.
Механизм патчей применялся еще в те времена, когда деревья были маленькими, а компьютеры очень большими. Патч (patch), или «заплатка», буквально представлял собой надпись-указание на перфокартах, которая предписывала, что и как нужно в стопке этих носителей заменить, чтобы получить новую версию программы. А перфоленты вообще разрезались на кусочки, и эти кусочки склеивались опять-таки определенным образом, чтобы внести изменения в код программы того времени.
В общем смысле набор патчей — это набор команд-предписаний, которые позволяют отредактировать (в полу- или полностью автоматическом режиме) исходную программу, чтобы получить ее новую версию. Набор патчей всегда меньше полной версии кода. Это превратило их в удобный интерфейс передачи изменений и совместной работы коллектива программистов.
Проблемы начались, когда сообщество разработчиков начало расти. Линус Торвальдс превратился в «бутылочное горлышко», количество патчей нарастало, времени на их рассмотрение требовалось всё больше и больше. Разработчики начали использовать систему контроля версий CVS для облегчения взаимодействия друг с другом. Конечно, такой подход шел вразрез с изначальной политикой Торвальдса о внесении изменений в ядро Linux. В частности, Торвальдсу не нравилось, что существует какое-то параллельное ветвление проекта, в котором образуется свой собственный порядок работы. С другой стороны, разработчики испытывали дискомфорт и раздражение, отправляя Торвальдсу свою работу, которую он физически не мог проверить и принять (или вернуть на доработку или даже отвергнуть) в приемлемые сроки. Разработчики жаловались, что им приходится отправлять Линусу по электронной почте несколько запросов подряд, чтобы обратить внимание «великодушного диктатора» на свою работу.
Решением стало использование децентрализованной проприетарной системы контроля версий BitKeeper. Продолжительное время проект использовал это программное обеспечение, но в итоге отношения между компанией, которая разрабатывала BitKeeper, и разработчиками ядра Linux испортились.
В то время имел место весьма забавный парадокс. Ядро Linux — это открытый и свободный продукт, который был защищен лицензией GNU General Public License, GPL. Основной принцип GPL — любой пользователь может свободно использовать, распространять и изменять программное обеспечение, выпущенное под этой лицензией, но все изменения должны быть также выпущены под GPL. BitKeeper же представлял собой полностью закрытый проприетарный коммерческий продукт, принадлежавший целиком и полностью его владельцам.
Таким образом, открытый и свободный проект для координации разработок и версионирования использовал закрытую, несвободную технологию. Рано или поздно это хрупкое равновесие должно было нарушиться, и однажды это случилось.
Это привело к тому, что использование этой системы контроля версий стало невозможным. Торвальдс отверг предложение использовать Subversion и вместо этого предложил Monotone. Однако, Monotone работала невыносимо медленно. В итоге Торвальдс начал писать код своей собственной VCS (version control system — система контроля версий) на Си с нуля. Так появился Git.
Новая VCS была далека от совершенства, но была положительно оценена сообществом разработчиков и довольно быстро «обросла» необходимым инструментарием. Новая система контроля версий стремительно набирала популярность, а GitHub превратил Git в доминирующее решение для управления исходным кодом, как в открытых, так и в коммерческих закрытых проектах.
Доминирующее… Действительно, любой проект, даже самый крошечный или наоборот — огромный (с несколькими тысячами контрибьюторов), с очень высокой долей вероятности будет зарегистрирован и размещен на GitHub. Даже те проекты, которые не используют в своей работе Git (например FreeBSD или OpenBSD), давно уже разместили readonly-копии своих рабочих материалов на GitHub.
У начинающих разработчиков (да и не только у них) формируется устойчивое представление о том, что без GitHub разработка и управление проектами вообще невозможны. Поэтому, когда вы как разработчик (фрилансер или FOSS-контрибьютор) присоединяетесь к какому-либо проекту, вас добавят в команду именно на этой платформе. Даже если вас всего двое, трое, четверо… Даже если проект состоит из нескольких десятков исходных файлов. GitHub везде.
Хорошо ли это? Ответить на этот вопрос однозначно «да» или категорически «нет» будет трудно. Безусловно, GitHub обладает массой полезных инструментов, он удобен, быстр, надежен. Разработчикам в нем удобно, как в теплых домашних тапочках. Однако не следует забывать о том, что это платный сервис и управляет им небезызвестная корпорация Microsoft. Как и всякий коммерческий продукт, GitHub ориентирован в первую очередь на получение прибыли. И если по какой-либо причине ваш проект начнtт препятствовать этому (негативно воздействовать на имидж платформы и пр.) — вам мгновенно перекроют кислород. Достаточно вспомнить тяжбы GitHub с командой проекта YouTube Downloader, которым блокировали доступ, закрывали и удаляли их репозитории. И только лишь потому, что ассоциация RIAA потребовала от GitHub ограничить доступ к вышеупомянутому ПО, которое якобы способствовало нарушению авторских прав. Это привело к тому, что GitHub покинуло некоторое (немалое) количество команд, которые начали использовать альтернативы GitHub для патчей в своих проектах, такие как GitLab или Gitea.
Итак. В сухом остатке, если взять за скобки моральные и юридические аспекты, можно увидеть одно противоречие: Git разрабатывался как децентрализованная система контроля версий (в отличие от Subversion, к примеру), а GitHub, используя Git, наоборот диктует разработчикам централизованное управление. Кроме этого, получается, что разработчик фактически не владеет ничем, всё принадлежит «управляющей компании».
Есть ли жизнь за пределами комфорта? Можно ли использовать эту замечательную VCS без сторонней службы? Можно ли принимать патчи без GitHub и отправлять их на рассмотрение своей команде?
Несмотря на столь мощное влияние GitHub на сообщества разработчиков, архитектура Git осталась практически без изменений — это по-прежнему всё та же децентрализованная система контроля версий. Git не накладывает абсолютно никаких требований на среду обмена. Можно применять обычные файлы (передавая их любым способом, хоть копированием на внешние носители), можно «заливать» патчи на FTP-сервер, можно использовать SSH, в конце концов можно задействовать встроенный в Git собственный протокол обмена. Это очень удобно. Если вернуться в начало этой статьи, там упоминается, что Линус Торвальдс принимал патчи без GitHub (его, как и Git, в те времена еще не существовало) по электронной почте, а результаты выкладывал на FTP-серверы.
Перейдем же теперь непосредственно к теме нашей статьи. Предположим, нас немного, мы смелые и мы не хотим ни от кого и ни от чего зависеть. У нас есть немного денег на покупку домена, VPS и пакета для корпоративной электронной почты, чтобы обмениваться информацией друг с другом и, конечно же, отправлять патчи по электронной почте и принимать их.
Мы пытались ходить за семь морей и искать счастья в AWS и DigitalOcean, но не задалось. И дорого, и, увы, недоступно. Покупка хлопотная, гарантий нет. Зачем искать где-то, если всё, что нам необходимо, есть прямо под рукой? Итак, выбираем Timeweb Cloud.
Напишем список задач, которые нам необходимо осуществить, чтобы сформировать для своего проекта необходимую инфраструктуру.
Итак:
Приобрести домен можно в панели Timeweb Cloud. Выбираем тот, который нам подходит наилучшим образом, в нашей статье мы зарегистрировали и используем домен twhelp.site
.
Далее следует приобрести корпоративную электронную почту, это также доступно в панели управления Timeweb Cloud.
Обязательно ли покупать домен, регистрировать корпоративную почту и пр.? Вовсе нет! Можно воспользоваться бесплатными ящиками, а домен вообще не использовать, либо приобрести его когда-нибудь, когда он будет необходим. Всё, в конечном счете, зависит от требований проекта. Однако, уже на первых этапах проекту может понадобиться сайт, средство обмена сообщениями (почтой) или файлами, а также инфраструктура запуска и развертывания продукта. Всё это можно приобрести частями в разных местах, а можно объединить на одном лицевом счете и развернуть под эгидой своего проекта. В этом случае Timeweb Cloud предоставляет удобные и надежные службы и инструменты.
Предположим, что мы разрабатываем веб-приложение и нам требуется инфраструктура. Мы выбираем Timeweb Cloud и настраиваем наши службы там. После покупки домена и настройки DNS нам нужно зарегистрировать столько почтовых ящиков, сколько потребуется для работы.
После создания ящиков нам необходимо настроить доступ к нашим ящикам в почтовых клиентах и в Git.
Инструкции по настройке почтовых клиентов можно найти на страницах помощи Timeweb Cloud, а вот Git нам придется настроить вручную.
Начинается всё с установки специального пакета-расширения для Git, который называется git-email
.
Это делается при помощи установщика пакетов той операционной системы или ее дистрибутива, в которой вы работаете. Например:
РЕД ОС
sudo dnf install git-email
Alt Linux
sudo apt-get install git-email
В операционной системе Windows git-email
входит в стандартный установочный пакет git
.
Следующий этап — это настройка.
В терминале вашей операционной системы нужно дать команду:
git config --global --edit
Будет запущен ваш любимый терминальный (или иной) текстовый редактор, где вам нужно внести в конфигурацию Git следующие строки (в статье использованы тестовые учетные данные, вы вносите свои!):
[user]
name = Vasya Poopkine
email = zerozero@twhelp.site
[sendemail]
smtpserver = smtp.timeweb.ru
smtpuser = zerozero@timeweb.site
smtpencryption = ssl
smtpserverport = 465
Параметр smtpencryption
может быть установлен в режим ssl
и tls
. Второй режим применяет STARTTLS для начала обмена по зашифрованному транспортному каналу, а первый инициирует шифрование сразу после подключения. Установка режима и порта зависит от требований провайдера e-mail.
Секция [user]
является обязательной. В этой секции вы идентифицируете себя, и эта информация будет отображаться во всех патчах и во всех коммитах, сделанных вами. Чтобы добиться более строгой идентификации патчей и коммитов, в Git применяется механизм подписи отправляемой информации при помощи ключей gpg. Но это другая история.
Итак, мы настроили Git для отправки патчей по электронной почте. Попробуем теперь всё это в деле. Нам нужно получить клон (копию) текущей рабочей версии репозитория. Сделать это можно разными способами, о которых мы поговорим в конце нашей статьи.
После клонирования внесем правки в наш проект.
Создадим файл log_stderr.go
:
package main
import (
"fmt"
"time"
"os"
)
func logStderr(message string, args ...interface{}) {
x := time.Now()
fmt.Fprint(os.Stderr, x.Format(time.RFC822))
fmt.Fprint(os.Stderr, " - ")
fmt.Fprintf(os.Stderr, message, args...)
}
Применим изменения:
git add log_stderr.go
git commit -m "log into stderr func"
Теперь отправим наш патч на просмотр руководителю проекта:
git send-email --to="project-boss@twhelp.site" HEAD^
В аргументе --to
можно указать более одного адреса, просто отделяйте их друг от друга запятыми. Таким образом вы можете отправить свой патч всем участникам проекта. А еще можно использовать аргумент --cc
(carbon copy), который также принимает список e-mail-адресов через запятую. Этот способ более предпочтителен в том случае, если вам необходимо отправлять свои патчи на просмотр всей команде или отдельным заинтересованным участникам.
Чтобы не указывать в командной строке каждый раз одно и то же, можно внести получателей наших патчей в конфиг. Делается это следующими командами
git config sendemail.to "project-boss@twhelp.site"
git config sendemail.cc "user1@email.tld","user2@email.tld",…, "userN@email.tld"
После этого достаточно просто дать команду git send-email HEAD^
, и ваш патч уйдет по адресам, которые были указаны в конфиге.
В этом примере мы отправили текущие изменения из своей рабочей копии (
HEAD^
). Можно отправлять любые изменения, например два изменения до текущего или по хэш-коду коммита. Более подробно это описано в документации Git.
После этого Git сформирует патч и попытается отправить его на SMTP-сервер, который мы указали в конфиге. Если SMTP-сервер потребует авторизацию, вы должны будете ввести свой пароль. Если вы отправляете большое количество патчей, это может быть немного утомительным. Пароль можно вписать в конфиг, но учтите, что он будет храниться там в незашифрованном виде.
git config --global sendemail.smtpPass 'your password'
Второй вариант может быть более предпочтительным: вы задаете Git время, в течение которого он хранит пароль в кэше, и не спрашивает вас.
git config --global credential.helper 'cache --timeout 3600'
Другие, более сложные решения могут использовать менеджеры паролей и расширение git-credential
, но тут мы это не рассматриваем.
Участники команды получают ваш патч в виде обычного текстового сообщения электронной почты, они могут проверить патч и даже, представьте себе, не принять ваши изменения с вердиктом «исправить» или «переписать». Это совершенно естественно, на этом и зиждется процесс коллективной разработки программного обеспечения. Полная свобода, управление патчами вручную — вот что так привлекает разработчиков к выработке своих собственных решений обмена информацией.
Как же быть, если нас попросили исправить наш патч? Предположим, что разработчики решили немного сократить количество вызовов функции Fprintf
и добавить уровень логирования (severity).
Наш код будет теперь выглядеть так:
package main
import (
"fmt"
"time"
"os"
)
type LogSeverity string
const (
ERR LogSeverity = "ERROR"
WARN LogSeverity = "WARN"
INFO LogSeverity = "INFO"
DEBUG LogSeverity = "DEBUG"
)
func LogStderr(message string, severity LogSeverity, args ...interface{}) {
x := time.Now()
fmt.Fprintf(os.Stderr, "%s - %s - ", x.Format(time.RFC822), severity)
fmt.Fprintf(os.Stderr, message, args...)
fmt.Fprint(os.Stderr, "\n")
}
Поскольку мы исправляем наш предыдущий патч, а других патчей после этого мы больше не выпускали, то мы можем просто внести корректировку (amendment) в наш текущий патч.
git commit -a --amend
Отправить патч теперь нужно командой (памятуя о том, что мы уже добавили в конфиг адресатов):
git send-email --annotate -v2 HEAD^
Ключ -v2
означает, что мы отправляем вторую версию патча, если нам нужно новое исправление, мы используем -v3
и т. д.
Ключ --annotate
необходим для того, чтобы внести комментарии в наше сообщение электронной почты. Git откроет текстовый редактор, в котором вы увидите нечто подобное:
Subject: [PATCH v2] Функция логирования в stderr
---
Добавлен уровень лога, уменьшено количество вызовов fmt.Fprintf
Добавим наш текст, закроем текстовый редактор с сохранением файла, и патч снова будет отправлен по электронной почте нашим адресатам.
Всегда добавляйте аннотации к своим патчам. Это в значительной степени облегчает работу вашим коллегам и вам. Однако каждый раз указывать --annotate
весьма утомительно. Автоматизировать это можно, указав соответствующий параметр в конфиге:
git config --global sendemail.annotate yes
Итак, отправлять патчи мы научились, но как теперь их принимать и интегрировать в свой проект? Сделать это чуть сложнее. Во-первых, Git отправляет специальным образом отформатированный патч, несмотря на то, что мы используем обычный текст в обычном сообщении электронной почты. Во-вторых, таких патчей может быть довольно много. В-третьих, Git не накладывает никаких ограничений на транспорт, по которому передаются патчи. А это значит, что Git не будет специально заботиться о том, как принимать информацию: это целиком и полностью ложится на плечи разработчика. Так как же?
Просто воспользуйтесь возможностями своего почтового клиента. После получения аннотированных одобренных патчей вам следует сохранить одно или более сообщений с патчами в файл в формате mbox
(Unix mailbox). Этот формат позволяет сохранять одно или более сообщений электронной почты в одном большом файле.
Далее следует дать команду:
git am <путь до патчей в mbox>
После чего все патчи будут инкорпорированы в вашу рабочую копию. Можно продолжать творить и удивлять.
Сценарии работы в Git через электронную почту могут быть простыми, как в этом небольшом руководстве, так и весьма изощрёнными. Самое главное, чтобы это устраивало команду и не создавало неоправданных неудобств.
Кажется, нет ничего проще, изящнее и элегантнее, чем работать с Git по электронной почте. Есть, правда, одна весьма существенная проблема: передача рабочей копии подключившимся к проекту разработчикам. Если проект большой, с богатой историей изменений, он может иметь весьма значительный «вес» в мегабайтах и даже гигабайтах. Передать такой объем по электронной почте невозможно, она просто не предназначена для этого. Как же быть, как предоставить новому участнику проект и всю историю изменений?
В Git существует весьма интересная штука, которая называется bundle. Это «срез» рабочей копии или вся рабочая копия в двоичном формате изменений Git. Bundle гораздо компактнее набора текстовых патчей, история и данные внутри bundle сжаты, а сам формат позволяет передавать как текстовые данные, так и двоичные.
Для новых разработчиков руководитель проекта или иное ответственное лицо может специально выкладывать на каком-либо файлообменном сервисе актуальный бандл всего проекта. В качестве такого сервиса может выступать FTP-сервер или объектное S3-подобное хранилище Timeweb Cloud.
Новичок скачивает бандл проекта, а затем делает из него clone:
git clone project.bundle <new place>
После этого в new place мы получим новую рабочую копию, в которой уже можно работать по электронной почте. Но если быть откровенными, механизм бандлов в Git — это своего рода альтернатива всей вышеописанной схеме обмена патчами и пр. Однако, коллективная работа при помощи bundles — это уже совершенно другая история.