Don’t Let ‘Cable Breaks’ Disrupt Your Progress: A Guide to Automated Repository Mirroring from GitHub to GitLab and Bitbucket

Git tutorial - IT technology blog
Git tutorial - IT technology blog

Why Bother Syncing Code to Multiple Locations?

After six months of “battling” with an outsourcing project, I learned a hard lesson: never put all your eggs in one basket. Even though GitHub promises 99.9% uptime, in reality, during maintenance or international cable issues, a 20-person team sitting around doing nothing because they can’t push code is a very real possibility.

Additionally, many clients require storage on internal GitLab instances for private CI/CD. Meanwhile, the dev team loves GitHub Actions for its robust ecosystem. This is where repository mirroring becomes the best of both worlds. Your code will appear simultaneously everywhere without having to manually type git push until your hands are tired.

I once escaped a disaster thanks to this habit. A new colleague accidentally git push --force and overwrote the develop branch. Fortunately, the internal GitLab server had been mirroring, allowing me to restore the entire commit history in just 5 minutes. Without that mirror, the whole team would have stayed up all night patching the code back together.

The Concept of Repository Mirroring: More Than Just Copying

Many people confuse adding a second remote with mirroring. The git remote add command is simply adding an address to push code. True mirroring synchronizes everything: from all branches and tags to the entire commit history.

There are two types you need to distinguish:

  • Push Mirroring: The source repository (Source) actively pushes data to the destination repository (Destination) as soon as changes occur.
  • Pull Mirroring: The destination repository periodically “visits” and pulls code from the source.

Method 1: Manual Mirroring via Git CLI (Use for Quick Fixes)

This is the fastest way to sync data without complex setup. We leverage Git’s --mirror flag.

# 1. Clone the source repository with the --mirror flag
git clone --mirror https://github.com/user/repo-goc.git

# 2. Move into the cloned directory
cd repo-goc.git

# 3. Push everything to the destination repository
git push --mirror https://gitlab.com/user/repo-dich.git

Warning: The git push --mirror command is extremely powerful. It will completely overwrite everything at the destination. If the destination has branches that don’t exist at the source, Git will delete them mercilessly.

Method 2: Automation with GitHub Actions (The Optimal Choice)

If GitHub is your “headquarters,” let GitHub Actions automatically push code to GitLab/Bitbucket whenever someone merges a Pull Request. This method is much more professional and hands-off.

Step 1: Set Up Access Permissions

To let the two platforms “talk” to each other, I recommend using SSH keys for higher security than Personal Access Tokens.

  • Create a new SSH key pair (don’t use your personal key).
  • Add the Public Key to the Deploy Keys section (remember to check Write access) on GitLab/Bitbucket.
  • Copy the Private Key into Secrets and variables > Actions on GitHub with the name GITLAB_SSH_PRIVATE_KEY.

Step 2: Configure the Workflow

Create the .github/workflows/mirror.yml file. This script will trigger every time there is a push to the main branches.

name: Mirror to GitLab

on:
  push:
    branches: [ main, develop ]

jobs:
  git-mirror:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout source code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Must fetch full history for mirroring

      - name: Setup SSH Key
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.GITLAB_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan gitlab.com >> ~/.ssh/known_hosts

      - name: Push to GitLab
        run: |
          git remote add gitlab [email protected]:username/project-mirror.git
          git push --force --prune gitlab "refs/remotes/origin/*:refs/heads/*"
          git push --force --tags gitlab

The --prune flag in the script helps clean up branches that have been deleted on GitHub, keeping the destination repository clean.

Method 3: Leverage GitLab’s Built-in Mirroring Feature

If you want to pull code from GitHub (Pull Mirroring), the Free version of GitLab supports this very well. This is the “lazy” but extremely effective way for periodic backups.

  1. Access the project on GitLab, select Settings > Repository.
  2. Open the Mirroring repositories section.
  3. Enter the GitHub URL (Format: https://github.com/user/repo.git).
  4. Select Pull as the mirroring direction.
  5. Fill in the GitHub PAT (Personal Access Token) in the Authentication section.

Typically, the free version of GitLab will update automatically every few hours. If you’re in a hurry, you can click the Refresh button to sync immediately.

“Hard-earned” Lessons for Operation

After setting this up for many large systems, I’ve gathered three important lessons:

1. Stop Infinite Loops

Absolutely do not set up two-way mirroring where A pushes to B and B pushes back to A. Without filters, both sides will continuously trigger each other, hanging the CI/CD system and wasting resources.

2. Handling Large Files (Git LFS)

Standard git push commands ignore large files. If your project contains many assets (images, videos, AI models), ensure Git LFS is installed on both environments and run git lfs fetch --all before mirroring.

3. Synchronizing Permissions

Mirroring code does not mean mirroring access rights. When there are new team members, you need to add them to both platforms if you want them to participate in code reviews or view CI/CD logs on both sides.

Conclusion

Setting up a Mirror Repository is more than just a backup. It’s a smart strategy to leverage the strengths of each platform: use GitHub for task management and use GitLab to run pipelines on your own servers to optimize costs.

Don’t wait until a server incident occurs to scramble for data recovery. It only takes about 15-30 minutes to set up, but the peace of mind it brings to the project is priceless.

Share: