Глава 3. Все о клонировании

В старых системах управления версиями стандартная операция для получения файлов — это checkout. Вы получаете набор файлов в конкретном сохраненном состоянии.

В Git и других распределенных системах управления версиями стандартный способ — клонирование. Для получение файлов вы создаете «клон» всего хранилища. Другими словами, вы фактически создаете зеркало центрального сервера. При этом всё, что можно делать с основным хранилищем, можно делать и с локальным.

Синхронизация компьютеров

Я вполне приемлю создание архивов или использование rsync для резервного копирования и простейшей синхронизации. Но я работаю то на ноутбуке, то на стационарном компьютере, которые могут никак между собой не взаимодействовать между этим.

Создайте хранилище Git и закоммитьте файлы на одном компьютере. А потом выполните на другом

$ git clone первый.компьютер:/путь/к/файлам

для создания второго экземпляра файлов и хранилища Git. С этого момента команды

$ git commit -a
$ git pull другой.компьютер:/путь/к/файлам HEAD

будут «втягивать» состояние файлов с другого компьютера на тот, где вы работаете. Если вы недавно внесли конфликтующие изменения в один и тот же файл, Git даст вам знать, и нужно будет сделать коммит заново после разрешения ситуации.

Классическое управление исходным кодом

Создайте хранилище Git для ваших файлов:

$ git init
$ git add .
$ git commit -m "Начальный коммит"

На центральном сервере создайте так называемое «голое» (bare) хранилище Git в неком каталоге:

$ mkdir proj.git
$ cd proj.git
$ git init --bare
$  # вариант «в одну строчку»: GIT_DIR=proj.git git init

Запустите Git-демон, если необходимо:

$ git daemon --detach # возможно уже запущен

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

Отправьте ваши изменения в центральное хранилище вот так:

$ git push git://центральный.сервер/путь/к/proj.git HEAD

Для получения ваших исходников разработчик вводит

$ git clone git://центральный.сервер/путь/к/proj.git

После внесения изменений разработчик сохраняет изменения локально:

$ git commit -a

Для обновления до последней версии:

$ git pull

Любые конфликты слияния нужно разрешить и закоммитить:

$ git commit -a

Для выгрузки локальных изменений в центральное хранилище:

$ git push

Если на главном сервере были новые изменения, сделанные другими разработчиками, команда push не сработает. В этом случае разработчику нужно будет вытянуть к себе (pull) последнюю версию, разрешить возможные конфликты слияний и попробовать еще раз.

Голые (bare) хранилища

Голое (bare) хранилище называются так потому, что у него нет рабочего каталога. Оно содержит только файлы, которые обычно скрыты в подкаталоге .git. Другими словами, голое хранилище содержит историю изменений, но не содержит снимка какой-либо определенной версии.

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

Многие команды Git не работают в голых хранилищах, если переменная среды GIT_DIR не содержит путь до хранилища и не указан параметр --bare.

Push или pull?

Зачем вводится команда push, вместо использования уже знакомой pull? Прежде всего, pull не работает в голых хранилищах, вместо нее нужно использовать команду fetch, которая будет рассмотрена позже. Но даже если держать на центральном сервере нормальное хранилище, использование команды pull в нем будет затруднительным. Нужно будет сначала войти на сервер интерактивно и сообщить команде pull адрес машины, с которой мы хотим забрать изменения. Этому могут мешать сетевые брандмауэры (firewall), но в первую очередь: что если у нас нет интерактивного доступа к серверу?

Тем не менее, не рекомендутся push-ить в хранилище помимо этого случая — из-за путаницы, которая может возникнуть, если у целевого хранилища есть рабочий каталог.

Короче говоря, пока изучаете Git, push-те только в голые хранилища. В остальных случаях pull-те.

Создание форка проекта

Не нравится путь развития проекта? Думаете, можете сделать лучше? Тогда на вашем сервере выполните

$ git clone git://основной.сервер/путь/к/файлам

Теперь расскажите всем о форке (ответвлении, прим. пер.) проекта на вашем сервере.

Позже вы сможете в любой момент втянуть к себе изменения из первоначального проекта:

$ git pull

Максимальные бэкапы

Хотите иметь множество защищенных, географически разнесенных запасных архивов? Если в вашем проекте много разработчиков, ничего делать не нужно! Каждый клон — это и есть резервная копия; не только текущего состояния, но и всей истории изменений проекта. Благодаря криптографическому хешированию, повреждение какого-либо из клонов будет обнаружено при первой же попытке взаимодействия с другими клонами.

Если ваш проект не такой популярный, найдите как можно больше серверов для размещения клонов.

Особо беспокоящимся рекомендуется всегда записывать самый последний 20-байтный SHA1 хеш HEAD в каком-нибудь безопасном месте. Оно должно быть безопасным, а не тайным. Например, хороший вариант — публикация в газете, потому что атакующему сложно изменить каждый экземпляр газеты.

Многозадачность со скоростью света

Скажем, вы хотите работать над несколькими функциями параллельно. Тогда закоммитьте ваши изменения и запустите

$ git clone . /некий/новый/каталог

Благодаря жёстким ссылкам создание локального клона требует меньше времени и места, чем простое копирование.

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

$ git pull /другой/клон HEAD

Партизанское управление версиями

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

$ git init
$ git add .
$ git commit -m "Начальный коммит"

затем склонируйте его:

$ git clone . /некий/новый/каталог

Теперь перейдите в этот новый каталог и работайте в нем вместо основного, используя Git в свое удовольствие. В какой-то момент вам понадобиться синхронизировать изменения со всеми остальными — тогда перейдите в изначальный каталог, синхронизируйте его с помощью другой системы управления версиями и наберите

$ git add .
$ git commit -m "Синхронизация с остальными"

Теперь перейдите в новый каталог и запустите

$ git commit -a -m "Описание моих изменений"
$ git pull

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

Subversion (вероятно, наилучшая централизованная система управления версиями) используется неисчислимым множеством проектов. Команда git svn автоматизирует описанный процесс для хранилищ Subversion, а также может быть использована для экспорта проекта Git в хранилище Subversion.

Mercurial

Mercurial — похожая система управления версиями, которая может работать в паре с Git практически без накладок. С расширением hg-git пользователь Mercurial может без каких либо потерь push-ить и pull-ить из хранилища Git.

Получить hg-git можно с помощью Git:

$ git clone git://github.com/schacon/hg-git.git

или Mercurial:

$ hg clone http://bitbucket.org/durin42/hg-git/

К сожалению, мне неизвестен аналогичное расширение для Git. Поэтому я рекомендую использовать Git, а не Mercurial, для центрального хранилища, даже если вы предпочитаете Mercurial. Для проектов, использующих Mercurial, обычно какой-нибудь доброволец поддерживает параллельное хранилище Git для привлечения пользователей последнего, тогда как проекты, использующие Git, благодаря hg-git автоматически доступны пользователям Mercurial.

Хотя расширение может сконвертировать хранилище Mercurial в Git путем push'а в пустое хранилище, эту задачу легче решить, используя сценарий hg-fast-export.sh, доступный как

$ git clone git://repo.or.cz/fast-export.git

Для преобразования выполните в пустом каталоге

$ git init
$ hg-fast-export.sh -r /hg/repo

после добавления сценария в ваш $PATH.

Bazaar

Упомянем вкратце Bazaar, так как это самая популярная свободная распределенная система управления версиями после Git и Mercurial.

Bazaar относительно молод, поэтому у него есть преимущество идущего следом. Его проектировщики могут учиться на ошибках предшественников и избавиться от исторически сложившихся неровностей. Кроме того, его разработчики заботятся о переносимости и взаимодействии с другими системами управления версиями.

Расширение bzr-git позволяет (в какой-то степени) пользователям Bazaar работать с хранилищами Git. Программа tailor конвертирует хранилища Bazaar в Git и может делать это с накоплением, тогда как bzr-fast-export хорошо приспособлена для разовых преобразований.

Почему я использую Git

Изначально я выбрал Git потому, что слышал, что он в состоянии справиться с совершенно неуправляемыми исходными текстами ядра Linux. Я никогда не ощущал потребности сменить его на что-то другое. Git работает замечательно и мне еще только предстоит напороться на его недостатки. Так как я в основном использую Linux, проблемы на других системах меня не касаются.

Я также предпочитаю программы на C и сценарии на bash исполняемым файлам вроде сценариев на Python-е: у них меньше зависимостей, и я привык к быстрому выполнению.

Я думал о том, как можно улучшить Git, вплоть до того, чтобы написать собственный инструмент, похожий на Git; но только как академическое упражнение. Завершив проект, я бы все равно продолжил пользоваться Git, потому что выигрыш слишком мал, чтобы оправдать использование самодельной системы.

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