1. repo工具链组成
项目工程庞大,多人协作开发,如果能够按照边界进行拆分,不仅从逻辑层面进行了解耦,也有利于模块进行独自维护,最小限度地解决问题而降低对他人的影响。
现在在公司采用已搭建好的 repo+gerrit 环境进行代码下载、检视、修改及提交。
想了解一下repo工具统一对多代码仓的管理的方式,以便日后用于自己的项目管理。
大概折腾了一下,把基本的工作流程及方式记录如下。
2. repo工作流
2.1 repo 工具套装
由图所示,repo套装工具主要由三部分构成:
repo script: 用以支撑repo执行各种命令(例如git)的底层python脚本仓。
manifests: 复杂的多项目管理配置XML文件仓,其中的XML文件将指示各个项目将以何种方式进行组织。例如某个项目的git clone URL,分支,目录组织形式。
将上述两个库从server下载到client端的引导脚本 repo boot script — repo。
repo boot script 会通过repo init命令,将 repo script 及 manifests 仓 从server端按照命令参数拉取到client端,并组织在 .repo
目录下。
2.2 项目的Git仓库目录和工作目录
一般来说,一个项目的Git仓库目录(默认为.git目录)是位于工作目录下面的,但是Git支持将一个项目的Git仓库目录和工作目录分开来存放。
.repo
目录组织如下(已省略部分次要项):
.repo
├── manifests
│ └── default.xml
├── manifests.git
├── manifest.xml -> manifests/default.xml
├── project.list
├── project-objects
│ ├── pro_1.git
│ ├── pro_2.git
│ ├── pro_3.git
│ └── test
│ └── pro_3.git
├── projects
│ ├── pro_1.git
│ ├── pro_2.git
│ └── test
│ └── pro_3.git
└── repo
├── .git
├── main.py
...
├── subcmds
│ ├── abandon.py
...
其中,repo script 仓的git仓目录(.git)位于工作目录 .repo/repo
下,而 manifests 仓的git仓目录与工作目录平行位于 .repo
仓下(二者目录独立)。
2.3 项目的git仓
在拉取项目代码后,我们很清晰的可以看到每个项目的工作目录下都有一个git仓目录:
repo_client/
├── pro_1
│ ├── .git
│ ├── f1
│ └── f2
├── pro_2
│ ├── .git
│ ├── f3
│ └── f4
└── test
└── pro_3
├── .git
└── f5
而该git仓目录,并不是真正的项目管理git仓,而仅仅是一些软链接,这些项目真正的git仓,位于 .repo
下project相关的git仓中。
xxxxxxxxx@xxxxxxxxx:~/repo_test/repo_client/pro_1/.git$ ll
total 16
drwxrwxr-x 2 xx 4096 Sep 12 14:13 ./
drwxrwxr-x 3 xx 4096 Sep 12 14:13 ../
lrwxrwxrwx 1 xx 37 Sep 12 14:13 config -> ../../.repo/projects/pro_1.git/config
lrwxrwxrwx 1 xx 49 Sep 12 14:13 description -> ../../.repo/project-objects/pro_1.git/description
-rw-rw-r-- 1 xx 41 Sep 12 14:13 HEAD
lrwxrwxrwx 1 xx 43 Sep 12 14:13 hooks -> ../../.repo/project-objects/pro_1.git/hooks/
-rw-rw-r-- 1 xx 209 Sep 12 14:13 index
lrwxrwxrwx 1 xx 42 Sep 12 14:13 info -> ../../.repo/project-objects/pro_1.git/info/
lrwxrwxrwx 1 xx 35 Sep 12 14:13 logs -> ../../.repo/projects/pro_1.git/logs/
lrwxrwxrwx 1 xx 45 Sep 12 14:13 objects -> ../../.repo/project-objects/pro_1.git/objects/
lrwxrwxrwx 1 xx 42 Sep 12 14:13 packed-refs -> ../../.repo/projects/pro_1.git/packed-refs
lrwxrwxrwx 1 xx 35 Sep 12 14:13 refs -> ../../.repo/projects/pro_1.git/refs/
lrwxrwxrwx 1 xx 46 Sep 12 14:13 rr-cache -> ../../.repo/project-objects/pro_1.git/rr-cache/
lrwxrwxrwx 1 xx 38 Sep 12 14:13 shallow -> ../../.repo/projects/pro_1.git/shallow
lrwxrwxrwx 1 xx 41 Sep 12 14:13 svn -> ../../.repo/project-objects/pro_1.git/svn/
3. manifest.xml组织格式
repo script 仓是repo真正执行指令的python脚本,此处暂不做代码级分析。
manifests 仓中存放的是 复杂的多项目管理配置XML文件,repo仓脚本,根据该仓下的XML配置文件,对不同的项目执行不同的操作,故该仓中的文件,直接决定了众多项目的工作方式。
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<!-- remote element. -->
<!-- several remote element, used to specify different project's default download server -->
<!-- Main Attribute:
┊ ┊fetch:all projects' git URL prefix
-->
<remote name="origin" fetch="/home/m00354437/repo_test/repo_server" />
<!-- default element. all projects' default attribute if project element not specified -->
<!-- Main Attribute:
┊ ┊revision:git branch's name. master or refs/heads/master ...
┊ ┊path: local sub directory used in git clone
┊ ┊sync_j: repo sync threads used
┊ ┊sync_c: True/False. sync specific revision(branch)
┊ ┊sync_s: True/False. sync git's children project
-->
<default remote="origin" revision="master" sync_j="4" />
<!-- project element, name:unique signature pointed to project. -->
<!-- project git URL: ${remote fetch}/${project name} -->
<project name="pro_1" path="pro_1" remote="origin" revision="master" />
<project name="pro_2" path="pro_2" remote="origin" revision="master" />
<project name="test/pro_3" path="test/pro_3" remote="origin" revision="master" />
</manifest>
该XML的主要标签为3个 — remote default project
- remote
设置远程git服务器的属性,主要属性为:
name:远程git服务器的名字;
fetch:所有projects的git URL 前缀;
当然,可以设置多个remote标签,以指示多个remote服务端
- default
设定所有projects的默认属性值,如果在project元素里没有指定一个属性,则使用default元素的属性值。
revision:分支名。master, refs/heads/master or other
path:git clone 的时候,指定本地子目录
sync_j:执行 repo sync 时的线程数
sync_c:是否指定只同步指定branch
sync_s:是否同步git仓下的子项目
- project:
name:唯一的名字标识project,同时也用于生成git仓库的URL。
path: 可选的路径。指定git clone出来的代码存放在本地的子目录。如果没有指定,则以name作为子目录名。
remote: 指定之前在某个remote元素中的name,以确定从哪个server进行clone等操作。
revision: 指定需要获取的git提交点,可以是master, refs/heads/master, tag或者SHA-1值。如果不设置的话,默认下载当前project,当前分支上的最新代码。
【重要】project git URL 组成:${remote fetch}/${project name}.git
这部分非常重要,remote fetch决定了server端地址, project name 包含了项目代码组织结构,故一定确认。
4. 常规实战
- 在repo_test目录下创建两个子目录,repo_server,repo_client
repo_server模拟远端 repo_client模拟本地
- 在repo_server端 git init —bare 4个空git仓:
manifest.git
pro_1.git
pro_2.git
test/pro_3.git
分别clone这4个仓,将 第3节的 xml 修改名为 default.xml 并push到manifest.git;其余3个仓分别touch几个文件并push。
在repo_client下,执行 repo init,进行.repo目录生成,manifests仓及repo script仓的拉取
repo init -u <manifest_repo_url> -b <manifest_repo_branch> -m <manifest_repo_xmlFile> --repo-url=<Repo_repo_url>
- 执行sync 进行代码拉取
repo sync -c --no-tags
- 检查代码目录组织结构,及log信息
参考:
[1] 深层次的讲解repo原理
[2] 搭建Repo服务器
[3] Manifest和Repo使用详解