Repo tool do Google: gerenciando múltiplos repositórios como um
1. O que é a Repo tool e por que ela existe
A Repo tool nasceu de uma necessidade concreta no desenvolvimento do Android. Quando o Google começou a gerenciar o código-fonte do Android, enfrentou um desafio monumental: centenas de repositórios Git independentes que precisavam ser coordenados como um único projeto. O Git, por si só, não foi projetado para gerenciar múltiplos repositórios de forma coesa.
A diferença fundamental entre Repo e Git é clara: Git é uma ferramenta de versionamento de código, enquanto Repo é uma ferramenta de orquestração. Repo não substitui Git; ele o coordena. Imagine um maestro (Repo) regendo uma orquestra (Git) onde cada músico toca um instrumento diferente (repositório). O maestro não toca os instrumentos, mas garante que todos estejam na mesma página.
Casos de uso típicos incluem projetos com múltiplos componentes independentes que precisam ser versionados juntos: sistemas embarcados, kernels Linux customizados, frameworks com plugins e, claro, o próprio Android Open Source Project (AOSP).
2. Arquitetura do Repo: manifesto, referências e workspace
O coração do Repo é o arquivo de manifesto, geralmente chamado default.xml. Este arquivo XML define quais repositórios Git fazem parte do projeto, em quais branches ou commits específicos eles devem estar e como devem ser organizados no sistema de arquivos local.
Exemplo de estrutura de manifesto:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="origin"
fetch="https://github.com/minha-org" />
<default revision="main"
remote="origin"
sync-j="4" />
<project path="core/lib"
name="biblioteca-core" />
<project path="services/auth"
name="servico-autenticacao"
revision="v2.1.0" />
<project path="frontend/webapp"
name="aplicacao-web" />
</manifest>
Quando você executa repo init -u <url-do-manifesto>, o Repo baixa o manifesto para o diretório .repo/ e prepara o workspace. O comando repo sync então percorre cada projeto listado no manifesto, clona ou atualiza os repositórios nos diretórios especificados pelo atributo path.
A estrutura do workspace fica assim:
meu-projeto/
├── .repo/
│ ├── manifests/
│ ├── manifest.xml
│ ├── projects/
│ └── repo/
├── core/
│ └── lib/ # repositório "biblioteca-core"
├── services/
│ └── auth/ # repositório "servico-autenticacao"
└── frontend/
└── webapp/ # repositório "aplicacao-web"
O diretório .repo/ contém todo o estado interno do Repo, enquanto os diretórios de trabalho são os repositórios Git normais que você edita diretamente.
3. Comandos fundamentais do dia a dia
Os comandos mais utilizados no dia a dia com Repo são:
repo init e repo sync — O ponto de partida:
repo init -u https://github.com/minha-org/manifestos.git -b stable-v1
repo sync
repo init configura o workspace apontando para um manifesto específico. repo sync baixa ou atualiza todos os repositórios para as revisões especificadas no manifesto.
repo start e repo upload — Trabalhando com branches temáticos:
repo start minha-feature --all
cd core/lib
echo "nova funcionalidade" >> README.md
git commit -a -m "Adiciona descrição da feature"
repo upload
repo start cria um branch com o mesmo nome em todos os projetos. repo upload empacota os commits locais e os envia para revisão (tipicamente integrado com Gerrit).
repo status, repo diff e repo info — Visão consolidada:
repo status
repo diff
repo info --all
repo status mostra o estado de todos os repositórios de uma vez. repo diff exibe mudanças não commitadas em todo o workspace. repo info fornece detalhes sobre cada repositório, como URL remota e branch atual.
4. Gerenciamento de branches e revisões com manifesto
O manifesto permite fixar versões específicas de duas formas: usando branches mutáveis ou commits imutáveis.
Fixando commits específicos:
<project path="core/lib"
name="biblioteca-core"
revision="a1b2c3d4e5f6..." />
Isso garante que todos os desenvolvedores estejam exatamente no mesmo commit, independentemente de novos commits no branch.
Usando branches mutáveis:
<project path="services/auth"
name="servico-autenticacao"
revision="develop" />
Aqui, repo sync sempre trará o HEAD mais recente do branch develop.
Para atualização seletiva, o repo sync respeita as revisões do manifesto. Se você quer atualizar apenas um projeto específico:
repo sync services/auth
Trabalhando com múltiplos manifestos:
repo init -u <url> --manifest-name=release-v2.xml
repo sync
Isso permite ter diferentes manifestos para diferentes cenários: desenvolvimento, staging, produção.
5. Trabalho colaborativo e fluxo de patches
O fluxo típico de contribuição com Repo envolve o repo upload integrado com Gerrit, um sistema de code review. O processo funciona assim:
- Desenvolvedor cria um topic branch com
repo start - Faz alterações em um ou mais repositórios
- Commita localmente com
git commit - Envia para revisão com
repo upload
O repo upload analisa todos os projetos que têm commits não enviados e os empacota como changesets no Gerrit. Cada change pode abranger múltiplos repositórios, mantendo a atomicidade da mudança.
Após a aprovação e merge no Gerrit, o manifesto precisa ser atualizado para refletir as novas revisões. Isso geralmente é feito manualmente ou por scripts de CI/CD.
Conflitos entre repositórios são comuns quando há dependências cruzadas. Por exemplo, se a biblioteca-core muda uma API, o servico-autenticacao que a utiliza pode quebrar. A solução é coordenar as mudanças: atualizar primeiro a biblioteca, depois os dependentes, e só então atualizar o manifesto.
6. Boas práticas e armadilhas comuns
Quando NÃO usar Repo: Para projetos pequenos (menos de 5 repositórios) ou com baixo acoplamento, o Repo adiciona complexidade desnecessária. Git Submodules ou até mesmo scripts simples podem ser mais adequados.
Cuidados com repo sync --force-sync: Este comando força a sincronização mesmo que haja conflitos locais, descartando mudanças não commitadas. Use com extrema cautela:
# Perigoso! Pode perder trabalho não commitado
repo sync --force-sync
Versionamento do manifesto: O manifesto em si deve ser versionado em um repositório Git. Isso permite rastreabilidade e rollback:
# No repositório de manifestos
git tag release-v2.1.0
repo init -u <url> --repo-rev=release-v2.1.0
7. Comparação com alternativas do ecossistema Git
Repo vs. Git Submodules: Submodules são mais leves e nativos do Git, mas têm workflow complexo para contribuição. Repo oferece repo upload e gerenciamento centralizado de revisões, ideal para equipes grandes.
Repo vs. Git Subtree: Subtree incorpora o histórico de um repositório dentro de outro, facilitando o desenvolvimento local, mas poluindo o histórico do repositório principal. Repo mantém os repositórios separados, com histórico independente.
Repo vs. Monorepo: Monorepo (um único repositório gigante) simplifica dependências e refatorações, mas escala mal em termos de ferramentas e permissões. Repo permite escalar horizontalmente com repositórios independentes, mantendo a coordenação.
8. Cenário prático: configurando um projeto multi-repositório do zero
Vamos criar um projeto com três repositórios interdependentes: uma biblioteca core, um serviço de autenticação e uma aplicação web.
Passo 1: Crie o manifesto
Crie um repositório Git chamado manifestos e adicione default.xml:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="github"
fetch="https://github.com/minha-org/" />
<default revision="main"
remote="github"
sync-j="4" />
<project path="core/lib"
name="biblioteca-core" />
<project path="services/auth"
name="servico-autenticacao" />
<project path="frontend/webapp"
name="aplicacao-web" />
</manifest>
Commite e faça push para o GitHub.
Passo 2: Inicialize o workspace
mkdir meu-projeto && cd meu-projeto
repo init -u https://github.com/minha-org/manifestos.git
repo sync
Agora você tem os três repositórios clonados nos diretórios especificados.
Passo 3: Fluxo completo de desenvolvimento
# Cria branch temático em todos os projetos
repo start adiciona-login --all
# Modifica a biblioteca core
cd core/lib
echo "função de hash de senha" >> lib.py
git commit -a -m "Adiciona hash de senha seguro"
# Modifica o serviço de autenticação
cd ../../services/auth
echo "usa hash da biblioteca core" >> auth.py
git commit -a -m "Integra hash de senha no serviço"
# Envia ambos para revisão
repo upload
Passo 4: Atualize o manifesto após aprovação
Após os merges, descubra os novos hashes dos commits:
cd core/lib
git rev-parse HEAD
# Saída: f1e2d3c4b5a6...
cd ../../services/auth
git rev-parse HEAD
# Saída: a6b5c4d3e2f1...
Atualize o default.xml com essas revisões:
<project path="core/lib"
name="biblioteca-core"
revision="f1e2d3c4b5a6..." />
<project path="services/auth"
name="servico-autenticacao"
revision="a6b5c4d3e2f1..." />
Commite e faça push do manifesto atualizado. Agora todos os desenvolvedores que rodarem repo sync terão exatamente as mesmas versões.
Referências
- Documentação oficial do Repo tool — Repositório oficial da ferramenta Repo, com código fonte e instruções de instalação
- Android Open Source Project: Repo command reference — Guia oficial do Google sobre comandos Repo no contexto do AOSP
- Gerrit Code Review - Repo Upload — Documentação sobre integração entre Repo e Gerrit para code review
- Repo Tool Tutorial: Managing Multiple Git Repositories — Tutorial da Atlassian explicando conceitos e comandos básicos do Repo
- Git Submodules vs Repo Tool: A Comparison — Discussão técnica no Stack Overflow comparando Submodules e Repo tool
- Managing Android Source with Repo — Artigo da eLinux.org sobre gerenciamento de código Android com Repo