cmc/cleberg.net

My personal web garden & blog.

clone: git clone https://gitbay.org/cmc/cleberg.net.git

main: content/blog/2025-04-05-git-mirror.org · raw

  1#+date:        [2025-04-05 Sat 23:04:54]
  2#+title:       Automating GitHub to GitLab Repository Sync
  3#+description: Automatically mirroring GitHub repos to GitLab for redundancy.
  4#+slug:        git-mirror
  5#+filetags:    :self-hosting:
  6
  7This is a short post detailing how I maintained repositories on GitHub and
  8mirrors on GitLab - including both public and private repositories.
  9
 10Since GitLab locks pull-only mirrors behind their Premium and Ultimate tiers, I
 11found a different solution.
 12
 13* Creating Mirrors
 14
 15I'll skip the setup and just hit the bullet points:
 16
 17- I have a plethora of GitHub repositories.
 18- I used GitLab's mass-import functionality to do the initial import of my
 19  repositories from GitHub.
 20- I made sure all of my GitHub repositories were cloned locally in my =~/git=
 21  directory.
 22
 23* Setting up Mirror Connections
 24
 25To start, I navigated to the =~/git= directory, which holds all of the
 26repositories I have on GitHub and created a shell script.
 27
 28#+begin_src shell
 29cd ~/git
 30nano setup_mirrors.sh
 31#+end_src
 32
 33Within this shell script, I created a loop that will open each repository and
 34add both the GitHub and GitLab SSH-style clone URIs to the =origin= remote.
 35
 36#+begin_src shell
 37for repo in */
 38do
 39    cd $repo
 40    git remote set-url origin --push --add git@github.com:ccleberg/${repo%*/}.git
 41    git remote set-url origin --push --add git@gitlab.com:ccleberg/${repo%*/}.git
 42    git remote -v
 43    cd ..
 44done
 45#+end_src
 46
 47Once complete, I created another shell script to open each repository, pull any
 48remote commits, and push local commits to both remotes.
 49
 50#+begin_src shell
 51nano mirror.sh
 52#+end_src
 53
 54#+begin_src shell
 55for repo in */;
 56do
 57    cd $repo
 58    git pull --rebase origin HEAD
 59    git push
 60    cd ..
 61done
 62#+end_src
 63
 64Finally, enable execution of both scripts before moving on.
 65
 66#+begin_src shell
 67chmod +x setup_mirrors.sh
 68chmod +x mirror.sh
 69#+end_src
 70
 71* Initialize Mirrors
 72
 73To use the =setup_mirrors.sh= script above, simply execute it from a terminal.
 74
 75#+begin_src shell
 76./setup_mirrors.sh
 77#+end_src
 78
 79Once complete, each repository /should/ have one fetch URI (GitHub) and two push
 80URIs (GitHub & GitLab). At this point, any =git pull= or =git fetch= commands
 81will pull from GitHub and any =git push= commands will send updates to both
 82GitHub and GitLab.
 83
 84* Schedule Periodic Checks
 85
 86To utilize the =mirror.sh= script from the previous step, let's use crontab.
 87
 88#+begin_src shell
 89crontab -e
 90#+end_src
 91
 92Within crontab, I used the schedule below to ensure the script is executed
 93daily.
 94
 95#+begin_src text
 960 0 * * * /Users/cmc/git/mirror.sh
 97#+end_src
 98
 99This ensures that the =mirror.sh= file is executed daily and will push any local
100or GitHub commits to GitLab.
101
102I have tested this by manually running =mirror.sh= and watching the results.
103There are edge cases where I will need to intervene and manually resolve merge
104conflicts, but it's largely autonomous, so I'm happy with the results.