Scripts for setting up and synchronizing two-way mirroring between Git repositories. There are instructions for one-way mirroring below as well.
Sets up a remote Git repository mirror.
Warning: mirroring may destroy revisions in either repository.
git clone --mirror
implies --bare
and sets up the origin remote so that
git fetch
will directly fetch into local branches without merging.
It will force the update, so if remote history has diverged from local,
local changes will be lost.
git push --mirror
is similar: instead of pushing just a branch, it assures
that all references (branches, tags etc) are the same on the remote
end as they are in local, even if this means forced updates or deletion.
It is strongly recommended to protect important branches and tags in the
remote mirror against unintended modification with with a Git update hook,
see example in scripts/git-update-hook-for-protecting-branches-and-tags
.
Copy it to hooks/update
and make it executable with chmod 755 hooks/update
in the remote repository.
Synchronizes the mirror that was previously set up with
scripts/setup-git-mirror.sh
.
This script will be run both from the mirror repository post-receive
hook
and crontab
.
There's locking to assure that two script runs don't step on each other's toes.
Synchronization logs are written to scripts/synchronize-git-mirror.log*
.
Configuration is in scripts/synchronize-git-mirror.config
, see comments there.
Simple one-way mirroring setup:
+------------+ +------------+ +------------+
| | | | | |
| Source | | Mirror | | Target |
| repository <-- pull --+ repository +-- push ---> repository |
| | | | | |
+------------+ +------------+ +------------+
Steps:
-
Add system user, generate key, share the key with source repository owner:
sudo adduser --system gitmirror sudo -u gitmirror ssh-keygen sudo cat /home/gitmirror/.ssh/id_rsa.pub
-
Test that cloning works:
cd /tmp && sudo -u gitmirror git clone git@source-repository.com:example/example.git
-
Create mirror repository:
sudo -u gitmirror mkdir example-mirror && cd example-mirror sudo -u gitmirror git clone --mirror git@source-repository.com:example/example.git cd example.git/ sudo -u gitmirror git remote add --mirror=push target git@target-repository.com:example/example-mirror.git
-
Create synchronization script, test:
cat <<EOF > /tmp/mirror-example.sh #!/bin/bash cd /home/gitmirror/example-mirror/example.git/ git fetch --prune origin git push --mirror target EOF chmod 755 /tmp/mirror-example.sh sudo -u gitmirror cp -a /tmp/mirror-example.sh /home/gitmirror/example-mirror/mirror-example.sh sudo -u gitmirror /home/gitmirror/example-mirror/mirror-example.sh
-
Add synchronization script to
/etc/crontab
(with e.g. 30-minute interval):*/30 * * * * gitmirror /home/gitmirror/example-mirror/mirror-example.sh
GitLab repositories that need two-way synchronization with an origin repository need a different setup.
As GitLab uses hooks to track changes in repositories, a separate satellite repository is needed for two-way mirroring that fetches from the origin repository and pushes to GitLab and vice-versa.
In the following, GitLab Omnibus installation is assumed.
-
Login as the GitLab
git
user in the GitLab server, generate SSH key:sudo su git ssh-keygen
-
Create a dedicated GitLab mirroring account in GitLab web interface, upload the SSH public key into the account profile.
-
Create the mirror project in GitLab web interface, give Master access to the mirroring account.
-
Copy the SSH public key to origin repository SSH authorized keys:
scp ~/.ssh/id_rsa.pub user@origin-repository-host: ssh user@origin-repository-host cat id_rsa.pub >> ~/.ssh/authorized_keys logout
-
(Optional) If origin repository username differs from
git
, setup SSH host alias:cat >> ~/.ssh/config << EOT Host gitmirror-origin-host User user HostName origin-repository-host EOT
-
Assure SSH server accepts connections to
localhost
in GitLab server. -
Setup the mirroring tools workspace for
git
user and configuregit-mirror
:sudo mkdir /var/opt/gitlab/mirroring-tools sudo chown git: /var/opt/gitlab/mirroring-tools sudo su git cd ~/mirroring-tools mkdir utils cd utils git clone https://github.com/mrts/git-mirror.git cd git-mirror/scripts/satellite # change the substituted values below according to your needs sed -i 's#CONF_ORIGIN_URL=.*#CONF_ORIGIN_URL=origin-repository-host:git/repo.git#' \ synchronize-git-repositories-with-satellite.config sed -i 's#CONF_OTHER_URL=.*#CONF_OTHER_URL=localhost:mirror/repo.git#' \ synchronize-git-repositories-with-satellite.config sed -i 's#CONF_GITDIR=.*#CONF_GITDIR=/var/opt/gitlab/mirroring-tools/repo.git#' \ synchronize-git-repositories-with-satellite.config sed -i 's#CONF_OTHER_GITDIR=.*#CONF_OTHER_GITDIR=/var/opt/gitlab/git-data/repositories/mirror/repo.git#' \ synchronize-git-repositories-with-satellite.config
-
Run the setup script:
./setup-synchronize-git-repositories-with-satellite.sh
-
The setup script does the following:
- Sets up the satellite repository with origin and GitLab remotes
- Sets up the
post-receive
hook in GitLab repository to push changes from GitLab to origin - Prints the line that should be added to
crontab
for running the synchronization job.
-
Assure passwordless access works, no password propmts should appear during setup.
-
-
Add the line that was printed in the end of setup scrip run to
crontab
:sudo sh -o noglob -c 'echo "*/1 * * * * git ...path..." >> /etc/crontab'
-
Test and examine logs.
- Verify that all branches are present and contain right commits in GitLab.
- Create a merge request and merge it in GitLab, verify that merge is mirrored to origin immediately.
- Commit to any branch in origin, verify that change is mirrored in GitLab after cron has run.
- Rewrite
master
history and deletemaster
in GitLab, verify that this does not get through to origin and results in error in logs. - Delete and create any other branch in GitLab, verify that delete and create is mirrored to origin immediately.
- Delete and create branches in origin, verify that change is mirrored in GitLab after cron has run.
-
Rejoice :)!
It seems that deleting and creating branches from the GitLab web UI does not
trigger the post-receive
hook in GitLab, so deleted branches will be
resurrected during next update from origin. This problem has been filed as
bug #1156 in the GitLab
issue tracker.