0. 前言

整个android系统源码大约有500个左右大大小小的project,其中每个project都是使用git进行管理。为了对所有的这些project进行统一的管理操作,谷歌就用python开发了repo工具。本文主要介绍如何使用repo工具来对android源码进行管理。

1. repo常用命令

repo的命令操作很简单,常用的也就几个,只要操作过很快就能够熟练使用了。下面对这些常用命令进行介绍。

1.1 init

repo init -u <URL> [<OPTIONS>]

该操作将会在当前目录创建一个.repo目录,其中包括一个repo的源代码的git仓库和一个包含Android manifest文件的git仓库。在.repo目录下还包含了一个manifest.xml文件,它是一个软连接,指向.repo/manifest目录的一个manifest文件(当前选择的manifest)。

该命令包含的选项包括:

  • -u:指定一个URL用于获取manifest仓库
  • -m:从.repo/manifest目录选择一个manifest,如果没有指定的话,那就是default.xml
  • -b:指定manifest仓库的分支

如在《Android AOSP源码下载》一篇中,使用的init的命令如下:

../repo/repo init -u git://aosp.tuna.tsinghua.edu.cn/android/platform/manifest -b android-5.1.1_r6

可以看到-u指定了manifest仓库的URL,-b指定分支,-m并没有指定,所以使用的是default.xml。

1.2 sync

repo sync [<PROJECT_LIST>]

该命令将会根据之前init中选择的manifest文件,将新的变化下载到本地环境中。如果没有指定任何参数,将会同步manifest文件中的所有project。

当执行rep sync的时候,主要做了如下操作:

  • 如果该工程之前从未同步过,那么repo sync就等效于执行git clone操作,会将指定的project从远程仓库拷贝到本地。
  • 如果工程之前有同步过一次,那么rep syn就等效于执行以下操作:
git remote update 
git rebase origin/<BRANCH>

<BRANCH> 是当前本地的project所checked-out的分支。如果本地分支没有跟踪一个远程分支,那么该project将不会有同步发生。

当成功执行repo sync命令后,指定project的代码将会与远程仓库的代码同步。

该命令包含的选项有:

  • -d: 将指定的project切换回manifest文件中指定的分支
  • -s: 根据当前manifest文件中manifest-server元素所的指定,切换到一个已知好的版本
  • -f: 即使当前project同步失败了,也会继续处理其他的project

1.3 diff

repo diff [<PROJECT_LIST>]

该命令就是对指定的每个project用git diff命令显示project的修改状态。

1.4 forall

repo forall [<PROJECT_LIST>] -c <COMMAND>

在每个project中执行给定shell命令,有以下附加的环境变量可以使用:

  • REPO_PROJECT 是该project的唯一的名字
  • REPO_PATH 是该project的与根目录的相对路径
  • REPO_REMOTE 是manifest中指定的remote
  • REPO_LREV 是将manifest中指定的revision的值变换为本地跟踪的分支名
  • REPO_RREV 是manifest文件中写的revision的值

该命令有以下选项:

  • -c: 指定要执行的shel命令和参数(使用/bin/sh执行)
  • -p: show project headers before output of the specified command. This is achieved by binding pipes to the command’s stdin, stdout, and sterr streams, and piping all output into a continuous stream that is displayed in a single pager session.
  • -v: 显示命令写到stderr的消息

1.5 start

repo start <BRANCH_NAME> [<PROJECT_LIST>]

基于manifest中指定的revision创建一个新分支用于开发。

1.6 status

repo status [<PROJECT_LIST>]

对于每个指定的project,将工作树、暂存区和当前分支最近的commit进行比较。对于有差异的文件将其用一行显示出来。其中有差异的文件的修改状态使用两个字母进行表示。

第一个字母是大写,表示该文件在暂存区与当前分支的最新commi有不同:

letter

meaning

description

-

no change

same in HEAD and index

A

added

not in HEAD, in index

M

modified

in HEAD, modified in index

D

deleted

in HEAD, not in index

R

renamed

not in HEAD, path changed in index

C

copied

not in HEAD, copied from another in index

T

mode changed

same content in HEAD and index, mode changed

U

unmerged

conflict between HEAD and index; resolution required

第二个字母是小写的,表示该文件在当前工作目录与暂存区不一致:

letter

meaning

description

-

new/unknown

not in index, in work tree

m

modified

in index, in work tree, modified

d

deleted

in index, not in work tree

1.7 help

如果有不熟悉的命令就通过repo help查看手册,其中对于每个命令,还可以通过指定–help 查看该命令的手册,如:

repo sync --help

2. manifest介绍

默认.repo/manifest.xml指向当前的sd的manifest文件,即位于.repo/manifests目录下(默认下载的aosp代码为default.xml)。repo工具就是根据这个manifest文件来管理android 500个大大小小的project,下面我们就来看一下该文件。

<manifest>

  <remote name="aosp" fetch=".." />
  <default revision="refs/tags/android-5.1.1_r6" remote="aosp" sync-j="4" />

  <project path="build" name="platform/build" groups="pdk,tradefed">

  </project>
  <project path="abi/cpp" name="platform/abi/cpp" groups="pdk" />
  <project path="art" name="platform/art" groups="pdk" />
  <project path="bionic" name="platform/bionic" groups="pdk" />
  <project path="bootable/bootloader/legacy" name="platform/bootable/bootloader/legacy" groups="pdk-cw-fs" />
  <project path="bootable/recovery" name="platform/bootable/recovery" groups="pdk" />

......

  <project path="tools/studio/cloud" name="platform/tools/studio/cloud" groups="notdefault,tools" />
  <project path="tools/studio/translation" name="platform/tools/studio/translation" groups="notdefault,tools" />
  <project path="tools/swt" name="platform/tools/swt" groups="notdefault,tools" />
  <project path="tools/tradefederation" name="platform/tools/tradefederation" groups="notdefault,tradefed" />

</manifest>

可以看到该xml文件主要包括3种元素:remotedefaultproject

2.1 remote

预先定义每个project中能够指定的remote,remote的功能见下面。

2.2 default

默认的remote,如果project中没有指定remote,则使用该remote。

2.3 project

指定整个Android源码的每一个project的配置,它包括以下属性值:

1) name

唯一的该project的名字。

2) remote

remote为project的远程仓库的URL字符串前面的定义,需要与name拼接成该project的远程仓库的实际的URL地址。每个project的仓库的在源码服务器中的实际路径应该为,remote中指定的路径 + project的name属性值,即:

${remote_fetch}/${project_name}.git

如果project没有指定remote,就使用default元素中定义的remote。

platform/abi/cpp,该project在源码服务器中的远程仓库的实际路径为:

<URL_TO_MANIFEST>/../platform/abi/cpp.git

3) path

该project在本地源码中的路径,如果没有指定,那就使用project的name的值,如果该project还有一个父元素,那么path会以父元素的path作为前缀。

4) revision

该project需要跟踪的远程git仓库的分支名。

5) upstream

该project的Git ref名,可以是一个sha1值。用于当以以-c模式同步一个revision的时候锁定manifest,从而避免同步全部的ref空间。

6) group

该project属于的组列表,可以用空格或者逗号分隔。所有的project都会属于all组,并且每个project都会属于它的namepath组。如果将project放置于组notdefault,那么repo将不会自动下载该project。