Переносим репозитории с GitHub на свой GitLab: план и подводные камни
Доступ к GitHub периодически становится ненадёжным: то не проходит оплата организации, то блокируется аккаунт без внятного объяснения, то просто пропадает уверенность, что завтра всё будет работать так же, как сегодня. Пока это не коснулось вас напрямую, кажется, что перенос репозиториев — дело на пару часов: git clone, git push в новое место, готово. На практике перенос кода — самая простая часть: сложность в том, что вокруг репозитория выстроена инфраструктура — issues, pull request'ы, CI/CD-пайплайны, вебхуки в Slack и таск-трекеры, SSH-ключи и токены доступа у каждого разработчика. Ниже — честный план миграции на self-hosted GitLab: что переносится штатно, что теряется без вариантов, и сколько времени на это реально закладывать команде среднего размера.
Содержание
- Когда переезжать и что выбрать вместо GitHub
- План миграции: последовательность, которая снижает риск
- Перенос истории коммитов: что переносится легко
- Issues и pull request'ы: что переносится, а что теряется
- CI/CD на новом месте: переносится только вручную
- Вебхуки, интеграции и доступ команды
- Честная оценка трудозатрат для команды среднего размера
Когда переезжать и что выбрать вместо GitHub
Решение переезжать стоит принимать до того, как доступ пропал полностью, а не в момент, когда репозитории уже недоступны. Организация на GitHub периодически теряет оплату, аккаунт попадал под блокировку хотя бы раз, или требования по размещению кода внутри страны стали обязательными — любой из этих поводов достаточен, чтобы перенести код туда, где вы полностью контролируете инфраструктуру и доступ.
Self-hosted GitLab CE — самый частый выбор для такого переезда: тот же продукт, что и облачный GitLab, только на вашем сервере, с репозиториями, merge request'ами, встроенным CI/CD и issue-трекером из коробки. Более лёгкие альтернативы — Gitea и её форк Forgejo — проще в администрировании, но беднее по встроенному CI/CD. План ниже ориентирован на GitLab CE как наиболее частый пункт назначения, но большинство шагов (перенос истории, вебхуки, SSH-ключи) одинаковы для любого self-hosted git-сервера.
Прежде чем начинать перенос, поднимите и проверьте целевую инсталляцию — она должна выдерживать нагрузку команды до переезда, а не после. Установка GitLab CE на VPS с нуля разобрана в статье как установить и настроить GitLab CE на VPS — начните с неё, если сервер ещё не поднят.
План миграции: последовательность, которая снижает риск
Переносить всё одним днём — плохая идея даже для небольшой команды: слишком много движущихся частей, чтобы не упустить что-то важное. Рабочий порядок:
- Подготовка целевой инфраструктуры — GitLab установлен, есть бэкап-стратегия, отдельный CI-раннер (или план его поднять), домен и TLS настроены.
- Тестовый перенос одного некритичного репозитория — чтобы обкатать процесс, импорт issues и CI на новом месте и понять, сколько времени уходит на один проект.
- Перенос истории кода для всех репозиториев — можно делать заранее, без остановки работы: коммиты не мешают разработчикам продолжать пушить в GitHub.
- Импорт issues и pull request'ов с фиксацией даты «заморозки»: после неё новые issues заводятся только в новом месте.
- Настройка CI/CD на новом месте и проверка, что пайплайны реально проходят на тестовых ветках.
- Переключение вебхуков и интеграций на новый адрес.
- Выдача доступа команде: SSH-ключи, токены, права по группам и проектам.
- Финальное переключение:
git remote set-urlна всех машинах, обновление ссылок в документации, закрытие или архивация репозиториев на GitHub.
Не пытайтесь совместить шаги 3 и 4 в один момент времени с непрерывной работой команды в обоих местах — рассинхронизация issues между двумя трекерами почти гарантированно приведёт к путанице, кто где отвечает на комментарий.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверПеренос истории коммитов: что переносится легко
Это единственная часть миграции, которая переносится действительно без потерь — git как система контроля версий не привязан к платформе, и вся история коммитов, веток, тегов переносится побайтово.
Самый надёжный способ — зеркальный клон с --mirror, который забирает все ветки и теги, а не только текущую:
git clone --mirror git@github.com:your-org/your-repo.git
cd your-repo.git
git remote set-url --push origin git@your-gitlab.example.com:your-group/your-repo.git
git push --mirror
Для private-репозиториев потребуется Personal Access Token GitHub с правами repo (HTTPS) или добавленный SSH-ключ (SSH). На действительно крупной истории (несколько гигабайт) клонирование может занять заметное время — это не баг, а особенность сети, закладывайте запас.
GitLab также умеет импортировать репозиторий напрямую по URL (Project → New Project → Import project → Repository by URL) — удобно для одиночных проектов, но при массовом переносе скрипт с --mirror в цикле быстрее и проще проверить на полноту.
Вместе с историей автоматически переносятся все коммиты с метаинформацией (автор, дата, сообщение), все ветки и теги, содержимое .gitattributes, .gitignore и остальных файлов репозитория.
Отдельно, вручную, нужно перенести:
- защищённые ветки — правила не являются частью git-истории, их надо настроить заново: Settings → Repository → Protected branches;
- GitHub Releases — это метаданные GitHub, а не git-теги; сами теги перенесутся, но описания релизов и прикреплённые бинарники нужно выгружать и заливать отдельно;
- LFS-объекты, если репозиторий использует Git LFS —
--mirrorих не подхватывает, нужны отдельныеgit lfs fetch --allиgit lfs push --all.
Если хотя бы один из ваших репозиториев подходит к пределам по размеру (сотни мегабайт истории, крупные бинарные файлы в старых коммитах), заранее прочитайте про типичные грабли с этим в статье предел размера репозитория: git-клон не влезает — миграция на новый сервер часто первый раз проявляет проблему, которая на GitHub была незаметна.
Issues и pull request'ы: что переносится, а что теряется
Здесь начинаются реальные потери, и о них стоит сказать честно, а не убеждать, что «всё переедет само».
GitLab предлагает встроенный импортер GitHub (Project → New Project → Import project → GitHub), который использует GitHub API и Personal Access Token для переноса. Он умеет переносить:
- issues с текстом, автором и датой создания;
- pull request'ы как merge requests, с диффом и историей коммитов внутри них;
- комментарии к issues и PR;
- метки (labels) — но без гарантии сохранения точных цветов и без автоматического маппинга на существующие метки в GitLab, если они называются иначе;
- вехи (milestones).
Что теряется или переносится с оговорками:
- Реакции (эмодзи на комментарии) — как правило, не переносятся вообще.
- Статусы CI-проверок, привязанные к PR — теряют смысл, потому что сам CI меняется, переносить их нет причины.
- Упоминания пользователей (
@username) — если ник в GitLab отличается от GitHub, старые упоминания в тексте останутся текстом, а не ссылкой на профиль. - Wiki — хранится как отдельный git-репозиторий и переносится тем же приёмом (
git clone --mirrorна.wiki.gitURL), но автоматического импортера для этого нет. - GitHub Projects (канбан-доски) — не переносятся импортером, структуру придётся воссоздавать вручную в GitLab Issue Boards.
- Discussions — прямого аналога и импортера в GitLab нет.
Практический совет: не гонитесь за идеальным 1:1 переносом всей истории issues за много лет. Перенесите только открытые issues и PR плюс закрытые за последние 3-6 месяцев, а старое оставьте в архивной копии GitHub-репозитория — это резко сокращает объём работы и почти не влияет на пользу для команды.
CI/CD на новом месте: переносится только вручную
Здесь нет автоматического импортера, и это стоит понимать заранее. GitHub Actions и GitLab CI/CD — разные системы с разным синтаксисом, моделью runner'ов и переменными окружения по умолчанию. .github/workflows/*.yml не превращается в .gitlab-ci.yml автоматически ни одним официальным инструментом.
Что придётся сделать вручную для каждого пайплайна:
- Переписать конфигурацию. Логика обычно переносится один в один (сборка → тесты → деплой), но синтаксис — нет: GitHub Actions matrix-стратегия и GitLab
parallel:matrixрешают одну задачу разными конструкциями. - Поднять раннеры. GitLab CI/CD выполняется на собственных runner'ах (Docker, Shell или Kubernetes executor) — их нужно установить и зарегистрировать до первого пайплайна. Пошаговая настройка разобрана в статье GitLab CI/CD на VPS: настройка.
- Перенести секреты. GitHub Secrets не экспортируются через API по соображениям безопасности — их вручную забирают из исходных систем и заводят заново в Settings → CI/CD → Variables, помечая чувствительные как Protected и Masked.
- Проверить deploy-шаги. Если деплой шёл через готовые GitHub actions — прямого аналога может не быть, и шаг придётся написать как обычный shell-скрипт.
Минимальный пример .gitlab-ci.yml, эквивалентный пайплайну «тест → сборка → деплой»:
stages:
- test
- build
- deploy
test:
stage: test
image: node:20
script:
- npm ci
- npm test
build:
stage: build
image: node:20
script:
- npm run build
artifacts:
paths:
- dist/
deploy:
stage: deploy
script:
- ./scripts/deploy.sh
only:
- main
Не переносите все пайплайны одновременно с кодом. Сначала перенесите код и issues, дайте команде поработать в новом GitLab пару недель, и только потом спокойно, по одному проекту, переносите CI/CD — пайплайн, сломавшийся в момент общего переезда, легко спутать с проблемой самого GitLab, хотя причина обычно в конкретной строке YAML.
Вебхуки, интеграции и доступ команды
Эта часть миграции наименее заметна на старте и наиболее болезненна, если её забыть — обычно всплывает через неделю-две, когда кто-то замечает, что уведомления в Slack перестали приходить.
Вебхуки и интеграции. У каждого репозитория на GitHub может быть свой набор вебхуков: уведомления в Slack или Telegram, интеграция с таск-трекером, вебхук деплоя или анализа кода. Составьте список активных вебхуков на GitHub до начала переноса (Settings → Webhooks) и зеркальный список задач «настроить то же в GitLab» (Settings → Webhooks проекта или группы). Часть интеграций (Slack, Jira) у GitLab встроена и настраивается через UI — их проще завести заново, чем переносить как generic-вебхук.
SSH-ключи и доступ разработчиков. SSH-ключи из профиля GitHub не переносятся никаким импортом — это персональные данные, привязанные к аккаунту. Каждый разработчик добавляет свой публичный ключ в профиль нового GitLab самостоятельно (тот же ключ или новый — некоторые команды предпочитают отдельный ключ под каждый git-хостинг). Это ручной шаг, который нельзя автоматизировать за пользователя, но можно назначить на конкретный день до финального переключения.
Personal Access Tokens. Токены GitHub, зашитые в CI-скриптах сторонних систем, в package-менеджерах (приватные npm-пакеты через GitHub Packages), в интеграциях с внешними сервисами — их нужно найти и заменить на токены GitLab. Полезно провести аудит: grep по кодовой базе и секретам CI на строки вида github.com или GITHUB_TOKEN, чтобы не упустить скрытые зависимости.
Права доступа по группам. GitHub Teams и GitLab Groups устроены похоже (вложенные группы, наследование прав), но не переносятся автоматически — роли (Owner, Maintainer, Developer, Reporter, Guest) нужно воссоздать вручную. Хороший повод заодно пересмотреть, кому реально нужен Maintainer, а кому хватит Developer. Практический подход к выдаче доступа без раздачи root на сам сервер разобран в статье как раздать доступ команде без выдачи root — те же принципы применимы и к правам внутри GitLab.
Отзыв старого доступа. После переноса — легко забываемый шаг: отозвать доступ к GitHub-организации у сервисов и людей, которым он больше не нужен, отозвать OAuth-приложения и деактивировать старые deploy-ключи. Открытый доступ к архивной копии кода, которым никто не пользуется, — это неучтённая поверхность атаки, а не безобидный хвост.
Честная оценка трудозатрат для команды среднего размера
Возьмём условную команду в 15-25 разработчиков и 10-20 активных репозиториев среднего размера, с CI/CD на большинстве проектов и несколькими внешними интеграциями. Ниже — ориентировочная раскладка по времени, не точная цифра для вашего случая, а структура, по которой стоит считать свою:
| Этап | Ориентировочное время | Кто выполняет |
|---|---|---|
| Подготовка сервера и GitLab CE | 0.5-1 день | DevOps/админ |
| Перенос истории кода всех репозиториев (скриптом) | 0.5-1 день | DevOps/админ |
| Импорт issues и PR через встроенный импортер | 1-2 дня (с проверкой качества) | DevOps/админ |
| Перенос и адаптация CI/CD (на репозиторий) | 0.5-1 день на проект | DevOps/админ + разработчик проекта |
| Настройка вебхуков и интеграций | 0.5-1 день | DevOps/админ |
| Выдача SSH-доступа и токенов команде | 2-3 часа координации + время каждого разработчика | Каждый разработчик самостоятельно |
| Финальное переключение и проверка | 0.5 дня | Вся команда |
| Стабилизация (мелкие проблемы первую-две недели) | Несколько часов в неделю | DevOps/админ |
Итого для команды такого размера реалистичная оценка — 5-10 рабочих дней активной работы одного человека, растянутых на 2-4 календарные недели при поэтапной миграции без остановки разработки. Если репозиториев больше 30-40 или среди них есть крупные монорепозитории с многолетней историей — закладывайте кратно больше времени на перенос истории и особенно CI/CD: именно число уникальных пайплайнов, а не число разработчиков, определяет объём ручной работы.
Что систематически недооценивают: время на CI/CD — это не копирование файла, а переписывание логики на новом языке конфигурации; время каждого разработчика на настройку локального окружения (умножьте на число людей — набегает больше, чем кажется); и период, когда часть команды по привычке ещё открывает старые ссылки на GitHub — сообщите дату отключения заранее и не один раз.
Не пытайтесь уложить весь переезд в один день ради красивой истории «переехали за сутки». Растянутая на пару недель миграция с тестовым прогоном на одном репозитории почти всегда обходится дешевле по нервам, чем марш-бросок в выходные.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Можно ли переносить репозитории постепенно, пока часть команды ещё работает в GitHub?
Да, для истории кода это безопасно — git push --mirror можно повторять, пока не наступит дата финального переключения. А вот issues и PR лучше не вести параллельно — заранее объявите дату «заморозки» GitHub-трекера.
Что делать с внешними контрибьюторами на GitHub у открытого проекта?
Полный уход с GitHub означает потерю этого канала — держите зеркало только для приёма внешних PR с ручным переносом в основной GitLab, либо сообщите контрибьюторам новый адрес.
Нужно ли переносить весь функционал GitHub Actions marketplace?
Нет прямого аналога маркетплейсу готовых actions в GitLab CI — вместо них пишут эквивалентные shell-команды или используют готовые Docker-образы под конкретные задачи (линтеры, сканеры безопасности).
Стоит ли сразу удалять репозитории на GitHub после переноса?
Не сразу. Разумнее перевести их в режим archived (read-only) на 1-3 месяца — подстраховка на случай, если что-то упустили.
GitLab CE тянет такую миграцию на минимальном VPS?
Для приёма кода и issues — да, но CI/CD-раннеры лучше вынести на отдельный сервер, чтобы сборки не конкурировали за ресурсы с самим GitLab.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →