Commit 6fe2867c47
Unsigned
Layout: unified · split
content/blog/2025-04-05-git-mirror.org added +104
| @@ -0,0 +1,104 @@ | |||
| 1 | #+date: <2025-04-05 Sat 23:04:54> | ||
| 2 | #+title: Mirroring my Repositories from GitHub to GitLab | ||
| 3 | #+description: Read to learn how I was able to efficiently make sure all of my repositories are mirrored from GitHub to GitLab. | ||
| 4 | #+filetags: :git: | ||
| 5 | #+slug: git-mirror | ||
| 6 | |||
| 7 | This is a short post detailing how I maintained repositories on GitHub and | ||
| 8 | mirrors on GitLab - including both public and private repositories. | ||
| 9 | |||
| 10 | Since GitLab locks pull-only mirrors behing their Premium and Ultimate tiers, I | ||
| 11 | found a different solution. | ||
| 12 | |||
| 13 | * Creating Mirrors | ||
| 14 | |||
| 15 | I'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 | |||
| 25 | To start, I navigated to the =~/git= directory, which holds all of the | ||
| 26 | repositories I have on GitHub and created a shell script. | ||
| 27 | |||
| 28 | #+begin_src shell | ||
| 29 | cd ~/git | ||
| 30 | nano setup_mirrors.sh | ||
| 31 | #+end_src | ||
| 32 | |||
| 33 | Within this shell script, I created a loop that will open each repository and | ||
| 34 | add both the GitHub and GitLab SSH-style clone URIs to the =origin= remote. | ||
| 35 | |||
| 36 | #+begin_src shell | ||
| 37 | for repo in */ | ||
| 38 | do | ||
| 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 .. | ||
| 44 | done | ||
| 45 | #+end_src | ||
| 46 | |||
| 47 | Once complete, I created another shell script to open each repository, pull any | ||
| 48 | remote commits, and push local commits to both remotes. | ||
| 49 | |||
| 50 | #+begin_src shell | ||
| 51 | nano mirror.sh | ||
| 52 | #+end_src | ||
| 53 | |||
| 54 | #+begin_src shell | ||
| 55 | for repo in */; | ||
| 56 | do | ||
| 57 | cd $repo | ||
| 58 | git pull --rebase origin HEAD | ||
| 59 | git push | ||
| 60 | cd .. | ||
| 61 | done | ||
| 62 | #+end_src | ||
| 63 | |||
| 64 | Finally, enable execution of both scripts before moving on. | ||
| 65 | |||
| 66 | #+begin_src shell | ||
| 67 | chmod +x setup_mirrors.sh | ||
| 68 | chmod +x mirror.sh | ||
| 69 | #+end_src | ||
| 70 | |||
| 71 | * Initialize Mirrors | ||
| 72 | |||
| 73 | To 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 | |||
| 79 | Once complete, each repository /should/ have one fetch URI (GitHub) and two push | ||
| 80 | URIs (GitHub & GitLab). At this point, any =git pull= or =git fetch= commands | ||
| 81 | will pull from GitHub and any =git push= commands will send updates to both | ||
| 82 | GitHub and GitLab. | ||
| 83 | |||
| 84 | * Schedule Periodic Checks | ||
| 85 | |||
| 86 | To utilize the =mirror.sh= script from the previous step, let's use crontab. | ||
| 87 | |||
| 88 | #+begin_src shell | ||
| 89 | crontab -e | ||
| 90 | #+end_src | ||
| 91 | |||
| 92 | Within crontab, I used the schedule below to ensure the script is executed | ||
| 93 | daily. | ||
| 94 | |||
| 95 | #+begin_src text | ||
| 96 | 0 0 * * * /Users/cmc/git/mirror.sh | ||
| 97 | #+end_src | ||
| 98 | |||
| 99 | This ensures that the =mirror.sh= file is executed daily and will push any local | ||
| 100 | or GitHub commits to GitLab. | ||
| 101 | |||
| 102 | I have tested this by manually running =mirror.sh= and watching the results. | ||
| 103 | There are edge cases where I will need to intervene and manually resolve merge | ||
| 104 | conflicts, but it's largely autonomous, so I'm happy with the results. | ||
theme/templates/index.html +7 −6
| @@ -10,18 +10,19 @@ sub rsa4096 2022-11-16 [E]</pre> | |||
| 10 | <h2>Recent Blog Posts</h2> | 10 | <h2>Recent Blog Posts</h2> |
| 11 | 11 | ||
| 12 | <div class="post"> | 12 | <div class="post"> |
| 13 | <time datetime="2025-02-24 19:20:05">2025-02-24</time> | 13 | <time datetime="2025-04-05 23:04:54">2025-04-05</time> |
| 14 | <a href="/blog/email-migration.html" >A Painful Email Migration</a> | 14 | <a href="/blog/git-mirror.html">Mirroring my Repositories from GitHub to |
| 15 | GitLab</a> | ||
| 15 | </div> | 16 | </div> |
| 16 | 17 | ||
| 17 | <div class="post"> | 18 | <div class="post"> |
| 18 | <time datetime="2025-02-11 11:40:00">2025-02-11</time> | 19 | <time datetime="2025-02-24 19:20:05">2025-02-24</time> |
| 19 | <a href="/blog/obscura-vpn.html">A Review of Obscura VPN: A Two-Party VPN</a> | 20 | <a href="/blog/email-migration.html">A Painful Email Migration</a> |
| 20 | </div> | 21 | </div> |
| 21 | 22 | ||
| 22 | <div class="post"> | 23 | <div class="post"> |
| 23 | <time datetime="2025-01-23 20:44:00">2025-01-23</time> | 24 | <time datetime="2025-02-11 11:40:00">2025-02-11</time> |
| 24 | <a href="/blog/self-hosting-tandoor.html">Self-Hosting Tandoor Recipe Manager</a> | 25 | <a href="/blog/obscura-vpn.html">A Review of Obscura VPN: A Two-Party VPN</a> |
| 25 | </div> | 26 | </div> |
| 26 | 27 | ||
| 27 | <br /> | 28 | <br /> |