一、Repo介绍
官方的定义:Repo是谷歌用Python脚本写的调用git的一个脚本,可以实现管理多个git库。
repo这个工具,是一个脚本,这个脚本是对git库的管理(对git常用的功能进行抽象)。
二、安装Repo
以下步骤已经通过脚本实现:install_for_current_user.shinstall_for_system.sh
1、下载 repo
注意:我直接下载(安装)到/bin
或/usr/bin
目录下
#谷歌官方连接
sudo curl https://storage.googleapis.com/git-repo-downloads/repo -o /bin/repo
#国内清华镜像站
sudo curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o /bin/repo
也可以在自己的用户主目录下创建一个隐藏的文件夹:mkidr ~/.local/bin
#谷歌官方连接
curl https://storage.googleapis.com/git-repo-downloads/repo -o ~/.local/bin
#国内清华镜像站
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/.local/bin
注意:其实下载下来的repo文件只是一个使用Python编写的引导脚本(Google 称之为 Repo launcher,本质上是一个python脚本,可以使用vim打开的),完整的repo(即,repo的主体部分)还没有下载。
2、赋予可执行权限
sudo chmod a+x /bin/repo
3、添加环境变量
注意:因为网络问题,repo脚本中默认的URL不能直接访问,所以需要设置一个国内能访问的URL,去下载repo的主体部分,如图:
如向系统添加环境变量:在
/etc/profile
中添加#指定repo的url
export REPO_URL=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/ #首次定义变量一定要使用export
如向个人终端环境中添加环境变量: ```bash
指定repo的url
echo “export REPO_URL=https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/“ >> ~/.bashrc
如果
echo ‘PATH=$PATH:~/.bin’ >> ~/.bashrc #PATH变量已经在系统中定义,无需使用export
<a name="uopis"></a>
### 4、初始化
前面已经说了下载下来的repo只是一个引导脚本,当执行repo init的时候才会下载repo的主体部分,并存放在当前目录的.repo/repo目录下。
这里就会涉及到一个问题,repo的主体部分是从哪里下载的?其实查看repo的引导脚本(/usr/local/bin/repo)可以发现,repo主体部分默认从[https://gerrit.googlesource.com/git-repo](https://gerrit.googlesource.com/git-repo)获取(即,执行repo init命令时,不设置--repo-url选项),这个网站需要科学上网才可以访问。
解决该问题可以使用其他镜像源来获取,例如使用清华源。具体执行上有多种方式,下面列举两种方式供参考:<br />方式一:<br />每次执行repo init时,增加选项--repo-url=[https://gerrit-googlesource.lug.ustc.edu.cn/git-repo](https://gerrit-googlesource.lug.ustc.edu.cn/git-repo),如:
```bash
repo init --repo-url=https://gerrit-googlesource.lug.ustc.edu.cn/git-repo
方式二:(建议)
设置环境变量REPO_URL,第3节,添加环境变量部分;然后直接执行:
repo init
三、.repo目录下的文件介绍
文件 | 说明 |
---|---|
manifests文件夹 | manifest仓库(清单库)内容,即repo init的-u选项对应的仓库 |
manifests.git文件夹 | manifest仓库(清单库)的.git目录 |
manifest.xml文件 | 指明当前生效的Manifest文件,即repo init的-m选项对应的参数(没有该选项时默认为default.xml) |
repo文件夹 | repo 命令的主体,包含了全部的 repo 命令 |
1、manifest
Repo 管理的核心就在于 Manifest(清单),每个采用 repo 管理的复杂多仓库项目都需要一个对应的 manifest 仓库,manifest仓库其实就是存放manifest文件的仓库,实际上可以是任意仓库,只要该仓库中存在repo init命令-m选项指定的manifest文件即可,清单库命名为manifest只不过是一种约定俗成的写法罢了。如 openHarmony 的 manifest ,此仓库用来存储所有子仓库的配置信息,repo 也是读取此仓库的配置文件来进行管理操作。里面的配置就是 xml 定义的结构,一般有两个主要的配置:子仓库用到的仓库地址(remote)、子仓库详细配置信息(project)。manifest仓库一般都会有一个default.xml文件,该文件为默认的manifest文件,如下:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote fetch="."
name="origin"
review="https://openharmony.gitee.com/openharmony/"/>
<default remote="origin"
revision="master"
sync-j="4" />
<project name="miscservices_inputmethod"
path="base/miscservices/inputmethod"
groups="default,ohos:standard,ohos:system"/>
......
......
<project name="build_lite" path="build/lite" groups="default,ohos:mini,ohos:small,ohos:standard,ohos:system,ohos:chipset">
<linkfile dest="build.py" src="build.py"/>
</project>
......
......
</manifest>
(1)remote
远程仓库地址配置,可以多个。
- name: 名字,也用于子仓库的 git remote 名称(.git/config 里的 remote)
- alias: 别名,可省略,建议设为 origin, 设置了那么子仓库的 git remote 即为此名,方便不同的 name 下可以最终设置生成相同的 remote 名称
- fetch: 仓库地址前缀,即 project 的仓库地址为: remote.fetch + project.name
- pushurl: 一般可省略,省略了则直接用 fetch
- review: Gerrit code review 的地址,如果没有用 Gerrit 则不需要配置(也就不能用 repo upload 命令了)
- revision: 使用此 remote 的默认分支
这里的 fetch 遇到个坑,git@github.com:group2/ 这样 git scheme 开头的地址会有问题(ssh/https 的正常),最终子仓库在本地的 remote 地址一直是 manifest 的地址拼上 fetch 再加 project 的 name (manifest.git_path + remote.fetch + project.name)。最终发现是 git-repo 里的代码 manifest_xml.py 有问题,需要 fix 下,简单的把 78 行注释掉,然后推到自己的仓库,指定下系统环境变量:
# repo 脚本会使用此变量的地址
(2)project
子项目仓库配置,可以多个。
- path: repo sync 同步时,相对于根目录的子仓库文件夹路径
- name: 子仓库的 git 仓库名称
- group: 分组
- revision: 使用的分支名
- clone-depth: 仓库同步 Git 的 depth
(3)copyfile
- project 的子节点属性.
- src: project 下的相对路径
- dest: 整个仓库根路径下的相对路径
(4)linkfile
project 的子节点属性,类似 copyfile,只是把复制文件变为创建链接文件。
(5)efault
project 没有设置属性时会使用的默认配置,常用的是 remote 和 revision。
(6)其他
其他现在暂时用的较少,详细完整的 manifest 格式说明请看官方文档。 了解了 Repo 下的 Manifest 配置仓库的概念后就可以根据自己的项目来创建了!
2、local_manifest
local_manifest 简单说就是一个比 repo init 时设置的 manifest 有更高优先级的本地配置,一般用在不改动远程 manifest 配置又想设置到本地的专属配置时用得到。版本高一点的 repo 下,在工作根目录新建配置文件即可: .repo/local_manifests/local_manifest.xml
有一点需要注意的是如果需要覆盖主 manifest 文件已有 project 的配置那么需要先 remove-project 才行,不然会报错:
fatal: duplicate path project_name in .repo/manifest.xml
fix :
<remove-project name="project_name" />
<!-- 再重写 project 配置 -->
<project path="xxx" name="xxx" revision="xxxx" remote="xxxx" />
四、Repo常用指令
repo init -u yout_manifest_git_url 初始化了你的项目 repo 工作区后,repo sync,就可以进入正常的特性开发状态了。按照一般使用顺序说明下需要使用到的常用命令(尝试使用的 repo workflow )。
repo init:初始化
repo init -u your_project_git_url
常用选项:
-b 选取的 manifest 仓库分支,默认 master
-m 选取的默认配置文件,默认 default.xml
--depth=1 git clone 的深度,一般如在 Jenkins 上打包时可用,加快代码 clone 速度
--repo-url=URL 使用自定义的 git-repo 代码,如前面说到的 fix 了 bug 的 git-repo
--no-repo-verify 不验证 repo 的源码,如果自定义了 repo url 那么这个一般也加上
repo sync
repo sync [<project>...]
常用选项:
-d:将指定项目切换回清单修订版本。如果项目当前属于某个主题分支,但只是临时需要清单修订版本,则此选项会有所帮助。
-s:同步到当前清单中清单服务器元素指定的一个已知的良好版本。
-f:即使某个项目同步失败,系统也会继续同步其他项目。
-t:使用对应 tag 里的 manifest 文件
-m:手动指定当前操作使用哪个 manifest 文件
--force-sync:如果需要,强制覆盖现有的 git 目录指向不同的对象目录。此操作可能会导致数据丢失
初始化好一个 repo 工作目录后下一步就是把代码同步下来了,该命令用来下载新的更改并更新本地环境中的工作文件。如果您在未使用任何参数的情况下运行 repo sync,则该操作会同步所有项目(所有项目是指manifest文件中所有的project元素)的文件。
运行repo sync 后,将出现以下情况:
如果目标项目从未同步过,则 repo sync 相当于 git clone。远程代码库中的所有分支都会复制到本地项目目录中。
如果目标项目已同步过,则 repo sync 相当于以下命令:
git remote update
git rebase origin/<BRANCH>
其中
如果 git rebase 操作导致合并冲突,那么您需要使用普通 Git 命令(例如 git rebase —continue)来解决冲突。
repo sync 运行成功后,指定项目中的代码会与远程代码库中的代码保持同步。
repo start 创建主题分支
命令格式:
repo start <newbranchname> [--all | <project>...]
常用选项:
<newbranchname> 参数应简要说明您尝试对项目进行的更改。
<project> 指定了将参与此主题分支的项目。
注意:.是一个非常实用的简写形式,用来代表当前工作目录中的项目。
创建并切换分支。刚克隆下来的代码是没有分支的,repo start实际是对git checkout -b命令的封装。
为指定的项目或所有的项目(若使用-all),以清单文件中为设定的分支,创建特定的分支。
这条指令与git checkout -b 还是有很大区别的。
git checkout -b 是在当前所在的分支的基础上创建特性分支。
repo start 是在清单文件设定的分支的基础上创建特性分支。
repo status
命令格式:
repo status [<project>...]
查看文件状态。对于每个指定的项目,将工作树与临时区域(索引)以及此分支 (HEAD) 上的最近一次提交进行比较。在这三种状态存在差异之处显示每个文件的摘要行。
要仅查看当前分支的状态,请运行 repo status。系统会按项目列出状态信息。对于项目中的每个文件,系统使用两个字母的代码来表示:
在第一列中,大写字母表示临时区域与上次提交状态之间的不同之处。
字母 | 含义 | 描述 |
---|---|---|
- | 无更改 | HEAD 与索引中相同 |
A | 已添加 | 不存在于 HEAD 中,但存在于索引中 |
M | 已修改 | 存在于 HEAD 中,但索引中的文件已修改 |
D | 已删除 | 存在于 HEAD 中,但不存在于索引中 |
R | 已重命名 | 不存在于 HEAD 中,但索引中的文件的路径已更改 |
C | 已复制 | 不存在于 HEAD 中,已从索引中的另一个文件复制 |
T | 模式已更改 | HEAD 与索引中的内容相同,但模式已更改 |
U | 未合并 | HEAD 与索引中的内容相同,但模式已更改 |
在第二列中,小写字母表示工作目录与索引之间的不同之处。
字母 | 含义 | 描述 |
---|---|---|
- | 新/未知 | HEAD 与索引中相同 |
m | 已修改 | 存在于索引中,也存在于工作树中(但已修改) |
d | 已删除 | 存在于索引中,不存在于工作树中 |
两个表示状态的字母后面,显示文件名信息。如果有文件重名还会显示改变前后的文件名及文件的相似度。
repo checkout
repo checkout <branchname> [<project>...]
切换分支。 实际上是对git checkout命令的封装,但不能带-b参数,所以不能用此命令来创建特性分支。
该命令等同于:repo forall [
repo branch
该命令等同于repo branches
repo branches [<project>...]
汇总当前所有可用的主题分支。
repo diff
repo diff [<project>...]
查看工作区文件差异。实际是对git diff命令的封装,用于分别显示各个项目或指定项目工作区下的文件差异。在 commit 和工作目录之间使用 git diff 显示明显差异的更改。
repo stage
repo stage -i [<project>...]
常用选项:
-i:表示git add --interactive命令中的--interactive,给出一个界面供用户选择。
把文件添加到index表中。实际上是对git add —interactive命令的封装,用于挑选各个项目中的改动以加入暂存区。
repo forall
repo forall [<project>...] -c <command> [<arg>...]
常用选项:
-c:要运行的命令和参数,即shell命令。此命令会通过 /bin/sh 进行求值,它之后的任何参数都将作为 shell 位置参数传递。
-p:在指定命令输出结果之前显示项目标头。这通过以下方式实现:将管道绑定到命令的 stdin、stdout 和 sterr 流,然后通过管道将所有输出结果传输到一个页面调度会话中显示的连续流中。
-v:显示该命令向 stderr 写入的消息。
注意:shell指令中有上述环境变量时,则需要用使用单引号把shell命令括起来。
在每个项目中运行指定的 shell 命令。通过 repo forall 可使用下列额外的环境变量:
REPO_PROJECT:项目的名称。
REPO_PATH:项目在该工作区的相对路径。
REPO_REMOTE:项目远程仓库的名称。
REPO_LREV:manifest文件中revision属性,已转换为本地跟踪分支。如果您需要将manifest中revision值传递到某个本地运行的 Git 命令,则可使用此变量。
REPO_RREV:manifest文件中revision属性,与manifest文件中显示的名称完全一致。
示例:
#打印项目列表
repo forall -c 'echo $REPO_PROJECT'
#打印项目路径
repo forall -c 'echo $REPO_PATH'
repo prune
repo prune {[project] change[/patchset]}...
删除已经合并分支。实际上是对git branch -d命令的封装,该命令用于扫描项目的各个分支,并删除已经合并的分支。
repo abandon
repo abandon [--all | <branchname>] [<project>...]
删除指定分支。实际是对git brance -D命令的封装。
repo upload
repo upload [--re --cc] [<project>]...
常用选项:
-t:发送本地分支名称到Gerrit代码审核服务器
--re=REVIEWERS:要求指定的人员进行审核
--cc=CC:同时发送通知到如下邮件地址
对于指定的项目,Repo 会将本地分支与最后一次 repo sync 时更新的远程分支进行比较。Repo 会提示您选择一个或多个尚未上传以供审核的分支。
注意:使用repo upload需要搭建gerrit环境,并且在manifest文件remote元素中添加review属性
您选择一个或多个分支后,所选分支上的所有提交都会通过 HTTPS 连接传输到 Gerrit。您需要配置一个 HTTPS 密码以启用上传授权。要生成新的用户名/密码对以用于 HTTPS 传输,请访问密码生成器。
当 Gerrit 通过其服务器接收对象数据时,它会将每项提交转变成一项更改,以便审核者可以单独针对每项提交给出意见。要将几项“检查点”提交合并为一项提交,请使用 git rebase -i,然后再运行 repo upload。
如果您在未使用任何参数的情况下运行 repo upload,则该操作会搜索所有项目中的更改以进行上传。
要在更改上传之后对其进行修改,您应该使用 git rebase -i 或 git commit —amend 等工具更新您的本地提交。修改完成之后,请执行以下操作:
进行核对以确保更新后的分支是当前已检出的分支。
对于相应系列中的每项提交,请在方括号内输入 Gerrit 更改 ID:
# Replacing from branch foo
[ 3021 ] 35f2596c Refactor part of GetUploadableBranches to lookup one specific...
[ 2829 ] ec18b4ba Update proto client to support patch set replacments
# Insert change numbers in the brackets to add a new patch set.
# To create a new change record, leave the brackets empty.
上传完成后,这些更改将拥有一个额外的补丁程序集。
repo upload 相当于 git push,但是又有很大的不同。它将版本库改动推送到代码审核服务器(Gerrit软件架设)的特殊引用上。代码审核服务器会对推送的提交进行特殊处理,将新的提交显示为一个待审核的修改集,并进入代码审核流程,只有当审核通过后,才会合并到官方正式的版本库中。
repo download
repo download {[project] change[/patchset]}...
从审核系统中下载指定更改,并放在您项目的本地工作目录中供使用。
例如,要将更改 23823 下载到您的平台/编译目录,请运行以下命令:
$ repo download platform/build 23823
repo sync 应该可以有效移除通过 repo download 检索到的任何提交。或者,您可以将远程分支检出,例如 git checkout m/master。
repo download命令主要用于代码审核者下载和评估贡献者提交的修订。
贡献者的修订在Git版本库中refs/changes//引用方式命名(缺省的patchset为1),和其他Git引用一样,用git fetch获取,该引用所指向的最新的提交就是贡献者待审核的修订。
使用repo download命令实际上就是用git fetch获取到对应项目的refs/changes//patchset>引用,并自动切换到对应的引用上。
repo grep
repo grep {pattern | -e pattern} [<project>...]
打印出符合某个模式的行。相当于对 git grep 的封装,用于在项目文件中进行内容查找。
repo manifest
repo manifest [-o {-|NAME.xml}] [-m MANIFEST.xml] [-r]
常用选项:
-r, --revision-as-HEAD:把某版次存为当前的HEAD
-o -|NAME.xml, --output-file=-|NAME.xml:把manifest存为NAME.xml
manifest检验工具,用于显示当前使用的manifest文件内容。
示例:
# 获取仓库的sha1值,并记录在一个新的release.xml文件中
repo manifest -o release.xml -r