转自文章《Android内核开发:理解和掌握repo工具》和《Repo的理解和用法小结2》
1. repo是什么?
repo是一种代码版本管理工具,它是由一系列的Python脚本组成,封装了一系列的Git命令,用来统一管理多个Git仓库。
2. 为什么要用repo?
因为Android源码引用了很多开源项目,每一个子项目都是一个Git仓库,每个Git仓库都有很多分支版本,为了方便统一管理各个子项目的Git仓库,需要一个上层工具批量进行处理,因此repo诞生。
repo也会建立一个Git仓库,用来记录当前Android版本下各个子项目的Git仓库分别处于哪一个分支,这个仓库通常叫做:manifest仓库。
3. 怎么安装repo?
官方的repo脚本下载方法:
curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ./repo
由于官网被墙,目前可以使用的repo脚本下载方法如下(两者选一):
$ git clone git://git.omapzoom.org/git-repo.git $ git clone git://aosp.tuna.tsinghua.edu.cn/android/git-repo.git/
$ cp git-repo/repo ./repo
或者修改手头已有的被墙的repo文件:
REPO_URL = ‘git://git.omapzoom.org/git-repo.git‘ REPO_URL = ‘git://aosp.tuna.tsinghua.edu.cn/android/git-repo‘
REPO_REV = ‘stable‘
当然,你也可以去我的GitHub下载这个repo文件,地址:
https://github.com/Jhuster/AOSP/blob/master/repo
4. 怎么下载源码?
上面说过,Android源码分支其实由一个叫manifest仓库来管理起来的,因此,下载源码首先要clone这个manifest仓库。这个仓库里面有一个XML文件,其实就是一个文件清单,列出了本代码仓库依赖哪些代码,该去哪下载,分支是什么。
一般用repo init命令来clone这个manifest仓库,例如,如果要下载Android源码,则方法如下:
$ repo init -u https://android.googlesource.com/platform/manifest
当然,上面的官网被墙了,因此,推荐如下镜像(两者选一):
$ repo init -u git://git.omapzoom.org/platform/manifest.git $ repo init -u git://aosp.tuna.tsinghua.edu.cn/android/platform/manifest
初始化完毕后,你会在本地的.repo文件夹中看到manifest仓库的内容,这个文件夹中最重要的文件是manifest.xml(有的仓库用的是default.xml,然后指向具体的xml),它就是上面说到的文件清单。
如果要选择特定版本的Android源码,或者在已下载的源码基础上切换到其他版本,则可以使用-b选项:
$ repo init -u git://git.omapzoom.org/platform/manifest.git -b android-5.0.2_r1 $ repo init -u git://aosp.tuna.tsinghua.edu.cn/android/platform/manifest -b android-5.0.2_r1
然后使用 repo sync 命令进行同步即可下载好全部的Android源码了。
5. manifest.xml文件清单的组成
上面提到了repo init需要初始化一个manifest仓库,仓库中含有一个很重要的manifest.xml文件清单,其实这个manifest.xml并不复杂的,它就是用XML文件的格式记录了本项目依赖的各个Git仓库的名称、地址,以及分支等信息。常用的元素如下所示:
(1) manifest 最顶层的XML元素
(2) remote 设置远程git服务器的属性,如名称、根URL地址等
(3) project 需要clone的Git仓库,path表示本机路径,name表示远程版本库的相对路径
(4) copyfile 执行拷贝操作,把URL/$src地址的文件拷贝到./$dest
其实,如果不使用repo工具,也是可以对照manifest.xml文件清单直接使用“git clone”的方式一个project一个project的下载的,然后对每个project进行git checkout特定的分支。
7. 常用repo命令
这一块网上文章很多,我就不详细讲解了,只列出常用命令。
(1) repo init // 初始化repo仓库
(2) repo sync // 下载源码
(3) repo start // 创建分支
(4) repo checkout //切换分支
(5) repo branches //查看分支
(6) repo status //查看文件状态
下面对其中的命令进行详细介绍:
repo init -u manifest_git_path -m manifest_file_name -b branch_name --repo-url=repo_url --no-repo-verify
在当前目录下安装 Repo。这会产生一个 .repo/ 目录,目录包括装 Repo 源代码和标准 Android 清单文件的 Git 仓库。.repo/ 目录还包括 manifest.xml,是一个在 .repo/manifests/ 目录选择清单的符号链接。
选项:
-u: 指定Manifest库的Git访问路径。
-m: 指定要使用的Manifest文件。
-b: 指定要使用Manifest仓库中的某个特定分支。
–repo-url: 指定要检查repo是否有更新的远端repoGit库的访问路径。
–no-repo-verify: 指定不检查repo库是否需要更新。
repo sync [project_name]
用于参照清单文件克隆并同步版本库。可以使用repo sync project_name的形式只克隆某个项目。。
实现参照清单.repo/manifests.xml克隆并同步版本库,如果版本库不存在,则相当于执行
git clone
如果版本库已经存在,则相当于执行
#对每个remote源进行fetch操作 git remote update #针对当前分支的跟踪分支进行rebase操作 git rebase/origin/branch
选项:
-d:切换指定项目回到清单修正。如果该项目目前是一个主题分支那就有帮助,但清单修正是暂时需要。
-s:同步到一个已知的构建 manifest-server 在当前清单指定的元素。
-f:继续同步其他项目,即使有项目同步失败。
repo start <newbranchname> [--all|<project>...]
创建并切换分支。刚克隆下来的代码是没有分支的,repo start实际是对git checkout -b命令的封装。
为指定的项目或所有的项目(若使用-all),以清单文件中为设定的分支,创建特定的分支。
这条指令与git checkout -b 还是有很大区别的。
· git checkout -b 是在当前所在的分支的基础上创建特性分支。
· 而repo start 是在清单文件设定的分支的基础上创建特性分支。
repo start stable --all
假设清单文件中设定的分支是gingerbread-exdroid-stable,那么执行以上指令就是对所有项目,在gingerbread-exdroid-stable的基础上创建特性分支stable。
repo start stable platform/build platform/bionic
假设清单文件中设定的分支是gingerbread-exdroid-stable,那么执行以上指令就是对platform/build、platform/bionic项目,在gingerbread-exdroid-stable的基础上创建特性分支stable。
<branchname> [ <rpoject> ...]{{{ repo checkout <branchname> [ <project> ...] }}}
切换分支。 实际上是对git checkout命令的封装,但不能带-b参数,所以不能用此命令来创建特性分支。
示例:
repo checkout liuq -dev repo checkout liuq -dev skipper/build platform/bionic
repo branches [<project>...]
查看分支。
示例:
repo branches repo branches skipper/build skipper/release #查看可切换的分支 cd .repo/manifests git branch -a | cut -d / -f 3
repo diff [<project>...]
查看工作区文件差异。实际是对git diff命令的封装,用于分别显示各个项目工作区下的文件差异。在 commit 和工作目录之间使用 git diff 显示明显差异的更改。
示例:
#查看所有项目 repo diff #只查看其中的两个项目 repo diff skipper/build skipper/release
repo stage -i [<project>...]
把文件添加到index表中。实际上是对git add –interactive命令的封装,用于挑选各个项目中的改动以加入暂存区。
-i表示git add –interactive命令中的–interactive,给出一个界面供用户选择。
repo prune [<project>...]
删除已经合并分支。实际上是对git branch -d 命令的封装,该命令用于扫描项目的各个分支,并删除已经合并的分支。
repo abandon <branchname> [<rpoject>...]
删除指定分支。实际是对git brance -D命令的封装。
repo status [<project>...]
查看文件状态。
示例:
#输出skipper/build项目分支的修改状态 repo status skipper/build
每个小节的首行显示项目名称,以及所在的分支的名称。
每个字母表示暂存区的文件修改状态。
字母 含义 描述 - 无变化 没有修改,在 HEAD 和在索引中是一样的 A 添加 不在HEAD中,在暂存区中 M 修改 在HEAD中, 在暂存区中,内容不同 D 删除 在HEAD中,不在暂存区 R 重命名 不在HEAD中,在暂存区中 C 拷贝 不在HEAD中,在暂存区,从其他文件拷贝 T 文件状态改变 在HEAD中,在暂存区,内容相同 U 未合并 需要冲突解决 第二个字符表示工作区文件的更改状态。
字母 含义 描述 - 新/未知 不在暂存区,在工作区 m 修改 在暂存区,在工作区,被修改 d 删除 在暂存区,不在工作区 两个表示状态的字母后面,显示文件名信息。如果有文件重名还会显示改变前后的文件名及文件的相似度。
repo remote add <remotename> <url> [ <project> ...] repo remote rm <remotename> [ <project> ...]
设置远程仓库。
示例:
repo remote add org ssh://10.11.10.11/git_repo
这个指令根据xml文件添加的远程分支,方便于向服务器提交代码,执行之后的build目录下看到新的远程分支org。
#删除远程仓库 repo remote rm org
repo push <remotename> [--all|<project>...]
向服务器提交代码。repo会自己查询需要向服务器提交的项目并提示用户。
示例:
repo push org
repo forall [<project>...] -c <command>
迭代器,可以在所有指定的项目中执行同一个shell指令。
选项:
-c 后面所带的参数是shell指令,即执行命令和参数。命令是通过 /bin/sh 评估的并且后面的任何参数就如 shell 位置的参数通过。
-p 在shell指令输出之前列出项目名称,即在指定命令的输出前显示项目标题。这是通过绑定管道到命令的stdin,stdout,和 sterr 流,并且用管道输送所有输出量到一个连续的流,显示在一个单一的页面调度会话中。
-v 列出执行shell指令输出的错误信息,即显示命令写到 sterr 的信息。
附加环境变量:
REPO_PROJECT 指定项目的名称
REPO_PATH 指定项目在工作区的相对路径
REPO_REMOTE 指定项目远程仓库的名称
REPO_LREV 指定项目最后一次提交服务器仓库对应的哈希值
REPO_RREV 指定项目在克隆时的指定分支,manifest里的revision属性
如果-c后面所带的shell指令中有上述环境变量,则需要用单引号把shell指令括起来。
repo forall -c 'echo $REPO_PROJECT' repo forall -c 'echo $REPO_PATH'
repo forall -p -c git merge topic
把所有项目都切换到master分支,执行上述指令将topic分支合并到master分支。
repo forall -c git tag crane-stable-1.6
在所有项目下打标签。
repo forall -c 'git remote add korg ssh://xiong@172.16.31/$REPO_PROJECT.git'
引用环境变量REPO_PROJECT添加远程仓库。
#删除远程仓库。 repo forall -c git remote rm korg
repo forall -c git branch crane -dev repo forall -c git checkout -b crane -dev
repo grep {pattern | -e pattern} [<project>...]
打印出符合某个模式的行。相当于对 git grep 的封装,用于在项目文件中进行内容查找。
示例:
#要找一行, 里面有#define, 并且有'MAX_PATH' 或者 'PATH_MAX': repo grep -e '#define' --and -\( -e MAX_PATH -e PATH_MAX \) #查找一行, 里面有 'NODE'或'Unexpected', 并且在一个文件中这两个都有的. repo grep --all-match -e NODE -e Unexpected
repo manifest [-o {-|NAME.xml} [-r]]
manifest检验工具,用于显示manifest文件内容。
选项:
-h, –help 显示这个帮助信息后退出
-r, –revision-as-HEAD 把某版次存为当前的HEAD
-o -|NAME.xml, –output-file=-|NAME.xml 把manifest存为NAME.xml
repo version
显示repo的版本号。
选项:
-h, –help 显示这个帮助信息后退出.
repo upload [--re --cc] {[<project>]...|--replace <project>}
repo upload 相当于git push,但是又有很大的不同。它不是将版本库改动推送到代码审核服务器(Gerrit软件架设)的特殊引用上,使用SSH协议。代码审核服务器会对推送的提交进行特殊处理,将新的提交显示为一个待审核的修改集,并进入代码审核流程,只有当审核通过后,才会合并到官方正式的版本库中。
选项:
-h, –help 显示帮助信息
-t 发送本地分支名称到Gerrit代码审核服务器
–replace 发送此分支的更新补丁集
–re=REVIEWERS 要求指定的人员进行审核
–cc=CC 同时发送通知到如下邮件地址
repo download {project change[/patchset]}...
repo download命令主要用于代码审核者下载和评估贡献者提交的修订。
贡献者的修订在Git版本库中refs/changes//引用方式命名(缺省的patchset为1),和其他Git引用一样,用git fetch获取,该引用所指向的最新的提交就是贡献者待审核的修订。
使用repo download命令实际上就是用git fetch获取到对应项目的refs/changes//patchset>引用,并自动切换到对应的引用上。
repo selfupdate
用于 repo 自身的更新。如果有新版本的repo存在, 这个命令会升级repo到最新版本。通常这个动作在repo sync时会自动去做, 所以不需要最终用户手动去执行。
选项:
-h, –help 显示这个帮助信息后退出.
–no-repo-verify 不要验证repo源码.
repo help [--all|command]
显示命令的详细帮助。
选项:
-h, –help 显示这个帮助信息后退出
-a, –all 显示完整的命令列表