Mirroring repositórios: sincronizando entre plataformas

Manter repositórios sincronizados entre diferentes plataformas é uma necessidade comum em fluxos de trabalho modernos de desenvolvimento. Seja para migração de projetos, criação de backups distribuídos ou disponibilização de código em múltiplos serviços como GitHub, GitLab e Bitbucket, o mirroring (espelhamento) de repositórios Git oferece uma solução robusta e eficiente.

1. Conceitos Fundamentais de Mirroring

Mirroring é o processo de criar e manter uma cópia exata de um repositório Git em outro local. Diferente de um fork, que é uma cópia independente com histórico compartilhado, ou de um clone, que pode ser uma cópia de trabalho com branches locais, o mirror busca espelhar fielmente todas as referências do repositório original.

Existem dois tipos principais de mirror:

  • Mirror completo (bare): Cria uma cópia idêntica do repositório, incluindo todas as branches, tags e commits. Ideal para backups e distribuição.
  • Mirror raso (shallow): Copia apenas uma profundidade limitada do histórico, útil para economizar espaço em cenários onde o histórico completo não é necessário.

Casos de uso típicos incluem migração entre plataformas, backup redundante em diferentes regiões geográficas e distribuição de código para equipes que usam serviços distintos.

2. Configuração Inicial do Repositório Fonte

O primeiro passo é clonar o repositório original no formato bare, que contém apenas os objetos Git sem uma árvore de trabalho:

git clone --bare https://github.com/usuario/repositorio-origem.git
cd repositorio-origem.git

Em seguida, adicione o remote de destino:

git remote add --mirror=push destino git@gitlab.com:usuario/repositorio-destino.git

A opção --mirror=push configura o remote para espelhar automaticamente todas as referências durante o push. Verifique as permissões de autenticação, preferencialmente usando SSH keys ou tokens de acesso pessoal:

# Testando a conexão com o destino
git push destino --dry-run

3. Sincronização Manual com git push --mirror

O comando principal para sincronização manual é:

git push --mirror destino

Este comando envia todas as referências locais (branches, tags, commits) para o remote de destino, substituindo completamente o que está lá. Diferente de git push --force --all --tags, que força apenas branches e tags, o --mirror também lida com referências removidas no fonte.

Limitações importantes:

  • Hooks do lado servidor no destino não são transferidos
  • Referências externas (como notas) podem não ser espelhadas
  • O reflog do destino não é atualizado

4. Automação com Scripts e Hooks

Para sincronização periódica, crie um script shell simples:

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

ORIGEM="/caminho/repositorio-origem.git"
DESTINO="git@gitlab.com:usuario/repositorio-destino.git"

cd "$ORIGEM"
git remote update --prune
git push --mirror "$DESTINO"

echo "Sincronização concluída em $(date)"

Configure uma tarefa cron para execução automática:

# Executar a cada hora
0 * * * * /caminho/sync-mirror.sh >> /var/log/git-mirror.log 2>&1

No lado servidor, use hooks post-receive para disparar sincronização imediatamente após cada push:

#!/bin/bash
# .git/hooks/post-receive (no repositório origem)

git push --mirror git@gitlab.com:usuario/repositorio-destino.git

5. Sincronização Bidirecional e Resolução de Conflitos

Para mirror bidirecional, a estratégia exige cuidado redobrado. Um fluxo seguro envolve:

# No mirror local
git fetch origem
git fetch destino
git push --mirror origem
git push --mirror destino

Divergências podem ocorrer se ambas as plataformas receberem commits simultaneamente. Nesse caso:

# Identificar divergências
git log --oneline --left-right origem/master...destino/master

# Resolver manualmente e forçar sincronização
git push --force origem master
git push --force destino master

Para mitigar riscos, mantenha branches de backup:

git branch backup-$(date +%Y%m%d) origem/master
git push origem backup-$(date +%Y%m%d)

6. Ferramentas Especializadas para Mirroring

Além dos comandos nativos, existem ferramentas que facilitam o processo:

  • git-mirror: Script avançado com logging e notificações
  • repo-mirror: Ferramenta multi-plataforma que suporta GitHub, GitLab e Bitbucket
  • Serviços gerenciados: GitHub Actions e GitLab CI/CD oferecem pipelines dedicados para mirroring automático

Exemplo de workflow com GitHub Actions:

name: Mirror para GitLab
on: [push]
jobs:
  mirror:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Push mirror
        run: |
          git remote add gitlab https://gitlab.com/usuario/repositorio.git
          git push --mirror gitlab

7. Monitoramento e Manutenção do Mirror

A manutenção regular garante a integridade do mirror. Execute verificações periódicas:

# Verificar integridade do mirror
git fsck --full

# Verificar consistência das referências
git show-ref --verify refs/heads/master

Configure logs detalhados e alertas para falhas:

#!/bin/bash
# sync-with-log.sh

LOG="/var/log/git-mirror.log"
DATA=$(date "+%Y-%m-%d %H:%M:%S")

echo "[$DATA] Iniciando sincronização" >> "$LOG"

if git push --mirror destino >> "$LOG" 2>&1; then
    echo "[$DATA] Sincronização bem-sucedida" >> "$LOG"
else
    echo "[$DATA] ERRO: Falha na sincronização" >> "$LOG"
    # Enviar alerta (email, Slack, etc.)
fi

8. Boas Práticas e Considerações Finais

Para um processo de mirroring confiável:

  • Política de nomes: Mantenha consistência nos nomes de branches e tags entre plataformas
  • Segurança: Use tokens com escopo mínimo (apenas permissão de push) e realize rotação periódica
  • Documentação: Registre o processo completo, incluindo procedimentos de recuperação
  • Testes: Simule cenários de falha e recuperação regularmente

O mirroring bem configurado proporciona resiliência e flexibilidade ao fluxo de desenvolvimento, garantindo que seu código esteja sempre disponível onde for necessário.

Referências