Говоря о системе управления версиями (VCS) файлов Git необходимо упомянуть об архитектуре её реализации. Именно она определяют преимущества и недостатки.
Прежде всего Git — распределённая VCS. Это значит, что мы работаем не с одним репозитарием на сервере, а каждый имеет у себя локальную копию репозитария. Соответственно, такие операции, как checkout и commit производятся с локальным репозитарием. Друг с другом же (или с тем, что на сервере) репозитарии синхронизируются специально предназначенными командами pull (fetch) и push. Это удобно. Это позволяет коммитить столь часто, сколь угодно, даже если в данный момент отсутствует соединение с сервером.
Так же при работе с локальным репозиториями в несколько раз повышается скорость выполнения всех операций.
Перед сохранением любого файла Git вычисляет контрольную сумму, и она становится индексом этого файла. Поэтому невозможно изменить содержимое файла или каталога так, чтобы Git не узнал об этом. Эта функциональность встроена в сам фундамент Git'а и является важной составляющей его философии. Если информация потеряется при передаче или повредится на диске, Git всегда это выявит.
Механизм, используемый Git'ом для вычисления контрольных сумм, называется SHA-1 хешем. Это строка из 40 шестнадцатеричных символов (0-9 и a-f), вычисляемая в Git'е на основе содержимого файла или структуры каталога. SHA-1 хеш выглядит примерно так:
24b9da6552252987aa493b52f8696cd6d3b00373
Практически все действия, которые вы совершаете в Git'е, только добавляют данные в базу. Очень сложно заставить систему удалить данные или сделать что-то неотменяемое. Можно, как и в любой другой VCS, потерять данные, которые вы ещё не сохранили, но как только они зафиксированы, их очень сложно потерять, особенно если вы регулярно отправляете изменения в другой репозиторий.
Поэтому пользоваться Git'ом — удовольствие, потому что можно экспериментировать, не боясь что-то серьёзно поломать.
Главное отличие Git'а от любых других SVC (например, Subversion и ей подобных) — это то, как Git смотрит на свои данные. В принципе, большинство других систем хранит информацию как список изменений (патчей) для файлов. Эти системы (CVS, Subversion, Perforce, Bazaar и другие) относятся к хранимым данным как к набору файлов и изменений, сделанных для каждого из этих файлов во времени.
Git не хранит свои данные в таком виде. Вместо этого Git считает хранимые данные набором слепков небольшой файловой системы. Каждый раз, когда вы фиксируете текущую версию проекта, Git, по сути, сохраняет слепок того, как выглядят все файлы проекта на текущий момент. Ради эффективности, если файл не менялся, Git не сохраняет файл снова, а делает ссылку на ранее сохранённый файл. То, как Git подходит к хранению данных, показано на рисунке.
Это важное отличие Git'а от практически всех других систем контроля версий. Из-за него Git вынужден пересмотреть практически все аспекты контроля версий, которые другие системы переняли от своих предшественниц.
Во многом благодаря именно такой модели хранения данных Git смог реализовать свою “killer feature“ - поддержка нелинейной разработки (тысячи параллельных веток).
Но есть и некоторые отрицательные моменты. Отсутствие сквозной нумерации коммитов монотонно непрерывно возрастающими целыми числами. Для идентификации ревизий используется хэш SHA1, что приводит к необходимости оперировать длинными строками вместо коротких номеров версий, как во многих других системах (хотя в командах допускается использование неполных хэш-строк).
Большие затраты времени, по сравнению с файл-ориентированными системами, на формирование истории конкретного файла, истории правок конкретного пользователя, поиска изменений, относящихся к заданному месту определённого файла. Система работает только с файлами и их содержимым, и не отслеживает пустые каталоги.
Почти каждая VCS имеет в какой-то форме поддержку ветвления. Ветвление означает, что вы отклоняетесь от основной линии разработки и продолжаете работу, не вмешиваясь в основную линию. Во многих VCS это в некотором роде дорогостоящий процесс, зачастую требующий от вас создания новой копии каталога с исходным кодом, что может занять продолжительное время для больших проектов.
Способ ветвления в Git'е чрезвычайно легковесен, что делает операции ветвления практически мгновенными и переключение туда-сюда между ветками обычно так же ыстрым. В отличие от многих других VCS, Git поощряет процесс работы, при котором ветвление и слияние осуществляется часто, даже по несколько раз в день. Понимание и владение этой функциональностью даёт уникальный мощный инструмент и может буквально изменить то, как ведётся разработка. Примером такой разработки является модель разработки «Удачная модель ветвления для Git».
Так же стоит отметить механизм слияния ветвей, поскольку ветки без слияния — мертвы. С механизмом слияния Git на сегодняшний день является лучший, а некоторые делают еще и криво (CVS, Subversion)
В Git кроме слияния поддерживается ещё и rebase. Эта операция получения набора всех изменений ветви А, с последующим их «накатом» на ветвь B. В результате ветвь B продвигается до состояния AB. В отличие от слияния, в истории ветви AB не останется никаких промежуточных коммитов ветви A (только история ветви B и запись о самом rebase, это упрощает интеграцию крупных и очень крупных проектов).
Предлагаемая модель ветвления опирается на конфигурацию проекта, содержащую один центральный «истинный» репозиторий, который содержит:
master – ветвь, исходный код которой находиться в состоянии production-ready в любой произвольный момент времени. develop – ветвь для разработки, Хранящийся в ней код в любой момент времени должен содержать самые последние изданные изменения, необходимые для следующего релиза. Эту ветку также можно назвать «интеграционной». Она служит источником для сборки автоматических ночных билдов.
Когда исходный код в ветви разработки (develop) достигает стабильного состояния и готов к релизу, все изменения должны быть влиты в главную ветвь (master) и помечены тегом с номером релиза. Следовательно, каждый раз, когда изменения вливаются в главную ветвь (master), мы по определению получаем новый релиз.
Помимо главных ветвей master и develop модель разработки содержит некоторое количество типов вспомогательных ветвей, которые используются для распараллеливания разработки между членами команды, для упрощения внедрения нового функционала (features), для подготовки релизов и для быстрого исправления проблем в производственной версии приложения. В отличие от главный ветвей, эти ветви всегда имеют ограниченный срок жизни. Каждая из них в конечном итоге рано или поздно удаляется. У каждого типа ветвей есть своё специфическое назначение и строгий набор правил, от каких ветвей они могут порождаться, и в какие должны вливаться. Сейчас мы рассмотрим их по очереди.
Ветви функциональностей (Feature branches) – порождаются от develop. Должны вливаться в develop. Соглашение о наименовании: всё, за исключением master, develop, release-* или hotfix-*. Ветви функциональностей (feature branches), также называемые иногда тематическими ветвями (topic branches), используются для разработки новых функций, которые должны появиться в текущем или будущем релизах. При начале работы над функциональностью (фичей) может быть ещё неизвестно, в какой именно релиз она будет добавлена. Смысл существования ветви функциональности (feature branch) состоит в том, что она живёт так долго, сколько продолжается разработка данной функциональности (фичи). Когда работа в ветви завершена, последняя вливается обратно в главную ветвь разработки (что означает, что функциональность будет добавлена в грядущий релиз) или же удаляется (в случае неудачного эксперимента).
Ветви релизов (Release branches) — порождаются от develop. Должны вливаться в: develop и master Соглашение о наименовании: release-*. Ветви релизов (release branches) используются для подготовки к выпуску новых версий продукта. Они позволяют расставить финальные точки над i перед выпуском новой версии. Кроме того, в них можно добавлять минорные исправления, а также подготавливать метаданные для очередного релиза (номер версии, дата сборки и т.д.). Когда вся эта работа выносится в ветвь релизов, главная ветвь разработки (develop) очищается для добавления последующих фич (которые войдут в следующий большой релиз).
Ветви исправлений (Hotfix branches) - порождается от master. Должны вливаться в develop и master Соглашение о наименовании: hotfix-*. Ветви для исправлений (hotfix branches) весьма похожи на ветви релизов (release branches), так как они тоже используются для подготовки новых выпусков продукта, разве лишь незапланированных. Они порождаются необходимостью немедленно исправить нежелательное поведение производственной версии продукта. Когда в производственной версии находится баг, требующий немедленного исправления, из соответствующего данной версии тега главной ветви (master) порождается новая ветвь для работы над исправлением. Смысл её существования состоит в том, что работа команды над ветвью разработки (develop) может спокойно продолжаться, в то время как кто-то один готовит быстрое исправление производственной версии.
В целом система Git интересна и многогранна. Она была спроектирована с оглядкой на предыдущие поколения, с учетом необходимости эффективной работы с большими проектами, как по скорости, так и по размеру данных, при этом оставаясь надежной. Её жизнеспособность проверена многими проектами, в том числе и проектом ядра Linux, проектом, для которого был создан Git.