引言
在大型软件项目中,我们常常需要同时管理几十甚至上百个 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:$PATH3. 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_repo2_test_repo3_test_repomanifest
下面脚本将每个仓库克隆到本地,添加 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 push4.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 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 ""
评论区