how to: Как и зачем работать с svn через git
В статье я расскажу, как мы работаем с svn через git и почему не выбрали чистый git.
Subversion — это централизованная система контроля версий. Это главный ее минус и главный ее плюс 🙂
Плюс в том, что централизация дает возможность, например, нумеровать коммиты, т.к. их порядок известен.
Так же она минимизирует конфликты (хотя об этом можно и поспорить), т.к. текущее состояние репозитория одно и оно всем известно.
В svn можно хранить несколько проектов в одном репозитории. Вообще интефрейс репозитория в svn очень похож на файловую систему, что обеспечивает минимальный порог вхождения для тех, кто никогда не работал с системами контроля версий.
Главный минус — это merge… Те, кто часто делает мерж средствами svn, понимает о чем я.
Это медленно (даже меееееееедлееенно), требует постоянного соединения с репозиторием, а еще эти svn-properties, которые мешают читать diff.
Казалось бы — решение лежит на поверхности, надо просто сменить систему контроля версий. В нашем же случае нельзя просто так взять и перейти на git.
Причин тому несколько, и все они обусловлены наследием. Если бы мы начинали разработку сейчас, то скорей бы всего выбрали git. У нас репозиторию уже около шести лет, за это время мы создали в нем 129 проектов, а число ревизий перевалило за 88 000.
Мы используем trac в качестве багтрекера. В нем сейчас более 10 тыс тикетов. Во многих есть ссылки на коммиты, подтверждающие исправления. Это богатое наследие терять не хочется.
Так же у svn есть плюс — все проекты лежат в одном репозитории. Trac думает, что проект у нас один, что сильно облегчает работу с ним.
Другими словами, отказ от svn для нас слишком затратен, но мержи.
Решение
Последняя команда займет ощутимое время. На нашем репозитории — часа 4.
—stdlayout как бы говорит нам, что расположение проекта у нас стандартное:
Транк теперь называется master, все остальные бранчи именованы как обычно.
Работа с бранчами:
И как теперь с этим работать?
Для мержа в master (trunk)
Subversion vs. Git: Развенчивание мифов о развенчивании мифов
Я относительно недавно сменил работу, попал в компанию, где используется svn, но переход на git часто всплывает в обсуждениях.
Однажды я стал свидетелем обсуждения этой темы. Коллеги обсуждали тот самый сайт и пришли к выводу, что «меняем шило на мыло».
В этом диалоге я был невольным слушателем, но что там за сайт и его аргументы меня заинтересовали. Пошел разбираться.
Начнем с первого заявления
The particular delta compression algorithms used in both version control systems differ in many details, but in general Subversion and Git store data in the same way. This results in the fact that Subversion and Git repositories with equivalent data will have approximately the same size. Except for the case of storing a lot of binary files, when Subversion repositories could be significantly smaller than Git ones (because Subversion’s xdelta delta compression algorithm works both for binary and text files).
Ниже есть пример, где они сравнивают размер репозитория. Вывод – разница не существенна.
Меня смутило различное число коммитов, и фактически разные первоисточники(кто знает, как они там синхронизируют эти репозитории). Так же меня не устроил уровень детализации описания процесса получения этих чисел.
Итак, начнем свой эксперимент!
Получаем svn репозиторий
У нас локальная копия всего репозитория в формате svn. Это папка размером 213 МБ, которая содержит 79758 файлов и 88 папок.
На этот момент в репозитории насчитывается 39864 коммита. Рабочая копия проекта состоит из 1701 файла и 160 папок.
Начинаем миграцию в гит
Этот этап был самым длительным, затянулся более чем на сутки (примерно 32 часа). В результате имеем git репозиторий — копия оригинального svn репозитория(не совсем копия, но для нас различия не существенны).
Здесь я сделал небольшую глупость, стоило бы создавать репозиторий без рабочей копии, но еще раз ждать более суток я был не готов.
Итак, папка git_from_svn/.git: 208 МБ содержит 7841 файлов и 509 папок. На данном этапе действительно можно говорить о незначительном перевесе в пользу git, видимо как раз на этом этапе и остановились те, кто ведет сайт. Но ведь у гита есть 2 формата хранения: “loose” object и “packfile».
Посмотрим, что же мы имеем:
count: 6826
size: 30.21 MiB
in-pack: 249852
packs: 25
size-pack: 145.51 MiB
prune-packable: 73
garbage: 0
size-garbage: 0 bytes
То есть у нас есть множество пакетов и 6826 (30.21 МБ) не сжатых объектов.
Оптимизируем хранение
count: 0
size: 0 bytes
in-pack: 256605
packs: 1
size-pack: 104.54 MiB
prune-packable: 0
garbage: 0
size-garbage: 0 bytes
Размер самой папки «.git» получается 136 МБ(945 файлов, 255 папок). Мне кажется такое преимущество уже сложно назвать незначительным.
Еще подчистим
Но и это еще не все, если избавиться от наследия svn — пушнуть это все в bare репозиторий получаем еще интересней картинку: 106 MБ, 19 файлов, 8 папок.
Соберем все вместе
svn — 213 MБ (79 758 файлов, 88 папок)
svn(после pack) — 214 MБ (4 644 файлов, 89 папок) (дополнение после публикации)
git svn — 208 MБ (7 841 файлов, 509 папок)
git svn(pack) — 136 MБ (945 файлов, 255 папок)
git bare(pack) — 106 MБ (19 файлов, 8 папок)
Мне кажется на этом этапе развенчивание мифа можно считать развенчанным(утверждение на сайте опровергнуто).
Еще стоит упомянуть, что loose объекты у вас все же будут, предназначены они для повышения производительности работы с часто используемыми файлами. Обычно в таком формате будут храниться файлы из веток, в которых сейчас активно идет работа. Их количество можно регулировать через конфигурационные файлы.
Идем дальше
Branches in Subversion are implemented with Copy-On-Write strategy (referred to as ‘Cheap Copies’ in the svnbook). No matter how large a repository or project is, it takes a constant amount of time and space to make a branch. In fact, Subversion branches are extremely cheap beginning with version 1.0 and you can branch even for small bugfixes in a very busy and large project.
И эксперимент это «подтверждающий».
Вывод – создание бранчи происходит быстрей чем вы глазом моргнуть успеете. Мне показалось, что если вся операция занимает меньше 0,01 секунды то тут и сравнивать нечего. Но почему-то на заявление о дороговизне бранчей в svn, сайт проверил только их создание. Но есть другие операции, например клонирование( или svn checkout). В этом эксперименте все происходит локально, возможное влияние сети исключено.
Первый эксперимент – клонирование
Git проиграл. Но здесь стоит учесть, git получил всю историю, а svn — одну ревизию.
Второй эксперимент – смена бранчи
Здесь все наоборот, при этом на одном переключении мы отыграли половину от потери при клонировании.
На этом я пожалуй закончу. Пойду обсуждать эти результаты с сотрудниками.
PS: Несмотря на то, что посыл этой заметки банален «не стоит доверять непроверенным источникам в интернете», но, оказывается, есть еще люди, не развившие достаточный уровень здорового скептицизма.
Git и Subversion
В настоящее время большинство проектов с открытым исходным кодом, а также большое число корпоративных проектов, используют Subversion для управления своим исходным кодом. Это самая популярная на текущий момент система контроля версий с открытым исходным кодом, история её использования насчитывает около 10 лет. Кроме того, она очень похожа на CVS, систему, которая была самой популярной до Subversion.
git svn
Важно отметить, что при использовании git svn вы взаимодействуете с Subversion — системой, которая намного менее «продвинута», чем Git. Хоть вы и умеете с лёгкостью делать локальное ветвление и слияние, как правило, лучше всего держать свою историю в как можно более линейном виде, используя перемещения (rebase) и избегая таких вещей, как одновременный обмен с удалённым Git-репозиторием.
Не переписывайте свою историю, попробуйте отправить изменения ещё раз, а также не отправляйте изменения в параллельный Git-репозиторий, используемый для совместной работы, одновременно с другими разработчиками, использующими Git. Subversion может иметь только одну единственную линейную историю изменений, сбить с толку которую очень и очень просто. Если вы работаете в команде, в которой некоторые разработчики используют Git, а другие Subversion, убедитесь, что для совместной работы все используют только SVN-сервер — это сильно упростит вам жизнь.
Настройка
Чтобы мы могли продолжить, прежде всего создайте новый локальный репозиторий Subversion:
Теперь вы можете синхронизировать проект со своей локальной машиной, вызвав svnsync init с параметрами, задающими исходный и целевой репозиторий:
Эта команда подготовит процесс синхронизации. Затем склонируйте код, выполнив:
Хотя выполнение этой операции и может занять всего несколько минут, однако, если вы попробуете скопировать исходный репозиторий в другой удалённый репозиторий, а не в локальный, то процесс займёт почти час, хотя в этом проекте менее ста коммитов. Subversion вынужден клонировать ревизии по одной, а затем отправлять их в другой репозиторий — это чудовищно неэффективно, однако это единственный простой способ выполнить это действие.
Приступим к работе
Таким образом, вы должны были получить корректный Git-репозиторий с импортированными ветками и метками:
Важно отметить, что эта утилита именует ваши ссылки на удалённые ресурсы по-другому. Когда вы клонируете обычный Git-репозиторий, вы получаете все ветки с удалённого сервера на локальном компьютере в виде: origin/[ветка] — в пространстве имён с именем удалённого сервера. Однако, git svn полагает, что у вас не будет множества удалённых источников данных и сохраняет все ссылки на всякое, находящееся на удалённом сервере, без пространства имён. Для просмотра всех имён ссылок вы можете использовать служебную команду Git’а show-ref :
Обычный Git-репозиторий выглядит скорее так:
Коммит в Subversion
Теперь, когда у вас есть рабочий репозиторий, вы можете выполнить какую-либо работу с кодом и выполнить коммит в апстрим, эффективно используя Git в качестве SVN-клиента. Если вы редактировали один из файлов и закоммитили его, то вы внесли изменение в локальный Git-репозиторий, которое пока не существует на Subversion-сервере:
После этого вам надо отправить изменения в апстрим. Обратите внимание, как Git изменяет способ работы с Subversion — вы можете сделать несколько коммитов оффлайн, а затем отправить их разом на Subversion-сервер. Для передачи изменений на Subversion-сервер требуется выполнить команду git svn dcommit :
Это действие возьмёт все коммиты, сделанные поверх того, что есть в SVN-репозитории, выполнит коммит в Subversion для каждого из них, а затем перепишет ваш локальный коммит в Git’е, чтобы добавить к нему уникальный идентификатор. Это важно, поскольку это означает, что изменятся все SHA-1 контрольные суммы ваших коммитов. В частности и поэтому работать с одним и тем же проектом одновременно и через Git, и через Subversion — это плохая идея. Взглянув на последний коммит, вы увидите, что добавился новый git-svn-id :
Получение новых изменений
Если вы работаете вместе с другими разработчиками, значит, когда-нибудь вам придётся столкнуться с ситуацией, когда кто-то из вас отправит изменения на сервер, а другой, в свою очередь, будет пытаться отправить свои изменения, конфликтующие с первыми. Это изменение не будет принято до тех пор, пока вы не сольёте себе чужую работу. В git svn эта ситуация выглядит следующим образом:
Теперь все ваши изменения находятся сверху того, что есть на SVN-сервере, так что вы можете спокойно выполнить dcommit :
Следует помнить, что в отличие от Git’а, который требует сливать себе изменения в апстриме, которых у вас ещё нет локально, перед тем как отправить свои изменения, git svn заставляет делать такое только в случае конфликта правок. Если кто-либо внесёт изменения в один файл, а вы внесёте изменения в другой, команда dcommit сработает без ошибок:
Это важно помнить, поскольку последствием этих действий может стать такое состояние проекта, которого нет ни на одном из ваших компьютеров. Если изменения несовместимы, но не ведут к конфликту изменений, у вас могут возникнуть проблемы, которые трудно будет диагностировать. Это отличается от работы с Git-сервером — в Git’е вы можете полностью проверить состояние проекта на клиентских машинах до публикации, в то время как в SVN вы не можете даже быть уверены в том, что состояние проекта непосредственно перед коммитом и после него идентично.
Кроме того, вам нужно выполнить следующую команду для получения изменений с сервера Subversion, даже если вы не готовы сами сделать коммит. Вы можете выполнить git svn fetch для получения новых данных, но git svn rebase и извлечёт новые данные с сервера, и обновит ваши локальные коммиты.
Проблемы с ветвлением в Git
Выполнение dcommit для ветки с объединённой историей не вызовет никаких проблем. Однако, если вы посмотрите на историю проекта в Git’е, то увидите, что ни один из коммитов, которые вы сделали в ветке experiment не были переписаны — вместо этого, все эти изменения появятся в SVN версии как один объединённый коммит.
Когда кто-нибудь склонирует себе эту работу, всё, что он увидит — это коммит, в котором все изменения слиты воедино; он не увидит данных о том, откуда они взялись и когда они были внесены.
Ветвление в Subversion
Создание новой ветки в SVN
Для того чтобы создать новую ветку в Subversion, выполните git svn branch [имя ветки] :
Переключение активных веток
Команды Subversion
Набор утилит git svn предоставляет в ваше распоряжение несколько команд для облегчения перехода на Git, путём предоставления функциональности, подобной той, которую вы имеете в Subversion. Ниже приведены несколько команд, которые дают вам то, что вы имели в Subversion.
Просмотр истории в стиле SVN
SVN-Аннотации
Опять же, эта команда не показывает коммиты, которые вы сделали локально в Git’е или те, которые за то время были отправлены на Subversion-сервер.
Информация о SVN-сервере
Игнорирование того, что игнорирует Subversion
Заключение по Git-Svn
Утилиты git svn полезны в том случае, если ваша разработка по каким-то причинам требует наличия рабочего Subversion-сервера. Однако, вам стоит смотреть на Git, использующий мост в Subversion, как на урезанную версию Git’а. В противном случае вы столкнётесь с проблемами в преобразованиях, которые могут сбить с толку вас и ваших коллег. Чтобы избежать неприятностей, старайтесь следовать следующим рекомендациям:
При следовании этим правилам, работа с Subversion-сервером может быть более-менее сносной. Однако, если возможен перенос проекта на реальный Git-сервер, преимущества от этого перехода дадут вашему проекту намного больше.
История систем управления версиями
В этой статье сравним с технической точки зрения самые известные системы управления версиями (в будущем планируем расширить список):
В VCS второго поколения появилась поддержка сети, что привело к централизованным хранилищам с «официальными» версиями проектов. Это был значительный прогресс, поскольку несколько пользователей могли одновременно работать с кодом, делая коммиты в один и тот же центральный репозиторий. Однако для коммитов требовался доступ к сети.
Третье поколение состоит из распределённых VCS, где все копии репозитория считаются равными, нет центрального репозитория. Это открывает путь для коммитов, ветвей и слияний, которые создаются локально без доступа к сети и перемещаются в другие репозитории по мере необходимости.
Хронология выхода VCS
Для контекста, вот график c датами появления этих инструментов:
SCCS (Source Code Control System): первое поколение
SCCS считается одной из первых успешных систем управления версиями. Она была разработана в 1972 году Марком Рочкиндом из Bell Labs. Система написана на C и создана для отслеживания версий исходного файла. Кроме того, она значительно облегчила поиск источников ошибок в программе. Базовая архитектура и синтаксис SCCS позволяют понять корни современных инструментов VCS.
Архитектура
Как и большинство современных систем, в SCCS есть набор команд для работы с версиями файлов:
Поскольку содержимое исходного файла теперь хранится в файле истории, его можно извлечь в рабочий каталог для просмотра, компиляции или редактирования. В файл истории можно внести изменения, такие как добавления строк, изменения и удаления, что увеличивает его номер версии.
Важно отметить, что все файлы отслеживаются и регистрируются отдельно. Невозможно проверить изменения в нескольких файлах в виде одного атомарного блока, как коммиты в Git. У каждого отслеживаемого файла свой файл истории, в котором хранится его история изменений. В общем случае это означает, что номера версий различных файлов в проекте обычно не совпадают друг с другом. Однако эти версии можно согласовать путём одновременного редактирования всех файлов в проекте (даже не внося в них реальные изменения) и одновременного добавления всех файлов. Это одновременно увеличит номер версии для всех файлов, сохраняя их согласованность, но обратите внимание, что это не то же самое, что включение нескольких файлов в один коммит, как в Git. В SCCS происходит индивидуальное добавление в каждый файл истории, в отличие от одного большого коммита, включающего все изменения сразу.
Когда файл извлекается для редактирования в SCCS, на него ставится блокировка, так что его никто больше не может редактировать. Это предотвращает перезапись изменений другими пользователями, но также ограничивает разработку, потому что в каждый момент времени только один пользователь может работать с данным файлом.
SCCS поддерживает ветви, которые хранят последовательности изменений в определённом файле. Можно произвести слияние ветви с исходной версией или с другой веткой.
Основные команды
Ниже приведён список наиболее распространенных команд SCCS.
Пример файла истории SCCS
RCS (Revision Control System): первое поколение
RCS написана в 1982 году Уолтером Тихи на языке С в качестве альтернативы системе SCCS, которая в то время не была опенсорсной.
Архитектура
У RCS много общего со своим предшественником, в том числе:
В SCCS иначе: там извлечение любой версии занимает одинаково времени. Кроме того, в файлах истории RCS не хранится контрольная сумма, поэтому нельзя обеспечить целостность файла.
Основные команды
Ниже список наиболее распространённых команд RCS:
Пример файла истории RCS
CVS (Concurrent Versions System): второе поколение
CVS создана Диком Груном в 1986 году с целью добавить в систему управления версиями поддержку сети. Она также написана на C и знаменует собой рождение второго поколения инструментов VCS, благодаря которым географически рассредоточенные команды разработчиков получили возможность работать над проектами вместе.
Архитектура
Разработчик получает копию модуля, который копируется в рабочий каталог на его локальном компьютере. В этом процессе никакие файлы не блокируются, так что нет ограничения на количество разработчиков, которые могут одновременно работать с модулем. Разработчики могут изменять свои файлы и по мере необходимости фиксировать изменения (делать коммит). Если разработчик фиксирует изменение, другие разработчики должны обновить свои рабочие копии с помощью (обычно) автоматизированного процесса слияния перед фиксацией своих изменений. Иногда приходится вручную разрешать конфликты слияния, прежде чем выполнить коммит. CVS также предоставляет возможность создавать и объединять ветви.
Основные команды
Пример файла истории CVS
SVN (Subversion): второе поколение
Subversion создана в 2000 году компанией Collabnet Inc., а в настоящее время поддерживается Apache Software Foundation. Система написана на C и разработана как более надёжное централизованное решение, чем CVS.
Архитектура
Как и CVS, Subversion использует модель централизованного репозитория. Удалённым пользователям требуется сетевое подключение для коммитов в центральный репозиторий.
Subversion представила функциональность атомарных коммитов с гарантией, что коммит либо полностью успешен, либо полностью отменяется в случае проблемы. В CVS при неполадке посреди коммита (например, из-за сбоя сети) репозиторий мог остаться в повреждённом и несогласованном состоянии. Кроме того, коммит или версия в Subversion может включать в себя несколько файлов и директорий. Это важно, потому что позволяет отслеживать наборы связанных изменений вместе как сгруппированный блок, а не отдельно для каждого файла, как в системах прошлого.
В настоящее время Subversion использует файловую систему FSFS (File System atop the File System). Здесь создаётся база данных со структурой файлов и каталогов, которые соответствуют файловой системе хоста. Уникальная особенность FSFS заключается в том, что она предназначена для отслеживания не только файлов и каталогов, но и их версий. Это файловая система с восприятием времени. Кроме того, директории являются полноценными объектами в Subversion. В систему можно коммитить пустые директории, тогда как остальные (даже Git) не замечают их.
Такая система работает только до определёного момента. Хотя дельты экономят место, но если их очень много, то на операции уходит немало времени, так как для воссоздания текущего состояния файла нужно обработать все дельты. По этой причине по умолчанию Subversion сохраняет до 1023 дельт на файл, а потом делает новую полную копию файла. Это обеспечивает хороший баланс хранения и скорости.
SVN не использует обычную систему ветвления и тегов. Обычный шаблон репозитория Subversion содержит три папки в корне:
Основные команды
Пример файла истории SVN
Git: третье поколение
Систему Git разработал в 2005 году Линус Торвальдс (создатель Linux). Она написана в основном на C в сочетании с некоторыми сценариями командной строки. Отличается от VCS по функциям, гибкости и скорости. Торвальдс изначально написал систему для кодовой базы Linux, но со временем её сфера использования расширилась, и сегодня это самая популярная в мире система управлениями версиями.
Архитектура
Git является распределённой системой. Центрального репозитория не существует: все копии создаются равными, что резко отличается от VCS второго поколения, где работа основана на добавлении и извлечении файлов из центрального репозитория. Это означает, что разработчики могут обмениваться изменениями друг с другом непосредственно перед объединением своих изменений в официальную ветвь.
Кроме того, разработчики могут вносить свои изменения в локальную копию репозитория без ведома других репозиториев. Это допускает коммиты без подключения к сети или интернету. Разработчики могут работать локально в автономном режиме, пока не будут готовы поделиться своей работой с другими. В этот момент изменения отправляются в другие репозитории для проверки, тестирования или развёртывания.
Когда ветви перемещаются в удалённые хранилища или извлекаются из них, по сети передаются эти пакетные файлы. При вытягивании или извлечении ветвей файлы пакета распаковываются для создания свободных объектов в репозитории объектов.
Основные команды
Пример блоба, дерева и коммита Git
Блоб с хэшем 37d4e6c5c48ba0d245164c4e10d5f41140cab980 :
Объект дерева с хэшем b769f35b07fbe0076dcfc36fd80c121d747ccc04 :
Коммит с хэшем dc512627287a61f6111705151f4e53f204fbda9b :
Mercurial: третье поколение
Mercurial создан в 2005 году Мэттом Макколлом и написан на Python. Он тоже разработан для хостинга кодовой базы Linux, но для этой задачи в итоге выбрали Git. Это вторая по популярности система управления версиями, хотя она используется гораздо реже.
Архитектура
Mercurial — тоже распределённая система, которая позволяет любому числу разработчиков работать со своей копией проекта независимо от других. Mercurial использует многие из тех же технологий, что и Git, в том числе сжатие и хэширование SHA-1, но делает это иначе.
Наконец, Mercurial использует ещё один тип revlog, который называется changelog, то есть журнал изменений. Это список записей, которые связывают каждый коммит со следующей информацией:
Основные команды
Пример файлов Mercurial
Журнал изменений (changelog):
Дополнительная информация об устройстве Mercurial:



