Anything may be lost unless you have a backup for them.
This article tell you how to backup your git repositories via GitHub Actions.
Our target
In this article, our final target is to backup git repositories under the user-a
to another user named user-b
.
Preparation
Before all, we need to create a new git repository used to run the backup workflow, and there will be some files in it and you can use the command tree
to have a check:
.├── .github│ └── workflows│ └── mirror.yaml
Normally, we wouldn’t to expose our secrets directly, so we need to create some secrets in the GitHub repository settings which will be used to clone, create and push git repo:
GH_TOKEN_A
is theuser-a
‘s GitHub AccessTokenGH_TOKEN_B
is theuser-b
‘s GitHub AccessTokenSLACK_WEBHOOK
is used to notify us while the workflow started or ended
Mirror Workflow
List user-a
‘s repos
We’ll use the command-line tool gh
to list user-a
‘s github repositories:
echo ${GH_TOKEN_A} > gh_token_agh auth login --with-token < gh_token_agh repo list user-a -L 1000 > a_reposcat a_reposcat a_repos | wc -l
Create repo with the same name
Before push the git repo, we need to make the repo existed under the user user-b
, like list repos above, we also use gh
to create a git repo with the same name:
gh repo create user-b/${repo_name} --private --description "${repo}" -y || true
Clone repo
While we make sure that the repo with the same name is already existed under the user user-b
, we can clone the git repo from the user user-a
first.
Unlike normal git clone, we should use the flag --bare
to clone the repo:
git clone --bare https://${GH_TOKEN_A}@github.com/user-a/${repo_name}.git ${repo_name}
Push repo
Finally, we can push the cloned repo to user-b
‘s repo which has the same name.
And we will use two flags to push them:
--all
means push all branches--mirror
means push allrefs
, contains all branches and tags
cd ${repo_name}mirror_repo="https://${GH_TOKEN_B}@github.com/user-b/${repo_name}.git"git push --all -f ${mirror_repo} || truegit push --mirror -f ${mirror_repo} || true
Full workflow script
This is the full workflow script:
name: Mirror reposon:schedule:- cron: "0 18 * * 0-4"workflow_dispatch: # Manual runjobs:mirror:runs-on: ubuntu-lateststeps:- uses: actions/checkout@v2- name: GitHub CLI versionrun: gh --version- name: List reposenv:GH_TOKEN_A: ${{ secrets.GH_TOKEN_A }}run: |echo ${GH_TOKEN_A} > gh_token_agh auth login --with-token < gh_token_agh repo list user-a -L 1000 > a_reposcat a_reposcat a_repos | wc -l- name: Mirror reposenv:GH_TOKEN_A: ${{ secrets.GH_TOKEN_A }}GH_TOKEN_B: ${{ secrets.GH_TOKEN_B }}IGNORE_REPOS: "/repo_a/repo_b/"ONLY_BRANCH_REPOS: "/repo_c/repo_d/"run: |echo ${GH_TOKEN_B} > gh_token_bgh auth login --with-token < gh_token_bmkdir reposcd reposset -xcat ${GITHUB_WORKSPACE}/a_repos | while read repo; dorepo_name=$(echo ${repo} | awk '{print $1}' | awk -F/ '{print $2}')[[ ${IGNORE_REPOS} =~ "/${repo_name}/" ]] && continue || truegh repo create user-b/${repo_name} --private --description "${repo}" -y || truerm -rf ${repo_name}git clone --bare https://${GH_TOKEN_A}@github.com/user-a/${repo_name}.git ${repo_name}cd ${repo_name}mirror_repo="https://${GH_TOKEN_B}@github.com/user-b/${repo_name}.git"git push --all -f ${mirror_repo} || true[[ ${ONLY_BRANCH_REPOS} =~ "/${repo_name}/" ]] && continue || truegit push --mirror -f ${mirror_repo} || truecd -done- name: Slack Notificationuses: rtCamp/action-slack-notify@v2env:SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}