Пользователь
0,0
рейтинг
27 мая 2012 в 18:10

Разработка → Переезд проекта с SVN на Git

image
Много лет подряд в качестве системы контроля версий для большого количества проектов использовали только SVN. Но наступил момент, когда количество разработчиков на одном из проектов заметно увеличилось, проект уже запущен в работу, и нужно как активно разрабатывать параллельно несколько фич, так и фиксить уже имеющиеся баги в оперативном режиме. Единый trunk в SVN не позволяет этого делать, а организация бранчей в нем же превращает жизнь разработчиков в ад. Поэтому было принято решение о переезде этого проекта с SVN на Git.

1. Сервер для центрального репозитория


Несмотря на то, что Git — система распределенная, это не отменяет необходимости наличия центрального репозитория, с которым в конечном итоге будут сихронизироваться все разработчики, а также с которого будут разворачиваться как тестовые сборки, так и будет производиться деплой на production. Поэтому нам необходим в первую очередь сервер. Поскольку проект коммерческий, то хранить исходники на чужих серверах как-то не очень хотелось, значит надо поднять свой сервер для хранения git-репозиториев. Сам сервер работает на Gentoo, поэтому нам нужно поставить на него весь необходимый софт.

Здесь выбор особо не велик — gitosis либо gitolite. Поскольку gitosis уже не разрабатывается несколько лет как, то выбор пал на gitolite.

1.1. Установка gitolite

Ставим gitolite 3.03 на сервер:
$ emerge gitolite

При этом создается пользователь git, который и будет владеть всеми будущими репозиториями.

1.2. Первичная настройка

Теперь нам нужно сгенерировать rsa-ключ для доступа к админскому репозиторию (gitolite хранит все настройки в git-репозитории) и сохранить публичный ключ в общедоступном месте:
$ ssh-keygen -t rsa
$ cp ~/.ssh/id_rsa.pub /tmp/admin.pub

После этого можно собственно инициализировать gitolite:
$ su git
$ cd
$ mkdir -p bin
$ gitolite/install -ln
$ gitolite setup -pk /tmp/admin.pub

1.3. Создание репозитория для проекта

Сервер установлен, возвращаемся в своего пользователя и клонируем себе репозиторий с конфигами:
$ cd
$ git clone git@server:gitolite-admin.git

Здесь и далее server — это hostname сервера, на котором установлен gitolite и хранятся репозитории.

Открываем появившийся файл gitolite-admin/conf/gitolite.conf и добавляем в конец описание репозитория для нашего проекта (пока только с одним пользователем):
repo project
    RW+          = javer

После этого сохраняем наши изменения. Находясь в gitolite-admin, выполняем:
$ git add .
$ git commit -am "Repository for project added"
$ git push origin master

gitolite автоматически проинициализирует все репозитории, которые описаны в конфиге и еще не существуют.

Все, gitolite установлен и первично настроен, репозиторий для нашего проекта создан, можно двигаться дальше.

2. Импорт проекта из SVN


Непосредственно преобразование SVN-репозитория в Git осуществляется с помощью команды
$ git svn clone

Для этого git должен быть собран с поддержкой perl.

2.1. Определение стартовой ревизии

Наш проект Project находится в SVN репозитории наряду с множеством других проектов. Поскольку номера ревизий сквозные на весь репозиторий, то находим в svn log первый коммит, который касается именно нашего проекта, и запоминаем. Это нужно для ускорения импорта, чтобы не сканировались все ревизии, начиная с первой. В нашем случае это ревизия 19815, поэтому к команде выше добавляется опция:
-r19815:HEAD

2.2. Соответствие SVN-пользователей с Git-пользователями

Далее нам необходимо составить соответствие SVN-пользователей с будущими Git-пользователями, чтобы они при импорте успешно заменились. Для этого где-нибудь создаем файл authors примерно такого содержания:
javer = javer <javer@domain.tld>
developer1 = developer1 <developer1@domain.tld>
...

Где user@domain.tld — это e-mail git-пользователя (в git-е каждый пользователь идентифицируется именем и электропочтой).

Соответственно, к команде импорта добавляется опция:
--authors-file=/path/to/authors

2.3. Исключение ненужных файлов

Едем дальше. В нашем проекте были случайные коммиты больших бинарных файлов, которые в новом репозитории нам не нужны. При импорте их можно исключить опцией:
--ignore-paths="\.(avi|mov)$"

2.4. Дополнительные опции

Также нам нужен пользователь в SVN, от имени которого будет производиться доступ к репозиторию:
--username javer

Добавляем еще опцию --no-metadata, которая нужна для того, чтобы в логе коммитов в каждом комментарии не было добавлений вида:
git-svn-id: svn://svn.domain.tld/repo/project/trunk@19815 e13dc095-444b-fa4e-8f24-06838a8318a5

В SVN-репозитории нашего проекта полезная информация хранилась только в trunk, немногочисленные бранчи содержали временный код, который в свое время путем невероятных усилий все-таки был смержен с trunk-ом, поэтому более они нам не нужны.

2.5. Клонирование проекта из SVN-репозитория

Собираем все вместе и запускаем:
$ cd
$ mkdir project && cd project
$ git svn clone -r19815:HEAD --authors-file=/path/to/authors --ignore-paths="\.(avi|mov)$" --username javer --no-metadata svn://svn.domain.tld/repo/project/trunk .

Где svn://svn.domain.tld/repo/project/trunk — адрес trunk-а нашего проекта в SVN-репозитории.

Начинается процесс клонирования, длительность которого зависит от количества коммитов и их объема. В нашем случае было около 4.5 тыс. коммитов, и на их клонирование понадобилось около двух часов.

2.6. Исключение более ненужных файлов и каталогов

По завершении клонирования в нашем каталоге project мы получаем полный клон проекта со всей историей коммитов. После клонирования может внезапно обнаружиться, что мы склонировали также какой-то каталог, который в новом репозитории нам не нужен, например, потому что мы выделим его в отдельный репозиторий. Удалить каталог и все упоминания о нем в истории можно так:
$ git filter-branch --tree-filter 'rm -rf unneeded_directory' -f HEAD

Этот процесс также достаточно длительный, поскольку пересматривается каждый коммит в отдельности, и в нашем случае это занимало около 1 секунды на каждый коммит.

2.7. Удаление пустых коммитов

В результате всех предыдущих действий мы получили наш склонированный проект со всей историей коммитов, среди которых теперь имеются пустые коммиты, то есть коммиты без единого измененного файла. Они появились в результате исключения некоторых файлов через опцию ignore-paths, либо же из-за последующей фильтрации через tree-filter. Для удаления таких пустых коммитов делаем:
$ git filter-branch --commit-filter 'git_commit_non_empty_tree "$@"' HEAD

Эта операция занимает примерно столько же времени, как и tree-filter.

2.8. Пустые каталоги и svn:ignore

Далее, нам необходимо сконвертировать бывшие svn:ignore в новые .gitignore. Это делается так:
$ git svn create-ignore

Не забываем, что git не хранит информацию о каталогах, только о файлах, поэтому во всех пустых каталогах нужно создать пустой файл .gitignore, после чего закоммитить все эти файлы:
$ git add .
$ git commit -am "Added .gitignore"

2.9. Удаление упоминания об SVN

Поскольку наш проект переезжает с SVN на Git окончательно, то удаляем всяческие упоминания об SVN:
$ git branch -rd git-svn
$ git config --remove-section svn-remote.svn
$ git config --remove-section svn
$ rm -rf .git/svn

2.10. svn:externals

В нашем проекте некоторые symfony-плагины, как кастомные, так и публичные, были подключены через svn:externals. Поскольку в git такой механизм отсутствует, будем использовать submodules для этого. С публичными плагинами проще:
$ git submodule add git://github.com/propelorm/sfPropelORMPlugin.git plugins/sfPropelORMPlugin
$ git submodule add git://github.com/n1k0/npAssetsOptimizerPlugin.git plugins/npAssetsOptimizerPlugin

Со своими плагинами чуть сложнее — для них нужно создать отдельные репозитории аналогично описанному выше, после чего точно также подключить к нашему проекту:
$ git submodule add git@server:customPlugin.git plugins/customPlugin

После подключения submodules их необходимо склонировать в каталог проекта:
$ git submodule update --init --recursive
$ git commit -am "Added submodules: sfPropelORMPlugin, npAssetsOptimizerPlugin, customPlugin"

2.11. Отправка локальной копии проекта на сервер

Перед отправкой нашего проекта на сервер для ускорения этой операции оптимизируем его:
$ git gc

Подключаем к проекту наш новый репозиторий:
$ git remote add origin git@server:project.git

И, наконец, заливаем локальную копию проекта на сервер:
$ git push origin master

2.12. Обновление submodules в будущем

Поскольку в отличие от svn:externals каждый submodule указывает на конкретный коммит, то при простом обновлении локальной копии через
$ git pull

содержимое submodules обновляться не будет. Их обновление производится следующим образом:
$ git submodule update

В случае, если были изменения:
$ git submodule foreach git pull
$ git commit -am "Updated submodules"


3. Настройка прав доступа к репозиторию


3.1. Пользовательские ключи

Поскольку доступ к удаленному git-репозиторию осуществляется через ssh, то теперь каждый разработчик должен сгенерировать на своей машине rsa-ключ.

3.1.1. Linux/Unix

В случае Linux/Unix или Git bash под Windows это делается так:
$ ssh-keygen -t rsa

После чего полученный публичный ключ ~/.ssh/id_rsa.pub передается админу репозитория.

3.1.2. Windows

В случае Windows также можно воспользоваться puttygen, который можно скачать здесь: puttygen.

Запускаем puttygen, нажимаем Generate, возим мышкой по окну, пока ключ не будет сгенерирован, потом в поле комментария указываем к чему этот ключ, вводим пароль доступа к ключу при необходимости. После этого копируем содержимое поля Public key, сохраняем в файл user.pub и передаем админу репозитория.

Потом нажимаем Save private key и сохраняем этот ключ в укромном месте для дальнейшего в использования, например, в TortoiseGit.

Также в меню Conversions выбираем пункт Export OpenSSH key и сохраняем его в файл под названием C:\Users\USERNAME\.ssh\id_rsa, где USERNAME — имя вашего пользователя в системе. Этот ключ нам будет нужен при использовании git из командной строки.

3.2. Настройка прав доступа

Полученные на предыдущем шаге публичные ключи пользователей помещаем в админский репозиторий в каталог ~/gitolite-admin/keydir/ в файлы с названиями USERNAME.pub, где USERNAME — имя пользователя.

Поскольку gitolite имеет достаточно широкие возможности по настройке, используем их для настройки прав доступа к репозиторию нашего проекта. Для этого редактируем файл ~/gitolite-admin/conf/gitolite.conf и приводим его к виду:

@owners = javer
@project_developers = user1 user2 user3
@deploy = root@production

repo project
- master$ = @project_developers
- refs/tags = @project_developers
RW+ = @project_developers @owners
R = @deploy

Этим мы даем полный доступ для группы пользователей owners. Для группы project_developers — также полный доступ с возможностью создания своих веток, за исключением записи в ветку master и создания тегов. Для группы deploy, которая используется для деплоя на продакшн, разрешаем доступ только для чтения.

В конце не забываем сохранить все изменения:
$ git add .
$ git commit -am "New users for project: user1, user2, user3..."
$ git push origin master


4. Установка и настройка на машинах разработчиков


Серверная часть полностью готова, теперь остается установить и настроить git-клиент на машинах разработчиков.

4.1. Linux/Unix


Тут все просто — устанавливаем git с помощью своего любимого менеджера пакетов.

После установки не забываем указать свое имя и e-mail, такие же, которые использовались при импорте из SVN:
$ git config --global user.name "javer"
$ git config --global user.email "user@domain.tld"

4.2. Windows


Здесь существует несколько различных клиентов, я пока остановился на TortoiseGit.

Перед его установкой сначала нужно установить msysgit, желательно самой последней версии, несмотря на надпись Beta. Во время установки на вопрос об интеграции в систему я советую выбирать пункт Git Bash and Command prompt, чтобы можно было запускать git как из Git bash, так и с командной строки.

После этого устаналиваем сам TortoiseGit. Я советую устанавливать последнюю стабильную версию, но не nightly-build.

Теперь заходим в настройки TortoiseGit (правой клик по любому каталогу и TortoiseGit->Settings), находим там раздел Git и справа в блоке User Info вписываем свои имя и e-mail.

5. Переезд завершен. Приступаем к работе


Все, на этом процедура переезда с SVN на Git завершена.

Каждый разработчик клонирует себе на машину проект и начинает с ним работать.

Я бы посоветовал разработчикам ознакомиться с этими статьями:
Вадим Бородавко @Javer
карма
57,0
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (51)

  • 0
    А Github или Bitbucket в качестве сервера почему не захотели использовать?
    • +9
      Потому что в будущем планируем постепенно все проекты переводить на git, а у нас их порядка сотни. Плюс у каждого еще свои svn:externals, которые тоже превращаются в отдельные репы. При таком количестве репозиториев стоимость размещения на стороне растет экспоненциально. К тому же локальный сервер для разработки все равно есть, зачем ему простаивать.
      • +4
        почему не рассматривали mercurial?
        • 0
          Рассматривали, но каких-то значительных преимуществ против git для нас не нашли. А поскольку большая часть разработчиков так или иначе уже имела дело с гитом раньше, то выбор стал очевиден.
      • 0
        Стоимость размещения на bitbucket зависит от размера команды, кол-во репозиториев и место неограничено. Просто для информации, ваш выбор не критикую.
  • +2
    А разве tmp не очищается при перезагрузке? В любом случае, как-то неправильно в tmp хранить то, что постоянно нужно.
    • 0
      Для таких данных есть каталог /var
    • +1
      В том-то и дело, что этот ключ по тому пути больше не нужен. При запуске gitolite setup он этот ключ перекладывает себе в keydir/. Поэтому сразу после setup этот файл вообще можно удалить.
      • +1
        А зачем тогда «сохранить публичный ключ в общедоступном месте»?
        • +2
          Имелось ввиду временно сохранить по короткому пути, чтоб потом набирать меньше букв и чтобы gitolite смог его прочитать.
          • 0
            Вы же gitolite запускаете от того же пользователя, от которого создаете файл. Это в большинстве случаев гарантирует, что он сможет прочитать этот файл.

            Между фразами «в общедоступном месте» и «чтобы gitolite смог его прочитать» есть большая разница. Лучше в статье поправьте, а то получается совсем не тот смысл, который вы имели в виду.
  • –2
    А что насчет AD в gitolite?
    • +1
      Только ключи, если использовать gitolite второй версии. В третьей версии система модульная, можно взглянуть на документ sitaramc.github.com/gitolite/http.html. Просто стандартный метод аутентикации — ssh. При использовании smart http она перекладывается на веб-сервер, который может взаимодействовать с чем угодно для аутентикации пользователей.

      Резюмируя, gitolite не занимается аутентикацией, но только авторизаций: sitaramc.github.com/gitolite/auth.html.
  • +1
    Ставим gitolite 3.03 на сервер:
    $ emerge gitolite


    Понт засчитан!

    А вообще огромное спасибо за статью! В свое время долго промучился с настройкой gitosis (под тем-же дистрибутивом), а точнее с интеграцией его с redmine.
    Этой статьей вы мне не только открыли глаза на мою проблему с устаревшим gitosis, но и дали простое решение.

    Если не секрет, какой багтрекер интегрировали с gitolite и насколько это трудно?
    • +3
      Не автор статьи, но отвечу.

      Мы интегрировали redmine. Начиная с версии 0.9 и до текущей 1.4 все работает прекрасно. Из особенностей:
      • репозитории должны располагаться на одном сервере с redmine (либо можно клонировать на него специальных хуком при пуше)
      • у сервера, который будет запускать redmine должны быть права на доступ к директории с репозиториями
      • для удобства желательно добавить в репозитории хук, который будет сообщать redmine об изменениях (иначе redmine прийдется постоянно обращаться к репозиториям)


      В качестве сервера для запуска использовали fastcgi-обертку в lighttpd и redmine/public/dispatch.fcgi.

      Если будет интересно и на хабре это не описано, могу написать статью об этом.
    • +1
      Используем Redmine. Он с коробки поддерживает Git, репозиторий подключался по инструкции: www.redmine.org/projects/redmine/wiki/RedmineRepositories#Setting-up-a-mirror-repository-shortcut-tracking-branches

      Обновление локальной копии и подтягивание в redmine производится по крону с некоторой периодичностью, пока этого хватает.
      • +3
        Можно использовать post-recieve/post-update хук такого вида:

        #!/bin/bash
        
        REDMINE_KEY=
        REDMINE_SERVER=
        
        curl http://${REDMINE_SERVER}/sys/fetch_changesets?key=${REDMINE_KEY}
        


        Для этого, естественно, необходимо сгенерировать ключ и разрешить работу веб-сервиса управления хранилищами в настройках redmine.
    • +2
      Кстати, рекомендую заодно с gitolite посмотреть gitlabhq.
  • +4
    Хотелось бы добавить, что для сохранения директорий обычно в листовых создают .gitkeep, а не .gitignore, последний обычно используется по прямому назначению.

    Также стоит упомянуть, что gitolite 3 ещё относительно сырой, Sitaram Chamarty его недавно выложил в публичный доступ. С другой стороны, поломать что-либо там довольно сложно, т. к. вся конфигурация и сами репозитории хранятся, как нормальные bare-repo.
    • +1
      Популяризации такого использования .gitignore способствует github:

      Sometimes an empty .gitignore file is used as a placeholder for an empty path, for example to force git to generate a log/ path for your development environment to use.
      ©github:help
      • +3
        Использование .gitkeep, как и .gitignore с этой целью — конвенции. Лично я предпочитаю использовать .gitignore по его прямому предназначению.

        На эту тему можно глянуть stackoverflow.com/questions/7229885/gitignore-vs-gitkeep
  • +1
    В литературу можно добавить ещё Git Book: git-scm.com/book
  • +1
    Скажите, пожалуйста, какие преимущества может дать Git в плане merge'a функционала в основную ветку? Ведь как в SVN нужно разгребать конфликты после каждого merge'a (если они есть), зато эти конфликты видны сразу; так и в Git при push'e могут возникнуть конфликты, только в этом случае вы заливаете не маленькое изменение (как в SVN), а целую фичу. И не факт, что после этого push'a и исправления конфликтов предыдущая функциональность не разъедется…
    • 0
      После ручного мержа — тоже не факт. Тестирование никто не отменял.
      • +1
        Я и не спорю, просто вопрос возник после прочтения первого абзаца. Вот и хочу узнать, чем так хорош Git в плане merge'a кучи фич в одну ветку.
    • +1
      Ключевая разница в том, что в SVN, чтобы проверить работоспособность фичи в ветке в последних актуальных условиях (голова транка), нужно либо замержить ветку в транк, что в нашем случае не вариант, либо замержить транк в ветку, проверить работоспособность, после чего слияние с транком будет _очень_ болезненным, потому что теперь все изменения транка с момента создания ветки будут самостоятельными изменениями ветки, и в момент слияния ветки фичи с транком мы получим целую кучу конфликтов, потому что одни и те же файлы в тех же местах одновременно менялись и в ветке, и в транке.
      • 0
        Согласен, ветка на фичу — не выход из ситуации. Но чем плохо merge'ить в trunk всем разработчикам в процессе выполнения фич?
        • +2
          Объясню на примере. Например, программисту в процессе выполнения задачи нужна верстка какого-то блока. Чтобы передать работу верстальщику, ему нужно закоммитить частично рабочий код (ведь задача не закончена) в транк, чтобы его увидел верстальщик и мог что-то сделать. Внимание! С этого момента в транке находится частично работающий код.
          Верстальщик может быть сейчас занят другой задачей либо выполнение необходимых правок требует значительного времени (дни). Теперь представим ситуацию, что другой программист в это время закончил выполнение задачи, его работа проверена и должна быть вылита на продакшн. Прямо сейчас. Либо же на продакшене был обнаружен критический баг, который требует немедленного исправления. А транк поломан, деплоить нельзя. Что делать?
          • 0
            1) Как на вашем примере поможет Git? Программист зальет частично работающий код… куда? В копию репозитория верстальщика? Это возможно?
            2) Что делать? Заливать в trunk закомментаренный код. Верстальщик его раскомментарит, поработает. Когда закончит, зальет в trunk. Гемор, согласен. Возможно, ваш ответ на первый пункт прояснит ситуацию, как сделать без этого гемора.
            • +2
              1. Программист коммитит в свою ветку, пушит на сервер, верстальщик подключает себе эту ветку, сливает в локальную копию, и теперь они вместе работают в ветке фичи, попеременно коммитят и пушат в эту ветку, не затрагивая транк. Задача может выполняться неделями, ведь они никому не мешают, и одновременно взаимодействуют друг с другом, при этом нет никаких ожиданий и простоев.

              2. Программист внес изменения в 10 файлов, закоммитил в транк, чтобы у верстальщика работал тот функционал, для которого нужно сделать верстку. Добавим сюда, что программист не один, например их десять. Часть взаимодействует друг с другом, часть с верстальщиками. И все они закоммитили частично нерабочий код, чтобы напарник мог сделать свою часть. Теперь нужно срочно исправить баг. Начинать в логе судорожно искать коммиты, которые они сделали, проходить по кругу и делать опрос, у кого что работает, а что нет, поверить на слово не проверив, отменить изменения в сотнях файлов, при этом не ошибившись ни в одной строчке, чтобы внести на продакшн небольшое исправление, чтобы потом снова вернуть все назад? Это очень удобно)
              • 0
                Уже ясней. Тогда такой вопрос: отдельная ветка в SVN не решает проблему первого пункта аналогично Git?
                • +2
                  Решает ровно до тех пор, пока эту ветку не надо будет окончательно тестить и вливать в транк, о чем я уже выше писал. Вот тогда и почувствуется разница между SVN и Git.

                  И, да, к первому пункту я забыл добавить, что если оба разработчика живут под линуксом и у них настроена авторизация на компы друг друга, то возможно прямое подключение между двумя локальными репозиториями, в этом случае один будет удаленной копией для второго, и они могут взаимодействовать полностью локально, без необходимости частого пуша на сервер. И когда фича будет завершена, можно отредактировать историю, объединив, например, 100 коммитов с пустыми комментариями в 10-20 осмысленных, если конечно в этом будет необходимость. Ведь философия Git — коммить как можно чаще, чтобы в любой момент можно было вернуться к предыдущему микросостоянию, ведь именно для этого и нужна система контроля версий.

                  За то недолгое время, как мы переехали на Git и добили раз и навсегда master до рабочего состояния, у меня еще ни разу не возникало мысли «сейчас нельзя задеплоить на продакшн, потому что...». Потому что причины больше нет. В мастере всегда рабочий код. А работа по разработке новых фич кипит пуще прежнего.
                  • 0
                    У нас эта тема тоже обсуждалась и мы пришли вот к какому затыку.
                    Представим, что у нас есть рабочий trunk. Начинается разработка двух новых фич параллельно двумя разработчиками Алисой и Бобом.
                    Допустим Алиса первая закончила свою фичу, заливает ее в trunk, в итоге мы имеем рабочую фичу в trunk'e. Вроде все пока нормально.
                    И тут приходит очередь заливать свой код Бобу. Мало того, что он мог поменять код, который меняла и Алиса, так еще их изменения могут носить ортогональный характер! То есть либо Бобу надо изменять свою логику, либо менять логику кода Алисы. В итоге получаем, что все те разработчики, которые заливают после Алисы, должны разгребать конфликты от предыдущих разработчиков, так еще и заливают они не один маленький участок кода, а целую фичу! Ну протестирует Боб свой код. Как он может быть уверен, что он не сломает код Алисы, когда зальет в trunk?

                    Надеюсь, проблему ясно описал. :)
                    • 0
                      Тут на помощь снова приходят локальные репозитории гита. Разработчик после завершения своей фичи может локально замержить свою ветку в мастер, если в процессе мержа будут проблемы — он сразу об этом узнает. И тут же он проверяет, все ли ок. Если нет — откатывает мерж и правит код, после чего снова мержит. Если код в мастере сильно поменялся за время выполнения задачи — лучше вообще сделать rebase относительно головы мастера, чтобы код гарантированно ничего не сломал после мержа в мастер, но это только если над фичей работает один человек. При этом все эти изменения происходят локально на машине разработчика, он никому не мешает, пока доводит все до ума.
                      В результате всего этого разработчик в конечном итоге коммитит исправление в свою ветку, которое позволяет безболезненно замержить потом его ветку в мастер. Сам разработчик мержить в удаленный мастер не может, это порезано на уровне прав доступа к центральному репозиторию. Для этого есть техлид или другое доверенное лицо, ответственное за то, что будет вылито на продакшн.
                      При этом в истории мастера мы видим чистые мержи фичи1, фичи2 и т.д., без коммитов вида «правка фичи2, чтобы она работала с фичей1».
                      • 0
                        > Тут на помощь снова приходят локальные репозитории гита. Разработчик после завершения своей фичи может локально замержить свою ветку в мастер, если в процессе мержа будут проблемы — он сразу об этом узнает.

                        В меркуриале я бы наоборот мастер замержил в свою ветку. Потом бы протестировал и профиксил баги в результате мержа. И только потом свою ветку безболезненно замержил в мастер. В Гите делается по другому?
                        • 0
                          Нет, всё аналогично. Только смысл иметь два мержа подряд вместо одного? Хотя, в этом плане git лучше — он сделает fast-forward и будет всё равно, кто в кого влился.
                          • +1
                            Если изменения в своей ветке были не большие, то конечно не имеет. Просто если мерж ломает программу, то ее лучше профиксить в своей ветке, чем в мастере. Пусть уж будет лишний коммит в своей ветке (пусть даже не рабочий), но зато в мастере будет только один коммит, причем профиксенный и рабочий.
      • –2
        в SVN, чтобы проверить работоспособность фичи в ветке в последних актуальных условиях (голова транка), нужно либо замержить ветку в транк, что в нашем случае не вариант, либо замержить транк в ветку, проверить работоспособность, после чего слияние с транком будет _очень_ болезненным, потому что теперь все изменения транка с момента создания ветки будут самостоятельными изменениями ветки

        В транк, естественно, мержить не надо. Но не вижу причин не синхронизировать функциональную ветку с транком. Это основной совет как раз для безболезненного слияния с транком.
      • 0
        потому что теперь все изменения транка с момента создания ветки будут самостоятельными изменениями ветки, и в момент слияния ветки фичи с транком мы получим целую кучу конфликтов
        Правильно я понимаю, что SVN просто «не помнит» о том, что он влил транк в ветку, в отличие от Git? Отсюда все дальнейшие проблемы?
        • 0
          Я думаю тут проблема в совокупности факторов. Во-первых, svn действительно не в курсе, что куда вливалось, для него это просто коммит каких-то изменений. Хотя в последних версиях он в комментариях обозначает, до какой ревизии было влито, но видимо это его не спасает. Плюс разница еще и в способах организации данных хранилища и способах мержа.
      • 0
        Использую «svnmerge.py merge -bs» для мержа в SVN между транком и веткой. Работает замечательно в обе стороны. Что я делаю не так?

        www.orcaware.com/svn/wiki/Svnmerge.py
  • 0
    А вот если разработка в SVN продолжается? Грубо говоря форкается SVN проект под GIT. Форкнуть-то не проблема, но вот вот потом подтасиквать изменения из апстрима как? Вернее даже они подтаскиваются (в консоли что-то идёт), но вот заливать на пшерги нечего почему-то. Никак врубиться не могу. С Mercurial подобная схема работает на ура, а вот с гитом видимо какой-то нюанс не уяснил.
    • +1
      Пока апстрим свн-а не отключен, можно все изменения из него подтягивать через git svn rebase, при этом появляются все недостающие коммиты. Правда для этого нужно было делать git svn clone без опции --no-metadata, потому что git svn ищет последнюю подтянутую ревизию в комментариях истории коммитов.
      • 0
        Спасибо, попробую. Опцию не использовал.
      • 0
        Нашёл другой способ. После начального git svn clone, делаю git svn fetch , при этом внезапно (для меня) изменения стягиваются в ветку git-svn, с которой уже работаю как с обычной веткой в частности git merge git-svn.

        Столкнулся правда с тем, что если реп залить на гитхаб, то настройки giit-svn не сохраняются, нужно в клонах гитхабовского репа их ручками вписывать, но при этом всё довольно прозрачно работает.
  • 0
    GitLab не пробовали?
  • 0
    Уже в двух фирмах проводил ту же операцию, использовал:
    1) GitLab для визуализации реп
    2) авторизация по логину/паролю от GitLab, а не ключу
    3) во 2ой конторе GitLab ставился рядом с уже работающим gitolite
  • 0
    Флейм:
    • 0
      Простите, ошибся веткой.
      P.S. shoutout to habra usability :(
  • +1
    Нашел на сайтике способ, как сгенерировать список пользователей
    svn log -q | awk -F '|' '/^r/ {sub("^ ", "", $2); sub(" $", "", $2); print $2" = "$2" <"$2">"}' | sort -u > authors-transform.txt
    

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