目 录CONTENT

文章目录

代码仓管理:repo 和 manifest

TalentQ
2026-05-20 / 0 评论 / 0 点赞 / 19 阅读 / 0 字

引言

在大型软件项目中,我们常常需要同时管理几十甚至上百个 Git 仓库。如果每个仓库都手动 clone、pull、checkout,不仅效率低下,还容易出错。Google 开发的 repo 工具正是为了解决这一痛点而生。

1. 什么是 repo?

Repo 是一个基于 Git 的仓库管理工具,它本身并没有替代 Git,而是通过一个 manifest 清单文件 来描述多个 Git 仓库的组织方式,并提供一系列命令批量操作这些仓库。最著名的应用场景就是 Android 源码——AOSP 由数百个独立 Git 仓库组成,开发者通过 repo init 和 repo sync 即可一键下载所有代码。

2. 安装 repo

推荐使用清华源下载:

curl -L https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o repo
chmod +x repo

有个好习惯是,在用户目录下创建 .local/bin/ 目录,用来放置该用户自己的一些可执行工具:

mkdir -p ~/.local/bin
mv repo ~/.local/bin/

并将以下内容写入到 ~/.bashrc 文件中。

# add env path
export PATH=$HOME/.local/bin:$PATH

3. manifest 清单文件

Manifest 是一个 XML 文件(通常命名为 default.xml),它定义了:

  • 所有 Git 仓库的远程地址(remote)

  • 每个仓库的默认分支或版本(revision)

  • 每个仓库的本地存放路径(path)

  • 以及其他同步行为(如并发数 sync-j)

一个典型的 manifest 文件结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch="git@github.com:ManifestDemo" />
  <default revision="main" remote="origin" sync-j="4" />
  <project name="app" path="app" />
  <project name="libs/common" path="libs/common" />
</manifest>
  • <remote>:定义远程仓库的别名和 fetch URL。fetch="git@github.com:ManifestDemo" 表示仓库的 URL 路径。

  • <default>:为所有 project 设置默认值,revision 即分支名或 commit hash。

  • <project>:每个需要管理的 Git 仓库,name 对应远程仓库名,path 为本地工作区中的相对路径。

你可以将 manifest 文件存放在一个单独的 Git 仓库中(通常命名为 manifest),通过分支来管理不同配置。

4. 实战:用 repo 管理三个测试仓库

为了更直观地理解,我们从头搭建一个示例:在 GitHub 上创建 3 个代码仓库和一个 manifest 仓库,然后使用 repo 批量同步。

4.1 步骤一:创建仓库并初始化内容

假设我们已经有了一个 GitHub 组织 ManifestDemo,在其下创建四个仓库:

  • 1_test_repo

  • 2_test_repo

  • 3_test_repo

  • manifest

下面脚本将每个仓库克隆到本地,添加 README 并推送到 main、dev1、dev2 三个分支。

#!/bin/bash
repo_list=("1_test_repo" "2_test_repo" "3_test_repo" "manifest")

# 克隆所有仓库
for repo in "${repo_list[@]}"; do
    git clone git@github.com:ManifestDemo/${repo}.git
done

# 为每个仓库添加 README 并推送到 main 分支
for repo in "${repo_list[@]}"; do
    cd ${repo}
    echo "# ${repo}" > README.md
    git add README.md
    git commit -m "first commit"
    git branch -M main
    git push -u origin main
    cd ..
done

# 创建 dev1、dev2 分支并推送
for repo in "${repo_list[@]}"; do
    cd ${repo}
    git checkout -b dev1
    echo "# ${repo}:dev1" > README.md
    git add README.md
    git commit -m "first commit for dev1"
    git push -u origin dev1

    git checkout -b dev2
    echo "# ${repo}:dev2" > README.md
    git add README.md
    git commit -m "first commit for dev2"
    git push -u origin dev2

    git checkout main
    cd ..
done

执行后,每个仓库都有三个分支,且不同分支的 README 内容不同。

4.2 步骤二:编写 manifest 文件

进入 manifest 仓库,为 dev1 和 dev2 分支分别创建各自的 default.xml。

cd manifest
git checkout dev1
cat > default.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch="git@github.com:ManifestDemo" />
  <default revision="dev1" remote="origin" sync-j="4" />
  <project name="1_test_repo" path="1_test_repo" />
  <project name="2_test_repo" path="2_test_repo" />
  <project name="3_test_repo" path="3_test_repo" />
</manifest>
EOF
git add default.xml
git commit -m "Add default.xml for dev1"
git push

git checkout dev2
cat > default.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch="git@github.com:ManifestDemo" />
  <default revision="dev2" remote="origin" sync-j="4" />
  <project name="1_test_repo" path="1_test_repo" />
  <project name="2_test_repo" path="2_test_repo" />
  <project name="3_test_repo" path="3_test_repo" />
</manifest>
EOF
git add default.xml
git commit -m "Add default.xml for dev2"
git push

4.3 步骤三:使用 repo 初始化并同步

现在,我们在一个干净的目录中演示 repo 的强大之处。

# 初始化 repo,使用 manifest 仓库的 dev1 分支
repo init -u git@github.com:ManifestDemo/manifest.git -b dev1
# 可以使用清华源
# repo init -u git@github.com:ManifestDemo/manifest.git -b dev1 --repo-url=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo

# 同步所有仓库
repo sync

执行完毕后,工作区中会出现三个文件夹:1_test_repo、2_test_repo、3_test_repo,并且每个仓库都处于 dev1 分支上。

如果想切换到 dev2 对应的代码集合,只需要重新 init 并 sync:

repo init -u git@github.com:ManifestDemo/manifest.git -b dev2
repo sync

此时所有仓库会自动切换到 dev2 分支。

4.4 步骤四:日常使用 repo 命令

除了 init 和 sync,repo 还提供许多实用命令:

命令

作用

repo sync

同步所有仓库(相当于 git pull --rebase)

repo start <branch> --all

在所有仓库上创建新分支进行开发

repo status

查看所有仓库的修改状态

repo diff

查看所有仓库的差异

repo forall -c <git command>

在每个仓库中执行任意 Git 命令

repo upload

将代码提交到 Gerrit 代码审查系统(AOSP 常用)

例如,要在所有仓库中查看当前分支,可以运行:

repo forall -c "git branch --show-current"

5. 多分支管理与团队协作

通过 manifest 仓库的不同分支,你可以轻松管理多种配置:

  • release/1.0 分支:manifest 指向稳定版本的 commit hash 或 release 分支。

  • dev 分支:manifest 指向开发分支的最新代码。

  • feature/xxx 分支:manifest 指向实验性仓库的特定分支。

每个团队成员只需 repo init -b 对应的 manifest 分支,就能获得一致的代码视图。这种模式非常适合大型团队和持续集成场景。

总结

  • repo 是 Git 多仓库管理的利器,尤其适合百仓级别的项目。

  • manifest 文件以 XML 形式描述仓库集合,并可以独立进行版本控制。

  • 通过切换 manifest 仓库的分支,可以轻松切换整个项目的基线。

如果你还在为管理十几个 Git 仓库而手动编写脚本,不妨试试 repo + manifest,让代码管理回归简单。

💡 小贴士:国内用户使用 repo 时,建议始终指定 --repo-url="https://mirrors.tuna.tsinghua.edu.cn/git/git-repo" ,否则首次初始化可能会很慢。也可以直接将--repo-url写入环境变量,参考清华源。

参考测试脚本

#!/bin/bash

repo_list=("1_test_repo" "2_test_repo" "3_test_repo" "manifest")

# Create 3 test repositories and 1 manifest repository on Github.
## 1_test_repo
## 2_test_repo
## 3_test_repo
## manifest

# Clone all repositories into local workspace.
for repo in "${repo_list[@]}"; do
    git clone git@github.com:ManifestDemo/${repo}.git
done

# Add README.md for all repositories.
for repo in "${repo_list[@]}"; do
    cd ${repo}
    echo "# ${repo}" > README.md
    git add README.md
    git commit -m "first commit"
    git branch -M main
    git push -u origin main
    cd ..
done

# Suppose there are 2 developement branches.
for repo in "${repo_list[@]}"; do
    cd ${repo}

    git checkout -b dev1
    echo "# ${repo}:dev1" > README.md
    git add README.md
    git commit -m "first commit for dev1"
    git push -u origin dev1

    git checkout -b dev2
    echo "# ${repo}:dev2" > README.md
    git add README.md
    git commit -m "first commit for dev2"
    git push -u origin dev2

    git checkout main
    cd ..
done

# Create default.xml for manifest repository.
cd manifest

git checkout dev1
cat > default.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch="git@github.com:ManifestDemo" />
  <default revision="dev1" remote="origin" sync-j="4" />
  <project name="1_test_repo" path="1_test_repo" />
  <project name="2_test_repo" path="2_test_repo" />
  <project name="3_test_repo" path="3_test_repo" />
</manifest>
EOF
git add default.xml
git commit -m "Add default.xml for dev1"
git push

git checkout dev2
cat > default.xml << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
  <remote name="origin" fetch="git@github.com:ManifestDemo" />
  <default revision="dev2" remote="origin" sync-j="4" />
  <project name="1_test_repo" path="1_test_repo" />
  <project name="2_test_repo" path="2_test_repo" />
  <project name="3_test_repo" path="3_test_repo" />
</manifest>
EOF
git add default.xml
git commit -m "Add default.xml for dev2"
git push

echo -e "\n⭐ Now you can run below commands in empty workspace.\n"
echo -e "\t repo init -u git@github.com:ManifestDemo/manifest.git -b dev1 --repo-url=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo"
echo -e "\t repo sync"
echo ""

0

评论区