В 2017-2018 я учился в филиале французской школы 42 и мне приходилось много писать на Си. Было много учебных проектов, начиная от реверс-инжениринга стандартной библиотеки Си, printf, sha/md5/des алгоритмов, заканчивая своими собственными проектами, которые не имели отношения к Школе 42. Был простенький DNS proxy, сниффер сетевых пакетов, реверс-инжениринг игры Сапер. Сейчас я понимаю насколько ужасен тот код, но хочется его сохранить как память о бессонных ночах над сегфолтами, бас ероррами, потерянными указателями, утечках памяти. Два десятка репозиториев воспоминаний.
Мой github давно хотел чистки, и я все откладывал идею сделать полностью автоматический сборщик до более свободных дней. И вот у меня четвертый день кашель и второй день температура 37,5 - спать не получается - настало время доделать "хотелку". Репозиторий для проекта я создал несколько месяцев назад, но руки так и не доходили сделать.
Сбор требований
Скрипт должен складывать каждую ветку проекта в отдельную папку
Скрипт должен сохранять историю коммитов
Скрипт должен быть устойчив к мердж конфликтам типа (rename/rename)
Скрипт должен работать через Gihub Actions и запускать вручную
Скрипт должен принимать переменными окружения репозиторий архива, архивируемый репозиторий, основную ветку архива в которую сливать все, а так же токен и имя пользователя github, чтобы запушить новое
Скрипт должен работать без вмешательства через консоль (например с браузера телефона можно добавить в архив новый проект)
Скрипт должен быть максимально простым, чтобы побудить людей поучаствовать в его доработке (<3 open source)
Реализация
Согласно списку требований я решил написать сам скрипт на баше, хотя я в нем и не силен. Логика довольно простая: получаем список веток, копируем содержимое проекта и переносим все в подпапку, коммитимся, повторяем для всех веток, потом добавляем новый удаленный репозиторий, и мерджим все ветки в архив. Но есть один нюанс, если мы переносим все в подпапку, а потом тоже самое делаем с соседней веткой - мы можем получить мердж конфликт типа (rename/rename). Поэтому пришлось добавить коммит в одном месте, который не сработает, если нет мердж конфликта (гит проигнорирует команду, так как нечего коммитить), но если был мердж конфликт (rename/rename) - проблему решит просто git add . && git commit.
Код конфига для Gihub Actions:
name: archivist
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout Archived Repository
uses: actions/checkout@v2
with:
repository: ${{ secrets.ARCHIVED_REPOSITORY }}
token: ${{ secrets.WRITE_GITHUB_TOKEN }}
path: archived
fetch-depth: 0
- run: |
cd ./archived
git config user.name github-actions
git config user.email github-actions@github.com
existBranches=($(git branch -a | grep remotes | awk -F '/' '{ print $3 }'));
for i in "${existBranches[@]}"; do
git checkout -- .
git checkout -b ${i}-move origin/${i} || true
git reset --hard HEAD
mkdir -p ../tmp/${{ secrets.ARCHIVED_REPOSITORY }}
mv ./.git ../tmp/.git
cd ..
mv ./archived/ tmp/${{ secrets.ARCHIVED_REPOSITORY }}/${i}/
cd ./tmp/
git add .
git commit -m "Preparing ${{ secrets.ARCHIVED_REPOSITORY }}/${i} for move"
cd ../
mv ./tmp/ ./archived/
cd ./archived
done;
git config -l | grep 'http\..*\.extraheader' | cut -d= -f1 | xargs -L1 git config --unset-all
git remote add archive "https://${{ secrets.GIT_USERNAME }}:${{ secrets.WRITE_GITHUB_TOKEN }}@github.com/${{ secrets.ARCHIVE_REPOSITORY }}"
git fetch archive
git checkout -b tmp_${{ secrets.ARCHIVE_REPOSITORY_DEFAULT_BRANCH }} archive/${{ secrets.ARCHIVE_REPOSITORY_DEFAULT_BRANCH }} || true
for i in "${existBranches[@]}"; do
git merge ${i}-move --allow-unrelated-histories --no-edit --no-ff > /dev/null 2>&1 || true
git add .
git commit -m "resolve conflicts for ${{ secrets.ARCHIVE_REPOSITORY }}/$i" || true
git push --force --quiet "https://${{ secrets.GIT_USERNAME }}:${{ secrets.WRITE_GITHUB_TOKEN }}@github.com/${{ secrets.ARCHIVE_REPOSITORY }}" tmp_${{ secrets.ARCHIVE_REPOSITORY_DEFAULT_BRANCH }}:${{ secrets.ARCHIVE_REPOSITORY_DEFAULT_BRANCH }}
done;
>&2 echo "All done" ;
Итоги
Скрипт я написал за пару часов, и потом еще минут 40 потратил чтобы слить туда более 20 репозиториев (и наконец-то их удалить). Конечно хотелось бы сразу добавить список, но мне подошло и текущее решение. В любой момент можно добавить новый проект в архив.
Ссылка на проект https://github.com/setnemo/bygone
Ссылка на архив https://github.com/setnemo/archive