Git as Subversion

в 10:38, , рубрики: Git, scm, subversion, svn, Блог компании Mail.Ru Group, велосипед, Системы управления версиями

Git as SubversionНекоторое время назад при старте нового проекта было решено попробовать использовать Git вместо Subversion. Через некоторое время коллектив разделился на тех, кто любит Git (программисты), и тех, кто его ненавидит (дизайнеры и художники). Эксперимент по замене Subversion на Git провалился и на горизонте замаячила перспектива возвращения Subversion.

Почесав репу и содрогнувшись от связанных с Subversion воспоминаний мужики решили: «А что, мы же программисты!» и запилили свой Subversion с Git-ом и печеньками. Так родился проект git-as-svn.

Теперь мы можем использовать и Git, и Subversion с одним и тем же репозиторием. Причем доступ через Subversion напрямую использует данные Git-репозитория, в отличие, скажем, от SubGit, где для Subversion используется отдельный репозиторий.

Зачем понадобился еще один велосипед?

Справедливости ради надо отметить, что оба лагеря были по-своему правы. В пользу Git можно сказать следующее:

  1. У Git-а можно делать по ветке на задачу и спокойно коммитить промежуточные результаты без риска все разломать.
  2. Git, по сравнению с Subversion, нереально быстрый.

Против Git:

  1. Более высокий порог вхождения:
    • Git объективно сложнее, чем Subversion;
    • TortoiseGit далеко не такой удобный как TortoiseSvn;
    • многие вещи надо делать через консоль;
    • много больше способов отстрелить себе ногу.
  2. У Git не очень хорошо с клиентами под Windows.
  3. Для работы в Subversion-стиле (обновил → поработал → залил → поработал → залил...) нужно много больше телодвижений.
  4. Нет разделения прав внутри репозитория.
  5. При большом количестве постоянно заливающего народу, люди начинают биться головами (между pull и push успевает кто-то вклиниться).

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

Когда стало ясно, что эксперимент по замене Subversion на Git провалился, начали поиск решения из сложившейся ситуации. В процессе поиска были обнаружены:

  • Поддержка Subversion на GitHub.
    Можно приобрести в комплекте с GitHub Enterprise за сотни нефти.
  • Стремный проект SubGit.
    SubGit пытается через хуки поддерживать в синхронном состоянии Git и Subversion репозитории. Это архитектурное решение выглядит очень шатким, хотя, надо отметить, что реализация кажется рабочей.
  • Люто тормозящая python-реализация Subversion-фронтэнда для Git-репозитория.
    Самое главное в этом проекте — его небольшой объем. После этого задача реализации Subversion-фронтенда для Git-репозитория стала казаться просто безумной, а не абсолютно безумной, как было ранее. :)

Что это и как оно работает

Данный проект представляет собой реализацию Subversion-фронтэнда для Git-репозитория. Он позволяет работать с репозиторием при помощи, как минимум:

  • консольного Subversion-клиента;
  • TortoiseSVN;
  • SvnKit.

На данный момент поддерживается:

  • svn checkout, update, switch, diff
  • svn commit (!)
  • svn log
  • svn cat, ls
  • svn replay (svnsync)
  • partial checkout
  • sparse working copy (svn --depth/--set-depth)
  • git submodules
  • аутентификация через LDAP

По производительности работа не просто сопоставима, но местами даже превосходит родной Subversion-сервер.

Как работает коммит?

Одна из самых важных деталей системы — сохранение изменений. В общих чертах, идея следующая:

  1. В момент команды svn commit клиент отправляет на сервер свои изменения. Сервер при этом запоминает их. В этот же момент происходит первая проверка на актуальность клиентских данных.
  2. Сервер берет голову ветки и начинает формировать новый коммит на базе полученных от клиента данных. В этот момент происходит ещё одна проверка на актуальность клиентских данных.
  3. Проверяется целостность svn properties для заливаемых данных.
  4. Сервер пытается консольным Git-клиентом сделать push нового коммита в текущую ветку этого же репозитория. Далее по результату push-а:
    — если все хорошо — загружаем последние изменения из git-коммитов и радуемся;
    — если не fast forward — загружаем последние изменения из git-коммитов и идём к шагу 2;
    — если отбили хуки — сообщаем клиенту;
    — если другая ошибка — сообщаем клиенту.

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

Где хранятся svn-данные репозитория?

Для представления Subversion репозитория нужен ряд данных, которые в Git либо отсутствуют (например, данные о том, откуда скопирован файл), либо очень дорого получить (например, номер ревизии, когда файл менялся в последний раз). Чтобы не заниматься их расчетом каждый запуск, они кэшируются в ветках refs/git-as-svn/*. Этот же кэш позволяет не ломаться соответствии Git-коммитов Subversion-ревизиям из-за операций force push. ;-)

Известные проблемы и ограничения

На данный момент приходится мириться со следующими ограничениями:

  1. нельзя средствами Subversion менять svn properties;
  2. не сохраняется история копирования файлов.

Svn properties

Основная беда svn properties в том, что некоторые свойства надо поддерживать в синхронном состоянии между Git и Subversion. Чтобы эти данные не расходились, svn properties генерируются на базе содержимого файлов из Git-репозитория (например, svn:ignore генерируется на основании .gitignore). При коммите же происходит проверка сохраняемых свойств данным репозитория. Это накладывает важное ограничение: нужно корректно формировать svn:auto-props, иначе при добавлении файлов пользователю придётся приводить их руками к виду, который ожидает сервер.

Самое злобное свойство: svn:eol-style. Основная беда в том, что поведение Git-а по умолчанию в контексте eol-ов сломано и соответствует файлу .gitattributes с содержимым:

* text=auto eol=native 

То есть, с настройками по-умолчанию Git меняет содержимое текстовых файлов.

После долгих страданий было найдено решение проблемы eol-ов: в корень Git-репозитория нужно добавить файл .gitattributes, начинающийся со строки:

* -text

Это потребует от Git не трогать окончания строк у файлов до тех пор, пока его об этом явно не попросят.

И что в итоге?

На данный момент проект находится в неторопливой разработке и эксплуатируется в одной из команд Mail.Ru Group. В результате, люди вольны использовать подходящий для их нужд инструмент: дизайнеры используют TortoiseSvn и заливают им изменения напрямую в master, а программисты пользуются Git-ом и живут в своих уютненьких веточках. Обстановка в целом стала здоровее, и у коллег перестали сжимать кулаки, когда кто-то рядом произносит слова Git или Subversion.

Что нужно сделать, чтобы потыкать в проект палочкой?

Чтобы запустить git-as-svn нужно:

  1. Установить Java 8.
  2. Скачать последнюю сборку с github.com/bozaro/git-as-svn/releases/latest.
  3. Распаковать архив.
  4. Запустить сервер.
    java -jar git-as-svn.jar --config config.example --show-config

В результате будет создан Git репозиторий с одним тестовым коммитом, доступный по URL svn://localhost/example/ из под пользователя test с паролем test. В качестве клиента настоятельно рекомендуется использовать клиент для Subversion 1.8+.

Автор: Bozaro

Источник

Поделиться

* - обязательные к заполнению поля