aboutsummaryrefslogtreecommitdiff
path: root/content/blog/2025-04-05-git-mirror.org
blob: 47e6fbfd9c7c39bc915e47456b9410c2a18ecd47 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
#+date:        <2025-04-05 Saturday 23:04:54>
#+title:       Methodology for Mirroring GitHub Repositories to GitLab for Backup and Synchronization
#+description: Technical steps for setting up automated synchronization and mirroring of source code repositories from GitHub to GitLab for redundancy and repository management.
#+slug:        git-mirror
#+filetags:    :git:mirroring:automation:

This is a short post detailing how I maintained repositories on GitHub and
mirrors on GitLab - including both public and private repositories.

Since GitLab locks pull-only mirrors behing their Premium and Ultimate tiers, I
found a different solution.

* Creating Mirrors

I'll skip the setup and just hit the bullet points:

- I have a plethora of GitHub repositories.
- I used GitLab's mass-import functionality to do the initial import of my
  repositories from GitHub.
- I made sure all of my GitHub repositories were cloned locally in my =~/git=
  directory.

* Setting up Mirror Connections

To start, I navigated to the =~/git= directory, which holds all of the
repositories I have on GitHub and created a shell script.

#+begin_src shell
cd ~/git
nano setup_mirrors.sh
#+end_src

Within this shell script, I created a loop that will open each repository and
add both the GitHub and GitLab SSH-style clone URIs to the =origin= remote.

#+begin_src shell
for repo in */
do
    cd $repo
    git remote set-url origin --push --add git@github.com:ccleberg/${repo%*/}.git
    git remote set-url origin --push --add git@gitlab.com:ccleberg/${repo%*/}.git
    git remote -v
    cd ..
done
#+end_src

Once complete, I created another shell script to open each repository, pull any
remote commits, and push local commits to both remotes.

#+begin_src shell
nano mirror.sh
#+end_src

#+begin_src shell
for repo in */;
do
    cd $repo
    git pull --rebase origin HEAD
    git push
    cd ..
done
#+end_src

Finally, enable execution of both scripts before moving on.

#+begin_src shell
chmod +x setup_mirrors.sh
chmod +x mirror.sh
#+end_src

* Initialize Mirrors

To use the =setup_mirrors.sh= script above, simply execute it from a terminal.

#+begin_src shell
./setup_mirrors.sh
#+end_src

Once complete, each repository /should/ have one fetch URI (GitHub) and two push
URIs (GitHub & GitLab). At this point, any =git pull= or =git fetch= commands
will pull from GitHub and any =git push= commands will send updates to both
GitHub and GitLab.

* Schedule Periodic Checks

To utilize the =mirror.sh= script from the previous step, let's use crontab.

#+begin_src shell
crontab -e
#+end_src

Within crontab, I used the schedule below to ensure the script is executed
daily.

#+begin_src text
0 0 * * * /Users/cmc/git/mirror.sh
#+end_src

This ensures that the =mirror.sh= file is executed daily and will push any local
or GitHub commits to GitLab.

I have tested this by manually running =mirror.sh= and watching the results.
There are edge cases where I will need to intervene and manually resolve merge
conflicts, but it's largely autonomous, so I'm happy with the results.