Я так давно пользуюсь услугами Github, что уже начал забывать, как это страшно потерять код, который целый день сочинял и отлаживал. Раньше для сохранения кода я использовал дискетки, потом cd-rom и переносной жесткий диск, потом пришли флешки. Все это для того, чтобы перенести код с рабочего компьютера на домашний и не потерять. И все эти
устройства постоянно ломались, терялись, у них заканчивался срок службы и т.п.

Потом я завел свои "облака" и хранил код на своем железе и рабочих компьютерах. И наконец появился Github. По началу что-то ещё дублировалось на своих серверах и внешних дисках, но к сегодняшнему дню я настолько привык к сервису Github, все настолько удобно и надёжно, что страх того, что "дискетка" может сломаться, постепенно улетучился.

И тут на тебе! Оказывается, в любой момент, по не зависящим от меня причинам, меня могут отключить от этого технологического чуда!

И ладно бы, если б я ходил на работу и писал неизвестно что, неизвестно зачем. Но у меня-то код весь свой, и кроме него ничего нет. Оказывается, что за время существования Github там у меня завелись сотни репозиториев и просто так - вручную - их не скопируешь.

Тем более, что работаем мы сегодня не на одном компьютере, и понять, где что лежит, сразу невозможно - все лежит в Github-е.

Короче. Слепил я программку для быстрого копирования всех своих репозиториев из Github, из всех своих пользователей и организаций, к которым у меня есть доступ. Программа на Go, потому что я последнее время использую только Go (ну, не считая vue и javascript для webapp).

Программа использует 'gh' (github-cli) и 'git'. С помощью gh получаем список репозиториев, а с помощью git клонируем репозиторий со всей историей коммитов, со всеми ветками и тегами. Это все можно сделать из командной строки, но если у вас много репозиториев, то легче с помощью программы.

Вот эти команды:

$ gh repo list -L 10
$ git clone --mirror git@user-or-org/reponame reponame.git

Как уже говорилось выше, gh выдает список репозиториев, а git клонирует репозиторий со всеми потрохами.

Перед использованием программы в gh нужно залогиниться, т.е. выполнить комманду 'gh auth login' и убедиться, что у вас настроен доступ к Github по ключу ssh.

Далее, полученные архивы можно перенести на любой git-хостинг простыми командами:

$ cd old-repository.git
$ git push --mirror https://github.com/exampleuser/new-repository.git

Программа имеет параметры:

-users  <[user-or-organisation-comma-separated-list]>

здесь указываем список пользователей и(или) организаций, 
разделленые запятыми, архив котрых нужно создать 
(обязательный параметр)

-limit  [user-repo-comma-separated-list]

здесь можно указать список только тех репозиториев, 
которые нужно клонировать, также разделенные запятыми

-output [local-folder-name], default: ./repos

здесь указываем папку, куда нужно записать архивы, 
по умолчанию использется папка ./repos

Пример запуска программы:

$ go run . -users=myuser,myorg -limit=myuser/github-backup -output=./tmp

В этом случае программа будет искать репозитории у пользователя myuser и в организации myorg и загрузит только репозиторий github-backup пользователя myuser, как указано в пареметре -limit, если этот параметр убрать, то будут загружены все репозитории пользователя myuser и организации myorg. Если права для 'gh' и 'git' позволяют вам пользоваться приватными репозиториями, то будут загружены публичные и приватные репозитории, если не позволяют, то только публичные.

Программа размещена в привычном для меня Github, доступ пока еще есть:
https://github.com/kirill-scherba/github-backup

Всё же надеюсь, что доступ к Github у нас останется, но, оказывается, в этом мире бэкап нужен всегда!

Вот ещё один адрес на Gitflic, пока он запасной:
https://gitflic.ru/project/kirill-scherba/github-backup

С уважением,
Kirill Scherba

Комментарии (25)


  1. amarao
    24.04.2022 11:21
    +7

    Ну, насколько я понимаю, в силу устройства git'а репы будут локальными если с ними работал. Т.е. код хранится распределённо by construction. А вот вся проприетарщина GH - issues, MR и т.д. - они проприетарны и с ними ничего толком не сделать.


    1. numb
      24.04.2022 11:54
      +2

      Как вариант, развернуть локальную копию gitlab и клонировать репы через импорт. При импорте, копируется большинство сущностей - PR, Issues, labels.

      Дальнейшая синхронизания, к сожалению, только за деньги.

      Gitlab, в докере, разворачивается одной командой)


      1. Aquahawk
        24.04.2022 11:56
        +4

        И жрёт 8(!) Гигабайт оперативы. Я с дури себе развернул, теперь хочу на gitea уйти


        1. max_rip
          24.04.2022 12:20
          +1

          У меня на 2гб виртуалке нормально живёт со свапом на 4гб ;)


          1. gecube
            24.04.2022 16:44
            +2

            да, согласен с тем, что для комфортной работы с гитлабом на 50 пользователей и гитлаб регистри (и прочими возможностями) - лучше иметь минимум 2 ядра и 6 гиг памяти, иначе тормозит, как не знамо что


    1. Telmah
      24.04.2022 12:37
      +1

      ну автор там в статье упоминал что у него куча реп и кроме кода больше ничего нет...


    1. ghostiam
      24.04.2022 21:58

      Можно забекапить с помощью этого скрипта https://github.com/josegonzalez/python-github-backup

      Бэкапит не только репозитории с issue/pr, но и wiki, gists, и может бекапить ещё и репозитории помеченные stars.

      (упомяну @krak, чтобы 2 комментария не писать)


    1. kirill-scherba Автор
      26.04.2022 16:45

      Вообще, предполагалось что архив сщзданный программой нужен для хранения и, при необходимости, переноса на другой сервер. Архивы созданные с использование параметра --mirror хронят всю историю коммитов.

      Но если вам необходимо из такого архива сделать рабочий git каталог на том же компе где сохранен архив, то вот набор комманд с помощью которых это можно сделать:

      cd reponame.git git bundle create reponame.bundle --all

      После этого у вас появится файл с именем reponame.bundle, который можно легко скопировать. Затем вы можете создать новый обычный репозиторий git из этого файла, используя:

      git clone reponame.bundle reponame

      Обратите внимание, что git копирует только те коммиты, которые ведут к какой-либо ссылке (ветке или тегу) в репозитории. И, запутанные коммиты не сохраняются в таком репозитории. Но для работы он полностью пригоден.

      Спасибо.


  1. krak
    24.04.2022 12:55
    +1

    Жду продолжения по клонированию еще и отслеживаемых репозиториев (Stars). Получить можно, например, с помощью API https://api.github.com/users/kirill/starred?page=1&per_page=10000.


    1. kirill-scherba Автор
      26.04.2022 15:14

      Да, Кирилл, уже практически готово.

      Смержу ваш пулреквест (я там вам новые комментарии оставил). И уже есть новая ветка с клонированием Stars, солью её после ваших правок. И будет новая версия.

      Спасибо.


  1. neenik
    24.04.2022 14:07
    +2

  1. classx
    24.04.2022 14:38
    +4

    пара вопросов:

    • почему golang, а не просто bash?

    • во многих репо есть секреты, как их сохранить тоже? (Encrypted secrets - GitHub Docs)


    1. kirill-scherba Автор
      26.04.2022 15:20

      Мне golang ближе и милее ????

      А по поводу секретов, то скорее всего нет. При создании github пишет, что они не подлежат редактированию.

      Хотя, можно всё же извратиться и создать и запустить гитхаб-акшин который будет использовать эти секреты и оттуда их забрать. Но пока как-то это выглядит костыльно.

      Спасибо.


  1. schulzr
    24.04.2022 15:45

    Спасибо. Скажите, а для sourceforge есть у вас такой же скрипт?


    1. kirill-scherba Автор
      26.04.2022 16:28
      +1

      К сожалению, нет.
      Спасибо.


  1. E_STRICT
    24.04.2022 16:01
    +18

    Использую такое код уже несколько лет.

    REPOSITORIES=$(curl -s https://api.github.com/users/NAME/repos?per_page=1000 | jq -r '.[] | select(.fork == false).clone_url')
    for REPOSITORY in $REPOSITORIES; do
      git clone $REPOSITORY
    done


    1. Staschik
      25.04.2022 05:57
      +1

      Добавьте --bare и сэкономите немного места.


  1. gth-other
    24.04.2022 18:14
    +4

    А можно воспользоваться уже готовым инструментом самого гитхаба - https://github.com/settings/admin.


  1. vtb_k
    24.04.2022 18:31

    После удаления zinit репы автором пришлось напрячься и накидать небольшой скрипт и повесить его на systemd service


    repos=(<список реп тут>)
    
    pr_dir=/data/work/projects
    for repo in "${repos[@]}"
    do
      mkdir -p /tmp/$repo
      cd $pr_dir
    
      if [ ! -d "$pr_dir/$repo/.git" ]; then
        echo "No .git dir"
        gh repo clone $repo $repo > /tmp/$repo/clone.log
      fi
    
      echo "Sync github repo: $repo"
      gh repo sync $repo
    
      cd $pr_dir/$repo
      echo "Inside $(pwd)"
    
      git pull > /tmp/$repo/pull.log
    done
    notify-send --urgency=normal 'Github sync service' "Github repos were synced"


  1. VXP
    25.04.2022 07:32

    А что случилось?


    1. naneri
      25.04.2022 08:38


  1. PaulArgent
    25.04.2022 14:32

    Пару дней назад решал подобную задачу по полному бэкапу своего и интересующих меня репозиториев GitHub. Но в отличае от автора статьи, помимо git-репозиториев мне нужен был полный бэкап всей остальной инфраструктуры GitHub: issues, comments, stars и т.д.

    Сперва так же хотел заняться велосипедостроительством, благо у GitHub простой и обширный API. Но немного погуглив нашел отличное готовое решение: https://github.com/josegonzalez/python-github-backup

    Устанавливаем Python последней версии с офф. сайта, если у вас его еще нет.

    Далее устанавливаем скрипт в одну строку:

    pip install github-backup

    или лучше:

    pip install git+https://github.com/josegonzalez/python-github-backup.git#egg=github-backup

    Далее получаем новый токен в настройках GitHub:

    Settings - Developer settings - Personal access tokens

    И бекапим!

    Для полного бэкапа всех своих репозиториев, со всей инфраструктурой, я использую такую строку запуска в cmd:

    python c:\users\user\appdata\local\programs\python\python310\scripts\github-backup -user My_Github_Username --token My_Github_token --output-directory C:\Backup --private --fork --repositories --starred --watched --followers --following --issues --issue-comments --issue-events --pulls --pull-comments --pull-commits --pull-details --labels --wikis --gists --starred-gists --all

    Для бэкапа чужого репозитория я использую такую строку запуска в cmd:

    python c:\users\user\appdata\local\programs\python\python310\scripts\github-backup -user Other_Author_Github_Username --token My_Github_token --output-directory C:\Backup -R Other_Author_Repository_Name --repositories --issues --issue-comments --issue-events --pulls --pull-comments --pull-commits --pull-details --labels --wikis

    У скрипта обширные параметры запуска, бэкап можно настроить на любой вкус.


  1. webdevium
    26.04.2022 10:32
    -1

    Ну как можно было параметр назвать limit? В 2022 году то.

    Есть же классические для cli приложений include и exclude.


    1. kirill-scherba Автор
      26.04.2022 15:45

      А вот так - легко ????

      Заимствовал у Ansible: https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html

      А что, действительно, уже кто-то ухитрился придумать классические параметры для cli приложений?

      Вот блин... тут всю жизнь пишешь код... а те кто не в состоянии - стандарты сочиняют ????

      Спасибо.


  1. Anonim66
    26.04.2022 16:29
    +1

    Спасибо за важную в наше время информацию!