Мы хотим перейти с svn на git навсегда, чтобы иметь возможность использовать лучшие функции git с точки зрения ветвления и совместной работы.
Наш текущий репозиторий svn выглядит так
svnrepo/
frontend/
trunk
branches/
ng/
...
tags/
1.x
...
backend/
trunk
branches/
ng/
...
tags/
1.x
...
Рабочий макет состоит в том, что мы проверяем проект внешнего интерфейса, и внутри него мы создаем внутреннюю папку и проверяем внутренний проект.
Теперь мы хотим перейти на git и отказаться от разделения на интерфейс и серверную часть (с точки зрения того, что это отдельные проекты), потому что это дает нам больше проблем, чем преимуществ. Мы хотим, чтобы они оба были в одном репозитории git.
Я хотел использовать svn2git для преобразования. К сожалению, последние разработки произошли в ветке, а не в основной системе, но я думаю, что это не должно быть проблемой для svn2git. Итак, новый макет репозитория git должен выглядеть так:
/ => svnrepo/frontend/branches/ng
/backend => svnrepo/backend/branches/ng
Где => означает «перенесено / преобразовано из».
Для преобразования нам не нужно преобразовывать все теги и ветки из репозитория svn в git. Для нас это не важно. Однако важно то, что у нас есть полная история всех коммитов для всех файлов в каталоге branch / ng, возвращаясь к ветвлению из ствола и всех коммитов, которые произошли в стволе до этого. И мы хотим, чтобы все эти коммиты были с упомянутым макетом в одном репозитории git. Это вообще возможно? И как бы мы это сделали?
Я уже искал в Google, а также в stackoverflow 1,2 но не смог найти точного решения нашей проблемы.
Одним из решений было бы сгенерировать каждый из репозиториев отдельно с помощью svn2git или просто git svn
(это симпатичный маленький инструмент, уже встроенный в git), а затем соедините их вместе с git filter-branch
.
git filter-branch
в этих новых ветвях, используя индексный фильтр, чтобы создать для них новый подкаталог.master
(или любую другую ветку, которую вы хотели) в корневом репозитории. Полная история сохранится.Команда для шага 3 будет выглядеть примерно так:
git filter-branch --index-filter '
git ls-files -s |
perl -pe "s{\t\"?}{$&newsubdir/}" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
' HEAD
Магия, и каждый раз, когда мне приходится это делать, это немного похоже на волшебство, - это perl
заявление. git filter-branch
фильтрует индекс при каждой фиксации и добавление всех путей к BLOB-объектам (т.е. изменение путей к файлам рабочего дерева) с помощью 'newsubdir'. Возможно, вам придется поэкспериментировать, чтобы выбрать правильные пути. Несколько уроков, извлеченных кем-то, кто ходил по этому пути раньше:
git filter-branch
разрушительна история. После того, как вы его измените, вы не сможете легко вернуть его обратно. Обязательно сделайте резервную копию всех копий репозитория, которые вы используете. Нет ничего хуже, чем завершить сложную операцию и обнаружить, что вы пропустили /
в пути.git filter-branch
чрезвычайно интенсивно загружает процессор. Фильтр индекса в глубокой истории может занять несколько часов в вашей локальной среде, но лишь часть этого времени - на AWS. экземпляр вычислительного кластера. Конечно, они стоят чуть больше 2 долларов в час, но вам понадобится всего лишь на несколько часов. Избавьте себя от боли и используйте те сценарии, которые вы написали на оборудовании, что делает операцию тривиальной. Это стоит цены хорошего обеда.Все, о чем я могу думать, это то, что это потребует серьезного взлома, если только svn2git
(из которых я не эксперт) изначально это как-то поддерживает.
Проблема в том, что фиксация frontend
полностью не зависит от фиксации в backend
. Нет реального способа сказать, какая фиксация будет соответствовать какой фиксации в одном репозитории. Это оставляет нам только один реальный вариант: история будет состоять из двух объединенных вместе веток, которые представляют историю исходного проекта, а затем, когда они будут объединены, новая ветка станет «лучшей моделью».
С этого момента я предполагаю, что у вас есть frontend
в svn-frontend
филиал импортный и backend
в svn-backend
ветка импортирована, и обе содержат свою историю.
Первая проблема - исправить svn-backend
быть в backend/
каталог:
git checkout svn-backend
git filter-branch --index-filter '
git ls-files -s |
perl -pe "s{\t\"?}{$&newsubdir/}" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE' HEAD
(Видеть эта документация, и ответ @Christopher)
Теперь, если они каким-то образом не содержат тот же коммит, что и базовый (маловероятно, если svn2git
создает некоторую предопределенную базовую фиксацию или что-то в этом роде ...), мы должны сделать ее. Не имеет значения, в какой ветке вы начинаете.
git symbolic-ref HEAD refs/heads/svn-base
rm .git/index
git clean -dxf
Git не может отслеживать пустые каталоги. Я никогда не проверял, применимо ли это к корневому каталогу, но мое предположение - нет, поэтому меньше создавайте пустой файл игнорирования git и фиксируйте:
touch .gitignore
git add .gitignore
git commit -m "Base for SVN branches"
Перепишем историю:
git rebase svn-base svn-frontend
git rebase svn-base svn-backend
Мы почти закончили. Теперь давайте создадим главную ветку. Если он уже существует:
git update-ref master "$head"
В противном случае:
git branch master
Давайте проверим это:
git checkout master
Наконец, слияние:
git merge svn-backend
Хорошая идея - пометить старые ветки, а затем удалить их:
git checkout svn-frontend
git tag svn-frontend
git branch -d svn-frontend
git checkout svn-backend
git tag svn-backend
git branch -d svn-backend
git checkout master
git branch -d svn-base
Одно из решений - преобразовать оба репозитория проектов SVN в 2 репозитория Git, а затем добавить один репозиторий Git в качестве Подмодуль Git другого.
Чтобы преобразовать репозиторий SVN в репозиторий Git, вы можете использовать любой сценарий на основе git-svn или SubGit. С помощью новейшего инструмента вы запускаете одну команду
$ subgit install path/to/svn/repository
Преобразованные репозитории git будут по пути / to / svn / repository / git.
Затем вы настраиваете доступ к обоим репозиториям Git и добавляете один как подмодуль другого:
$ git clone <frontend_GitURL> frontend
$ git co
$ cd frontend
$ git submodule add -b ng <backend_GitURL> backend