repo

1,785 阅读2分钟

Git作为一个版本控制工具,功能很强大,新建分支,切换分支都很快,小团队用Git就能很好地管理好了,但如果是Android系统如此庞大的工程呢,我们知道全套Android源码是很大很大的,目录结构也很复杂,如果直接将其init成一个Git库,简直是灾难,也不符合解耦的要求。

要知道Git是无法将整个库中间的某个目录单独clone出来的,这样如果我只是负责frameworks的,但我下代码的时候却得把整个都下下来。

相比较一开始,Android本身也发生了翻天覆地的变化,有些模块在演进过程中可能就渐渐被抛弃了,这个时候我们就需要一个定义一个文件去记录每一个版本的Android到底用了哪些库。

Repo是谷歌用Python脚本写的调用git的一个脚本。主要是用来下载、多个Git仓库。repo 其实就是把相关的git操作命令进行了封装,方便一下操作好几个git仓库.

安装下载repo脚本

mkdir ~/bin
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
chmod a+x ~/bin/repo

修改本地环境变量,在~/.bashrc(mac下可能不生效)或者~/.bash_profile中增加

export PATH=~/bin:$PATH
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'

在当前bash环境下读取并执行bashrc中的命令

source ~/.bashrc

一般来说为了方便管理,你可以用合适的文件夹名称来存放你要下载的分支代码,然后用在这个文件夹内repo init

初始化repo工具脚本,并且从服务器端克隆manifest,这个manifest很关键,repo就是按照它来管理多个git仓库的。

repo init -u URL -b branch_name : 这是最常用的URL就用公司的服务端地址,branch_name:就是你下载的代码的分支的名字,因为公司肯定会同时维护好几个分支的代码用于开发。

这个命令就相当于对repo配置和repo脚本集进行git pull,但是它还额外做了更多的事情

命令参数:
  -u:指定一个url然后连接到一个manifest库.这个manifest库里面会有所有分支的manifest文件。
  -b :选择manifest仓库的一个特殊的分支
  -m :选择manifest仓库中的某一个。当有很多个的时候默认default.xml.

最终此命令完成repo工具的完整下载,克隆url对应的清单文件米克隆岛本地的.repo/manifest.xml当中。注意 它只是一个连接符号,指向了.repo/manifets/default.xml.你要是用-m指向了别处,那么就会连接到对应的.repo/manifests/xxxxx.xml的manifest当中。

其实,如果不使用repo工具,也是可以对照manifest.xml文件清单直接使用“git clone”的方式一个project一个project的下载的,然后对每个project进行git checkout特定的分支。

当你完成了repo init以后,你会在你的目录下发现一个.repo的隐藏目录,进到.repo/manifest/中,打开default.xml,这就是之前所说的用来记录一个版本中需要哪些库的文件。下图是android-4.0.1_r1版本所对应的default.xml文件:

但Google分模块分的更细一些,并不是简单地将一级目录直接就划成一个模块,比如external,它是以二级目录划分的,而device目录下划分得更细一些。而revision定义的则是对应库的对应分支。

这个文件看完关闭之后,我们在.repo/manifest/目录下运行git branch -a来看看。

这个manifest目录本身其实也是一个git库,一个Android版本对应一个分支,其中的default.xml就记录着这个版本所需要的库,repo工具再根据这个文件去把取各个库的对应分支并最终组合起来。

总结一下,Git管理单独的模块,而repo管理所有的Git库,将多个Git库组合在一起,形成一个完整的大版本。

下载代码

repo sycn :按照.repo/manifest.xml指向的那个xml开始克隆并同步远程版本库中的代码.此时两种情况
    1)、如果是第一次克隆本地不存在上面的版本库,那么就相当于git clone.
    2)、如果版本库已经存在相当于
     git remote update  这个命令对于每一个remote的远程分支进行执行了fetch.
     git rebase orignl/branch :对当前所在的分支执行rebase.

repo sync -c 是指当前分支。可以加快下载速度。 也可以克隆某个指定的git仓库,但注意单独克隆的一般没法编译因为它会依赖别的git库或者缺少mk。所以可能编译不成功

repo sycn URL. 这个URL就是manifest中指定的name.

如:repo sycn platform/packages/apps/Nfc (-j8) :platform/packages/apps/Nfc是project的name.

总结来说:在repo目录(即.repo)之外,根据repo配置(即.repo/manifest.xml文件),从.repo/projects/*中提取出指定分支的各个git项目(即.repo/projects中git项目的子集)的工作目录,形成repo工作目录,可供开发使用。

下面我们先大概了解一下重要的几个目录的含义:
        .repo:此为repo目录,可用于提取相应项目工作目录到外面的repo工作目录。
        .repo/manifests.git:此为repo配置信息的git库,不同版本包含不同配置信息。每个repo项目初始化后也会有自己的git仓库的repo也会建立一个Git仓库,用来记录当前Android版本下各个子项目的Git仓库分别处于哪一个分支,这个仓库通常叫做:manifest仓库。
        .repo/manifests:此为repo配置信息的工作目录(将配置信息的工作目录和相应的实际git目录分离管理,并且配置信息中的.git目录实际只是指向实际git库的软连接)。此目录中可能包含一个或多个xml文件描述的配置。每个xml文件是独立的一套配置,配置内容包括当前repo工作目录包含哪些git项目、所有git项目所处的默认公共分支、以及远端地址等。
        .repo/manifest.xml:repo工作目录中的内容同一时刻只能采用manifests中的一个xml文件做为其配置,该文件就是其软连接,通过init的-m选项指定采用哪个文件;另外,同一xml文件也可能处于manifests库的不同版本或者不同分支,通过init的-b选项指定使用manifests中的哪个分支,每次init命令都会从服务器更新最新的配置。这里通过-m指定的manifests中的xml文件中。
        .repo/repo:此为repo脚本集的git库,用于repo管理所需的各种脚本,repo的所有子命令就是其中的对应脚本实现。这些脚本也通过git管理,.repo/repo/.git为对其应的git目录,用git进行版本管理。

基本上所有的repo命令。如果只是: repo 命令参数
那么就代表对所有的git仓库的执行,无论是在那个目录下。

当你向操纵某个指定的git仓库的时候,无论是不是在它目录下。执行 repo 命令参数 指定的本地仓库路径(也就是path对应)

创建/切换分支。刚下载下来的代码是没有本地分支的。

xp022430@cnbjlx24729:~/Projects/n-mr1-yoshino2/packages/apps/Dialer$ git branch
* (no branch)
xp022430@cnbjlx24729:~/Projects/n-mr1-yoshino2/packages/apps/Bluetooth$ git branch
* (no branch)

创建 :调用 repo start 分支名字 --all : 为全部的本地git仓库配置分支名字

然后在config里面会看到,自动关联了upstream根据manifet中的revision。

切换:repo checkout branch_name [projects]

查看分支:repo branches [projects]

[projects] :代表可省略git仓库,此时会查看所有的git仓库

repo abandon [projects]: 删除指定的分支. 是对git branch -D的封装.

比较差异

repo diff [projects]:查看工作区的差异

repo diff :查看所有

repo diff project1 project2 :查看指定的project1、project2。

repo stage [projects] 相当于git add 把工作区内容加入到缓存区。

repo status [projects] 同时显示缓存区和工作区的文件的状态.

repo push :一般用很少用

repo push [--all | [projects]]