- Все совпадения случайны
- Действия могут быть деструктивны и выполняются на свой страх и риск
Представим следующее: дружелюбный gitlab.com уведомил нас, что в ближайшее время наши с ним пути разойдутся и нам пора собирать вещички.
Проблема осложняется тем, что репозиториев в нашем аккаунте гитлаба вагон и маленькая тележка.
На наше счастье у нас уже есть свой сервер git с блекджеком и всем остальным на базе selfhosted gitea (но на самом деле реализация сервера не сильно принципиальна). Все, что нам нужно – перенести репозитории со всей историей, ветками и тегами.
Предварительные соглашения
-
Работать будем по SSH, все ключи добавлены, соединения настроены.
-
Не будем сильно заморачиваться над красотой наших скриптов, немножко хардкода нам не повредит.
-
Специфично для gitea: на самом деле в gitea имеется встроенный механизм зеркалирования репозиториев, но будем считать, что мы принципиально не выпускаем в интернет наш сервер.
-
Специфично для gitea: работать будем локально через API, токен сгенерирован заранее.
-
Специфично для gitea: на нашем сервере gitea репозитории будут расположены в одной организации в виде плоской структуры, а гитлабовские группы будут преобразованы в префиксы имен репозиториев (не принципиально, но хотелось бы сохранить определенный порядок). Если организации нет и не планируется – рекомендую почитать API gitea и подобрать соответствующие методы.
Примерный план действий
- Предварительно создать на нашем сервере gitea пустые репозитории под новыми именами.
- Выкачать репозитории на локальную машину под новыми именами.
- Загрузить репозитории с локальной машины на сервер gitea.
Реализация
1. Создаем пустые репозитории на сервере gitea
- Этот пункт специфичен для gitea, для других реализаций придумывайте сами.
- Выполняется на сервере gitea в любом каталоге от любого пользователя. Будем подразумевать
/home/user
.
1.1. Создаем текстовый файл repos-list.txt, содержащий имена новых репозиториев
Наименования гитлабовских групп являются необязательными префиксами, а имена репозиториев соответствуют гитлабовским.
Формат файла repos-list.txt:
group-1_group-n_reponame_1
...
group-1_group-n_reponame_n
1.2. Создаем два скрипта create-repos.sh и remove-repos.sh
1.2.1. create-repos.sh – создает репозитории по списку из файла repos-list.txt
#!/bin/bash
REPOS_LIST="repos-list.txt"
API_URL="http://localhost:3000/api/v1"
HEADER1="content-type: application/json"
HEADER2="Authorization: token xxxxxxxxxxxxxx_gitea_token_xxxxxxxxxxxxxxxx"
TEAM="team_name"
TEAM_ID="111"
while IFS= read -r LINE; do
echo "${LINE}"
METHOD="POST"
API_STRING="orgs/org_name/repos"
DATA="{ \"name\": \"${LINE}\" }"
curl -X "${METHOD}" -H "${HEADER1}" -H "${HEADER2}" -d "${DATA}" "${API_URL}/${API_STRING}"
echo "Add ${LINE} into ${TEAM}"
METHOD="PUT"
API_STRING="teams/${TEAM_ID}/repos/org_name/${LINE}"
curl -X "${METHOD}" -H "${HEADER1}" -H "${HEADER2}" -d "${DATA}" "${API_URL}/${API_STRING}"
echo
done < ${REPOS_LIST}
Используя заранее сгенерированный токен (заменить на свой), для организации с именем org_name (заменить на свое) читает из файла repos-list.txt имена репозиториев, создает репозитории с указанными именами и добавляет их в команду team_name (заменить на свое).
TEAM_ID заменить на корректный. Узнать можно с помощью команды:
curl -X 'GET' -H 'accept: application/json' -H "Authorization: token xxxxxxxxxxxxxx_gitea_token_xxxxxxxxxxxxxxxx" 'localhost:3000/api/v1/orgs/org_name/teams/search?q=team_name'
1.2.2. remove-repos.sh – удаляет созданные репозитории, на случай если что-то пойдет не так
#!/bin/bash
REPOS_LIST="repos-list.txt"
API_URL="http://localhost:3000/api/v1"
HEADER1="content-type: application/json"
HEADER2="Authorization: token xxxxxxxxxxxxxx_gitea_token_xxxxxxxxxxxxxxxx"
METHOD="DELETE"
while IFS= read -r LINE; do
echo "remove ${LINE}"
API_STRING="repos/org_name/${LINE}"
curl -X "${METHOD}" -H "${HEADER1}" -H "${HEADER2}" "${API_URL}/${API_STRING}"
done < ${REPOS_LIST}
1.3. Выполняем create-repos.sh для создания репозиториев по списку
$ ./create-repos.sh
2. Выкачиваем репозитории на локальную машину
Все последующие действия универсальны и выполняются на локальной машине от имени текущего пользователя.
2.1. Создаем файл repos.csv со списком репозиториев для миграции следующего формата:
git@gitlab.com:gitlab-account/group-1/group-n/reponame_1.git group-1_group-n_reponame_1
...
git@gitlab.com:gitlab-account/group-1/group-n/reponame_n.git group-1_group-n_reponame_n
Важно: Имена репозиториев должны совпадать с именами из repos-list.txt на сервере.
2.2. Создаем скрипт download_repos.sh для выкачивания репозиториев из gitlab на свою машину
#!/bin/bash
REPOS_LIST="repos.csv"
REPOS_DIR="repos_from_gitlab"
while IFS= read -r LINE; do
read -a REPO <<< ${LINE}
echo "Performing repo: ${REPO[1]}.."
mkdir -p "${REPOS_DIR}/${REPO[1]}"
cd "${REPOS_DIR}/${REPO[1]}"
git clone "${REPO[0]}" --mirror ".git"
git config --local --bool core.bare false
git reset --hard
git remote add gitea git@my.giteaserver.ru:org_name/${REPO[1]}.git
cd ../..
echo -e "done\n"
done < ${REPOS_LIST}
Скрипт по списку из repos.csv клонирует репозитории из gitlab в каталог repos_from_gitlab на локальной машине вместе со всей историей, ветками и тегами; добавляет в конфиг полученных репозиториев ссылку на наш сервер my.giteaserver.ru (заменить на свое) под именем gitea.
org_name (заменить на свое) должен совпадать с организацией из create-repos.sh.
2.3. Выполняем скрипт download_repos.sh и выкачиваем репозитории на локальную машину
$ ./download_repos.sh
3. Загружаем репозитории на свой сервер git
3.1. Создаем скрипт upload_repos.sh для загрузки репозиториев на свой сервер git
#!/bin/bash
REPOS_DIR="repos_from_gitlab"
for DIR in $(ls ${REPOS_DIR}); do
echo "Push repo: ${DIR}.."
cd "${REPOS_DIR}/${DIR}"
git push gitea --mirror
cd ../..
echo -e "done\n"
done
Скрипт загружает все репозитории из каталога repos_from_gitlab на наш сервер git.
3.2. Выполняем скрипт upload_repos.sh и загружаем репозитории на свой сервер
$ ./upload_repos.sh
Готово.
PS
- Надеюсь, это кому-то поможет.
- Никогда не любил gitlab