Перенос кода с tfs на git
В один прекрасный день, наш TFS2012 был обновлен до TFS2013.Вместе с TFS2013 у нас появилась возможность, оставаясь в рамках привычного интерфейса администрирования и менеджмента прав, перейти на распределенную source control git. (Про плюс и минусы распределенного source control сказано уже столько, что повторять не стоит, т.к. холиваров уже было много.)Задача: перенести разработку build на git, сохранив при этом историю изменений.Риски
Не всю историю удастся перенести: если вы активно перемещали ваш код, иногда часть теряется; Код придется переразложить на ветки руками; Возможно, придется некоторое время «жить» параллельно на 2 системах контроля версий; Если при build вы использовали более одного проекта, то придется подключить их в качестве submodules или придумывать другие способы подключения зависимостей (nuget, к примеру в .net, gem в ruby и т. п.); Придется перенести не только код, но и build. Перед началом миграции кода…Перед тем, как будете переносить репозиторий, рекомендую погасить технические долги в плане version control: удалить мертвые ветки; смержить то, что нужно смержить; удалить ненужный/неиспользуемый код, файлы, которые не должны быть в source control, в принципе (промежуточные этапы компиляции, индексы resharper и т.п.). Это лучше сделать на TFS, т.к. тащить это в GIT все равно смысла не имеет. Чем меньше сущностей для переноса, тем лучше.Заранее стоит подумать и о том, как в git будет этот переносимый код разложен. Например, TFS позволял в рамках одного TFS Project вести хоть сотню проектов в смысле кода, и каждым из них управлять отдельно, делать коммиты в отдельную папку и т.п. Git такого не позволит. По крайней мере, управление разными проектами в рамках одного репозитория по отдельности тут невозможно.Внешний вид такого проекта Начинаем миграцию Git-TF — это основная утилита, которая, исключая мозг и знания о коде, понадобится при миграции.Установка Git-TF Качаем утилиту миграции. Она на java.Открыв ее, читаем документацию по настройке. Это не долго, советую потратить на это пару минут.Вот такая вебстраничка В целом, она тривиальная. Поставить java, прописать пути в переменной окружения на java и на команду Git-TF. Java нужна, чтобы утилиту можно было запустить и на не Windows машинах.Clone кода После того, как настройки завершили, выполняем клонирование из консоли.Синтаксис: git tf clone tfs-server:8080/tfs/*Collection $/Project –deep–deep означает клонирование с историей, а не только последний слепок кода.Как-то так После окончания выкачки кодов в home каталоге (C:/users/myuser) будет находиться проект с именем, соответствующим проекту в TFS.
И выглядеть так При этом будет перенесена вся история, которая была в этом репозитории.Каждый коммит будет помечен тэгом. Тэг — это номер коммита в TFS (очень помогает, если нужно посмотреть, как все было до git).
Варианты миграции Концепции системы хранения кода в TFS и GIT различные. Поэтому сконвертировать одной командой с сохранением веток TFVC в Git репозитории не так уж просто.Тут есть ещё второй момент: будет ли это перманентная миграция или какое-то время вы готовы работать.В зависимости от этого я бы выделил такие варианты миграции: Перманентно №1 Git-TF может скопировать весь рапозиторий, и будет одна ветка в git- master. Все TFS ветки будут вместе как папки. Вам придется руками создать ветки и так же вручную разложить в них код так, как вам нужно.Изначально же проект будет выглядеть следующим образом Проблема тут очевидна — до точки разделения кода в Git все изменения лежат скопом.Уже потом придется приводить проект к нормальному для Git виду.
К вот такому Перманентно №2 Используя GIT TF, можно вытащить все нужные ветки и сделать их ветками-сиротами (orphan), и уже по необходимости в git делать merge. Тут проблема диаметрально противоположная — до точки слияния коды разных веток независимые.Не перманентно Если вы готовы некоторое время жить частично в Git, частично TFVC, то этот вариант для вас. Миграция ветки main из TFVC в ветку main на Git. Далее уже бранчуемся от этой перенесенной ветки.По мере готовности веток в TFVC к слиянию делать merge внутри TFVC, а затем делать Git TF pull из ветки main TFVC в Git main. Таким образом, мы заберем разницу между коммитами в TFVC и Git. Далее делаем rebase по необходимости. Проблема тоже очевидная — жить в 2 разных project какое-то время с 2 разными системами контроля версий. Можно очень хорошо разойтись на уровне кода.Общие моменты для всех вариантов После того, как вы локально получили код и его историю, нужно сделать несколько вещей: Создать в новом TFS projectCollection (это опционально) и все projects. Не буду на этом заострять внимание — можно погуглить или прочесть мою статью про миграцию SVN в Git-TFS.Push на remote Далее добавить новый удаленный репозиторий (remote), сделать туда push. Обязательно вместе с tags, чтобы потом можно было искать соответствие.В GitExtensions это здесь Раскладывание кода, в случае Перманентно 1 В моем случае, весь перенос растянулся на 2 дня.Проект был разделен на 12 подпроектов, т.к. именно столько разных логических проектов в нем жило, и все это вынесено в отдельный projectCollection.Получилось вот так: Основным ограничивающим фактором было:
Наличие определенного беспорядка в репозитории; Необходимость самому создать и проверить на собираемость все ветки; Подключить submodules; Создать бинарные ветки в репозиториях с кодом; Непонимание в одном из проектов какая ветка жива, какая не жива. Все это относится не к методу, а к проекту в целом.Merge, Git TF pull, Rebase в случае не перманентной миграции Если схематически рисовать, то будет примерно так.Шаг 1 Шаг 2 Шаг 3 Шаг 4 Шаг 5 Шаг 6 При такой миграции нам повезло — никаких submodules не было, т.о. коды мы перекладывали один в один. Наличие старого кода, мертвых веток, конечно, осложнило жизнь, но мертвые ветки мы не переносили и, следовательно, в Git код был чище.
Ограничение истории: Git-TF ничего не знает про другие проекты, кроме того, который вы указали. Т.е. если ваш код когда-то был в другом project collection или другом project, то в TFS коммиты из них не увидите — только те, которые в текущем проекте (файлы при этом конечно же будут на диске). Как вы видели историю в TFS, так же вы ее увидите в Git.Пример: вы сделали move куска кода из одного TFS project в другой. Тогда командаgit tf clone tfs:8080/tfs/DefaultCollection $/ TargetProjects --deep вытащит только последний коммит, без истории.Если move был сделан недавно, то можно забрать историю из старого проекта, указав последний перед move коммит.git tf clone tfs:8080/tfs/DefaultCollection $/SourceProjects --deep --version=57012Если же эти изменения были сделаны давно, то это будет крайне тяжело — вытащить историю, т.к. нужно будет проделать много ручных манипуляций.Не наступайте на наши грабли: «Решили переходить на Git, переходите на Git», — эта фраза кажется банальной, но если переходить на Git по полгода, то в это время возникнет слишком много проблем, которые сильно измотают всем нервы. Git — это source control. Не надо пытаться вместе с Git сразу поменять build систему и процессы разработки. Сделайте сначала одно, затем другое. Именно из-за того, что Git рассматривался в контексте изменения процесса разработки-тестирования-внедрения-сопровождения у одной из команд очень долго идет процесс миграции. Уже полгода… Убедитесь, что все разработчики хотя бы минимальную практику работы с Git получили до начала. Иначе может наступить момент, когда «некогда думать, надо делать». А тут вдруг окажется, что человек не знает, как свой код объединить с другой ветки и выложить на remote repository. P.S. Есть у меня небольшой проект GitQuiz (тестовые примеры, видео как их выполнить).Очень помогает для обучение разработчиков, у которых есть некоторые теоретические знания по работе с распределенными системами хранения исходных кодов, но нет практического опыта. Я его на своих коллегах опробировал.Ну, а совсем для профи, можно мне с этим проектом помочь, есть набор задач, до которых у меня пока руки не дошли.