目 录CONTENT

文章目录

代码仓管理:repo 和 manifest

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

引言

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

1. 什么是 repo?

Repo 是一个基于 Git 的仓库管理工具,它本身并没有替代 Git,而是通过一个 manifest 清单文件 来描述多个 Git 仓库的组织方式,并提供一系列命令批量操作这些仓库。最著名的应用场景就是 Android 源码——AOSP 由数百个独立 Git 仓库组成,开发者通过 repo initrepo 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 并推送到 maindev1dev2 三个分支。

#!/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 仓库,为 dev1dev2 分支分别创建各自的 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_repo2_test_repo3_test_repo,并且每个仓库都处于 dev1 分支上。

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

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

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

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

除了 initsync,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

评论区