Files
gitea-infrastructure/MIRRORING-GUIDE.md
Alex Mikhalev 1637782273 chore: Fix trailing whitespace across project files
Automated fix from pre-commit hooks (trailing-whitespace, end-of-file-fixer).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 12:45:32 +01:00

11 KiB

Repository Mirroring: GitHub ↔ Gitea

Complete guide for setting up mirroring between GitHub and self-hosted Gitea.

Overview

Mirroring keeps two repositories in sync automatically. Choose your direction:

Direction Use Case
GitHub → Gitea GitHub as primary, Gitea as backup/mirror
Gitea → GitHub Gitea as primary, GitHub for visibility/CI
Bidirectional Both accept commits (advanced)

Method 1: Gitea as Mirror (GitHub → Gitea)

Gitea periodically pulls from GitHub. Best for backup scenarios.

Step 1: Create Mirror in Gitea

Via Web Interface:

  1. Go to https://git.terraphim.cloud
  2. Click "+""New Migration"
  3. Select "GitHub"
  4. Enter URL: https://github.com/terraphim/gitea-infrastructure
  5. Authentication:
    • If private repo: Enter GitHub Personal Access Token
    • If public: Leave empty
  6. Check "This repository will be a mirror"
  7. Click "Migrate Repository"

Via Gitea API:

# Get Gitea API token (Settings → Applications → Generate Token)
GITEA_TOKEN="your_gitea_api_token"

# Create mirror
curl -X POST \
  "https://git.terraphim.cloud/api/v1/repos/migrate" \
  -H "Authorization: token ${GITEA_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "clone_addr": "https://github.com/terraphim/gitea-infrastructure",
    "repo_name": "gitea-infrastructure-mirror",
    "repo_owner": "terraphim",
    "mirror": true,
    "auth_token": "your_github_token_if_private"
  }'

Step 2: Configure Mirror Settings

  1. Go to repository SettingsRepository
  2. Scroll to Mirror Settings
  3. Set Synchronization Interval: 8h (or your preference)
  4. Click "Update Mirror"

Step 3: Manual Sync (Optional)

# Trigger immediate sync
curl -X POST \
  "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure-mirror/mirror-sync" \
  -H "Authorization: token ${GITEA_TOKEN}"

Method 2: GitHub as Mirror (Gitea → GitHub)

Push from Gitea to GitHub. Best when Gitea is your primary.

Step 1: Add GitHub Remote to Local Repository

cd /home/alex/infrastructure/gitea_config

# Add GitHub as mirror remote
git remote add github https://github.com/terraphim/gitea-infrastructure.git

# Or use SSH (recommended for automation)
git remote add github git@github.com:terraphim/gitea-infrastructure.git

Step 2: Configure Push Mirroring in Gitea

Option A: Gitea Push Mirror (Native)

  1. In Gitea, go to repository SettingsRepository
  2. Scroll to Mirror Settings
  3. Check "Push Mirror"
  4. Set Git Remote URL: https://github.com/terraphim/gitea-infrastructure.git
  5. Add authentication:
    • Username: Your GitHub username
    • Password/Token: GitHub Personal Access Token
  6. Set Interval: 8h
  7. Click "Add Push Mirror"

Option B: Using Git Hooks (More Control)

Create a post-receive hook in Gitea:

  1. Go to repository SettingsGit Hooks
  2. Find post-receive hook
  3. Edit and add:
#!/bin/bash
# Push to GitHub after receiving commits

# Use deploy key or HTTPS with token
export GIT_SSH_COMMAND='ssh -i /path/to/deploy_key -o StrictHostKeyChecking=no'

git push github main --mirror

echo "Mirrored to GitHub"

Step 3: Test Push Mirroring

# Make a test commit
echo "# Test" >> README.md
git add README.md
git commit -m "test: Mirror sync"

# Push to Gitea
git push origin main

# Check GitHub (should appear within seconds)

Method 3: Bidirectional Mirroring

Both repositories accept commits. Warning: Can cause conflicts!

Architecture

Developer A → Gitea ←→ GitHub ← Developer B
                    ↑___________↓
                    Bidirectional sync

Setup

  1. Set up both mirrors:

    • GitHub → Gitea (Method 1)
    • Gitea → GitHub (Method 2)
  2. Conflict Resolution Strategy:

    • Always use git merge instead of git push --force
    • Set up webhook for immediate sync
    • Have clear contribution guidelines
  3. Webhook-based Immediate Sync:

    In Gitea:

    • Settings → Webhooks → Add Webhook → Gitea
    • Target URL: Your sync service
    • Events: Push

    GitHub → Gitea sync service:

    # sync-service.py (simplified)
    from flask import Flask, request
    import subprocess
    
    app = Flask(__name__)
    
    @app.route('/github-webhook', methods=['POST'])
    def github_hook():
        # Trigger Gitea pull
        subprocess.run(['curl', '-X', 'POST',
            'https://git.terraphim.cloud/api/v1/repos/terraphim/repo/mirror-sync'])
        return 'OK'
    
    @app.route('/gitea-webhook', methods=['POST'])
    def gitea_hook():
        # Trigger GitHub push
        subprocess.run(['git', 'push', 'github', 'main'])
        return 'OK'
    

Method 4: Local Git Configuration (Simplest)

Push to both remotes simultaneously from your local machine.

Setup

cd /home/alex/infrastructure/gitea_config

# Check current remotes
git remote -v
# origin: should be Gitea

# Add GitHub as additional remote
git remote add github https://github.com/terraphim/gitea-infrastructure.git

# Or use SSH:
git remote add github git@github.com:terraphim/gitea-infrastructure.git

Push to Both

# Push to Gitea (origin)
git push origin main

# Push to GitHub
git push github main

Automate with Git Alias

Add to ~/.gitconfig:

[alias]
    pushall = !git push origin $(git branch --show-current) && git push github $(git branch --show-current)
    pa = pushall

Usage:

git pa  # Pushes to both remotes

Automate with Bash Function

Add to ~/.bashrc or ~/.zshrc:

git-push-all() {
    local current_branch=$(git branch --show-current)
    echo "Pushing to all remotes..."
    git push origin "$current_branch"
    git push github "$current_branch"
    echo "✅ Pushed to Gitea and GitHub"
}

alias gpa='git-push-all'

Authentication Setup

GitHub Personal Access Token

  1. Go to GitHub → Settings → Developer settings → Personal access tokens
  2. Generate new token (classic)
  3. Scopes needed:
    • repo (full control of private repositories)
    • workflow (if using GitHub Actions)
  4. Copy token

Use Token in Gitea

When setting up push mirror:

  • Username: Your GitHub username
  • Password: Your Personal Access Token (not your password!)

For automated pushes:

  1. Generate deploy key:
ssh-keygen -t ed25519 -f ~/.ssh/gitea_github_deploy -C "gitea-mirror"
  1. Add public key to GitHub:

    • Repository Settings → Deploy Keys → Add deploy key
    • Paste contents of ~/.ssh/gitea_github_deploy.pub
    • Allow write access
  2. Add private key to Gitea server:

# Copy to Gitea server
scp ~/.ssh/gitea_github_deploy bigbox:~/.ssh/
ssh bigbox "chmod 600 ~/.ssh/gitea_github_deploy"
  1. Configure SSH for GitHub in Gitea:
# Create SSH config
ssh bigbox "cat > ~/.ssh/config << 'EOF'
Host github-mirror
    HostName github.com
    User git
    IdentityFile ~/.ssh/gitea_github_deploy
    StrictHostKeyChecking no
EOF"
  1. Update remote to use SSH:
ssh bigbox "cd ~/gitea-stack && git remote set-url github git@github-mirror:terraphim/gitea-infrastructure.git"

Verification and Monitoring

Check Mirror Status

In Gitea:

  • Repository → Settings → Repository → Mirror Settings
  • Shows last sync time and status

Via API:

# Check mirror status
curl -s \
  "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure-mirror" \
  -H "Authorization: token ${GITEA_TOKEN}" | \
  jq '.mirror_updated, .mirror_interval'

Monitoring Script

Create check-mirror.sh:

#!/bin/bash
# Check if mirrors are in sync

echo "Checking repository sync status..."

# Get latest commit from GitHub
GITHUB_SHA=$(curl -s \
  "https://api.github.com/repos/terraphim/gitea-infrastructure/commits/main" | \
  jq -r '.sha')

# Get latest commit from Gitea
GITEA_SHA=$(curl -s \
  "https://git.terraphim.cloud/api/v1/repos/terraphim/gitea-infrastructure/commits/main" | \
  jq -r '.sha')

if [ "$GITHUB_SHA" == "$GITEA_SHA" ]; then
    echo "✅ Repositories are in sync"
    echo "Latest commit: ${GITHUB_SHA:0:7}"
else
    echo "⚠️  Repositories are OUT OF SYNC"
    echo "GitHub: ${GITHUB_SHA:0:7}"
    echo "Gitea:  ${GITEA_SHA:0:7}"
fi

Troubleshooting

Mirror Not Syncing

Check Gitea logs:

ssh bigbox "docker logs gitea | grep -i mirror"

Test manually:

ssh bigbox
cd ~/gitea-stack
git fetch github
git log HEAD..github/main  # Check if behind

Authentication Failures

GitHub token expired:

  • Generate new token in GitHub
  • Update in Gitea mirror settings

SSH key issues:

ssh bigbox "ssh -T github-mirror"
# Should show: Hi terraphim/gitea-infrastructure! You've successfully authenticated

Conflict Resolution

If repositories diverge:

# On local machine
git fetch origin  # Gitea
git fetch github  # GitHub

# Check differences
git log --left-right --graph --cherry-pick --oneline origin/main...github/main

# Merge changes
git checkout main
git merge origin/main
git merge github/main

# Push to both
git push origin main
git push github main

Best Practices

1. One-Way vs Two-Way

  • Use one-way for most cases (clear primary/secondary)
  • Use two-way only for specific workflows with clear contribution guidelines

2. Sync Frequency

  • Backup mirrors: 24h interval
  • Active development: 1h interval or webhook-triggered
  • CI/CD: Immediate webhook sync

3. Notifications

Set up alerts for sync failures:

  • Gitea webhook on sync failure
  • GitHub Actions monitoring
  • Email notifications

4. Documentation

Document your mirroring strategy:

  • Which repository is primary?
  • Where should PRs be opened?
  • How to handle conflicts?

Quick Reference

Task Command
Check remotes git remote -v
Add GitHub remote git remote add github https://github.com/terraphim/gitea-infrastructure.git
Push to all git push origin main && git push github main
Force sync curl -X POST "https://git.terraphim.cloud/api/v1/repos/terraphim/repo/mirror-sync"
Check status git log origin/main..github/main

Primary: Gitea (self-hosted, private) Mirror: GitHub (backup, CI/CD)

  1. Use Method 2 (Push Mirror) from Gitea to GitHub
  2. Set sync interval: 1 hour
  3. Use SSH authentication with deploy key
  4. Enable GitHub Actions for CI/CD on GitHub side
  5. Keep Gitea as single source of truth for commits

This gives you:

  • Full control on Gitea
  • GitHub as backup
  • Can use GitHub Actions for CI/CD
  • Simple one-way sync (less conflicts)