How to mirror a Git repository

Mirroring Git repositories creates exact copies including all branches, tags, and refs for backup, migration, or multi-location synchronization. With over 25 years of software development experience and as the creator of CoreUI, I’ve mirrored numerous repositories for disaster recovery and platform migrations. Git mirror cloning copies complete repository history and references, maintaining an exact replica that can be kept synchronized. This approach ensures complete backup coverage and enables seamless repository migration between hosting platforms.

Use git clone –mirror to create exact repository copies with all branches and tags for backup and migration.

Basic repository mirror:

# Create mirror clone
git clone --mirror https://github.com/user/original-repo.git

# This creates original-repo.git directory
cd original-repo.git

# Push mirror to new location
git push --mirror https://github.com/user/new-repo.git

Mirror with authentication:

# Clone from private repository
git clone --mirror https://username:[email protected]/user/repo.git

# Or use SSH
git clone --mirror [email protected]:user/repo.git

# Push to new location
cd repo.git
git push --mirror [email protected]:user/repo.git

Keep mirror synchronized:

# In mirror directory
cd original-repo.git

# Fetch all changes from original
git fetch --prune origin

# Push updates to mirror
git push --mirror https://github.com/user/mirror-repo.git

# Or create script for automation

Automated sync script:

#!/bin/bash
# sync-mirror.sh

MIRROR_DIR="/path/to/mirror/repo.git"
SOURCE_URL="https://github.com/user/source-repo.git"
MIRROR_URL="https://github.com/user/mirror-repo.git"

cd "$MIRROR_DIR" || exit 1

echo "Fetching from source..."
git fetch --prune origin

echo "Pushing to mirror..."
git push --mirror "$MIRROR_URL"

echo "Mirror synchronized: $(date)"

Mirror multiple repositories:

#!/bin/bash
# mirror-repos.sh

REPOS=(
  "repo1"
  "repo2"
  "repo3"
)

MIRROR_BASE="/path/to/mirrors"
SOURCE_ORG="github.com/source-org"
MIRROR_ORG="gitlab.com/mirror-org"

for repo in "${REPOS[@]}"; do
  echo "Mirroring $repo..."

  # Create mirror if doesn't exist
  if [ ! -d "$MIRROR_BASE/$repo.git" ]; then
    git clone --mirror "https://$SOURCE_ORG/$repo.git" "$MIRROR_BASE/$repo.git"
  fi

  cd "$MIRROR_BASE/$repo.git"

  # Sync
  git fetch --prune origin
  git push --mirror "https://$MIRROR_ORG/$repo.git"
done

Convert mirror to regular repository:

# Clone mirror as regular repo
git clone /path/to/mirror/repo.git regular-repo

cd regular-repo

# Set up remote
git remote rename origin upstream
git remote add origin https://github.com/user/new-repo.git

# Push to new remote
git push -u origin main

Mirror bare repository:

# Clone as bare repository
git clone --bare https://github.com/user/repo.git repo.git

# Bare vs Mirror:
# --bare: Creates bare repo without remote configuration
# --mirror: Creates bare repo WITH remote configuration for push

# Convert bare to mirror
cd repo.git
git config --bool core.bare true
git config --add remote.origin.mirror true

Backup strategy:

#!/bin/bash
# backup-repositories.sh

BACKUP_DIR="/backups/git-repos"
DATE=$(date +%Y%m%d)
BACKUP_PATH="$BACKUP_DIR/$DATE"

mkdir -p "$BACKUP_PATH"

REPOS=(
  "https://github.com/user/repo1.git"
  "https://github.com/user/repo2.git"
)

for repo in "${REPOS[@]}"; do
  repo_name=$(basename "$repo" .git)
  echo "Backing up $repo_name..."

  git clone --mirror "$repo" "$BACKUP_PATH/$repo_name.git"

  # Create tarball
  cd "$BACKUP_PATH"
  tar -czf "$repo_name.tar.gz" "$repo_name.git"
  rm -rf "$repo_name.git"
done

echo "Backup completed: $BACKUP_PATH"

Migration between platforms:

# Migrate from GitHub to GitLab

# 1. Mirror clone
git clone --mirror https://github.com/user/repo.git

cd repo.git

# 2. Push to new platform
git push --mirror https://gitlab.com/user/repo.git

# 3. Update local clones
# On developer machines:
git remote set-url origin https://gitlab.com/user/repo.git
git fetch origin

Incremental mirror updates:

# Cron job for continuous sync
# crontab -e
# 0 * * * * /path/to/sync-mirror.sh >> /var/log/git-mirror.log 2>&1

#!/bin/bash
# sync-mirror.sh

MIRROR_DIR="/mirrors/repo.git"
LOCK_FILE="/tmp/mirror-sync.lock"

# Prevent concurrent runs
if [ -f "$LOCK_FILE" ]; then
  echo "Sync already running"
  exit 1
fi

touch "$LOCK_FILE"

cd "$MIRROR_DIR" || exit 1

# Fetch updates
git fetch --prune origin || {
  echo "Fetch failed"
  rm "$LOCK_FILE"
  exit 1
}

# Push to mirrors
git push --mirror mirror1 || echo "Mirror1 push failed"
git push --mirror mirror2 || echo "Mirror2 push failed"

rm "$LOCK_FILE"
echo "Sync completed: $(date)"

Best Practice Note

Use –mirror flag to copy all refs including branches, tags, and notes. Mirror clones are bare repositories and cannot be used for development. Use –prune when fetching to remove deleted branches. Automate mirror synchronization with cron jobs. Verify mirror integrity after initial setup. Use authentication tokens for private repositories. Keep mirrors in separate physical locations for disaster recovery. This is how we mirror CoreUI repositories—automated synchronization with –mirror flag ensuring complete backup of all branches, tags, and history for disaster recovery and platform migration.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author

Subscribe to our newsletter
Get early information about new products, product updates and blog posts.
What Does javascript:void(0) Mean?
What Does javascript:void(0) Mean?

How to Hide Scrollbar with CSS
How to Hide Scrollbar with CSS

How to force a React component to re-render
How to force a React component to re-render

How to dynamically add, remove, and toggle CSS classes in React.js
How to dynamically add, remove, and toggle CSS classes in React.js

Answers by CoreUI Core Team