Repo用法详解

Android 为企业提供一个新的市场,无论大企业,小企业都是处于同一个起跑线上。研究 Android 尤其是 Android 系统核心或者是驱动的开发,首先需要做的就是本地克隆建立一套 Android 版本库管理机制。

Android 使用 Git 作为代码管理工具,开发了 Gerrit 进行代码审核以便更好的对代码进行集中式管理,还开发了 Repo 命令行工具,对 Git 部分命令封装,将 百多个 Git 库有效的进行组织。要想克隆和管理这百多个 Git 库,还真不是一件简单的事情。

在研究 Repo 的过程中,发现很多文档在 Google Group 上,非“翻墙”不可看。非法的事情咱不干,直接阅读 repo 的代码吧。

创建本地 Android 版本库镜像的思路

如果了解了 Repo 的实现,参考 《Using Repo and Git》 , 建立一个本地的 android 版本库镜像还是不难的:

  • 下载 repo bootstrap 脚本

    $ curl http://android.git.kernel.org/repo >~/bin/repo
    
    $ chmod a+x ~/bin/repo
    
    $ export PATH=$PATH:~/bin
  • 提供 –mirror 参数调用 repo init ,建立 git 版本库克隆
    $ repo init -u git://android.git.kernel.org/platform/manifest.git --mirror
    • 使用 –morror 则下一步和源同步的时候,本地按照源的版本库组织方式进行组织,否则会按照 manifest.xml 指定的方式重新组织并检出到本地
  • 开始和源同步
    $ repo sync
  • 修改 manifest ,修改 git 库地址,指向本地的 git 服务器
    • 修改 platform/manifest.git 库中现有的 xml 文件,或者创建一个新的 xml 文件
    • 将 git 的地址改为本地地址,提交并 push
  • 本地 repo 镜像建立完毕之后,就可以在执行 repo init 时,使用本地更改后的 manifest 库,之后执行 repo sync 就是基于本地版本库进行同步了。
  • 也可以改造 repo,使得不必为 repo 工具初始化,也在本地网络完成操作…

Repo init 干了些什么?

实际上,得到客户使用 repo 的信息后,首先下载 repo 执行脚本开始研究。

curl http://android.git.kernel.org/repo >~/bin/repo

难道只有 600 行的 python 代码么?要是这样应该很简单的呀。可以看下来,却发现远非如此。

Shell script or python?

首先 repo 脚本使用了一个魔法:从脚本第一行的 shebang 来看应该是 shell 脚本,但是满眼却都是 python 语法,怎么回事?

 1 #!/bin/sh

 2

 3 ## repo default configuration

 4 ##

 5 REPO_URL=‘git://android.git.kernel.org/tools/repo.git‘

 6 REPO_REV=‘stable‘

 7

 8 # Copyright (C) 2008 Google Inc.

   ...

22 magic=‘--calling-python-from-/bin/sh--‘

23 """exec" python -E "$0" "[email protected]" """#$magic"

24 if __name__ == ‘__main__‘:

25   import sys

26   if sys.argv[-1] == ‘#%s‘ % magic:

27     del sys.argv[-1]

28 del magic

魔法就在第 23 行,巧妙的通过 python 三引号字串写出了一个能被 python 和 shell script 都能理解的代码,以此为界,代码由 Shell 脚本进入了 Python 的世界。

Bootstrap 和真正的 repo

通过 curl 下载的的 repo 并非完整的 repo 脚本,只是一个 bootstrap。当 repo 执行时,会负责下载完整的 repo 代码,并将控制权转移给真正的 repo。

通过 main 函数,可以看到 repo 运行的开始,就试图发现本地真正的完整的 repo 代码,以便移交控制权:

544 def main(orig_args):

545   main, dir = _FindRepo()

586   try:

587     os.execv(main, me)

其中 545 行的 _FindRepo() 会在当前目录开始向上递归查找 “.repo/repo/main.py”,如果找到则移交控制权(587行)。

Repo bootstrap 脚本调用 init 只完成第一阶段的初始化

Repo 的 bootstrap 脚本只支持两个命令 help 和 init,而 init 也只完成 repo 版本库克隆(即安装 repo 完整工具),之后就转移控制权。

在 Repo bootstrap 执行 init 可以提供很多参数,但实际上第一阶段初始化,只用到两个参数(而且都有默认值)

  • 参数:–repo-url=URL
    repo 工具本身的 git 库地址。缺省为:git://android.git.kernel.org/tools/repo.git
  • 参数:–repo-branch=REVISION
    使用 repo 的版本库,即 repo git 库的分支或者里程碑名称。缺省为 stable

第二阶段的 repo init

执行第二阶段的 repo init,控制权已经移交给刚刚克隆出来的 repo git 库的脚本。

Repo git 库被克隆/检出到执行 repo init 命令当前目录下的 .repo/repo 子目录中,主要的执行脚本为 .repo/repo/main.py。main.py 接着执行 repo init 命令。

Repo 的代码组织的非常好,在 .repo/repo/subcmds/ 子目录下,是各个 repo 命令的处理脚本。repo init 的第二阶段脚本正是由 .repo/repo/subcmds/init.py 负责执行的。第二阶段主要完成:

  • 克隆由 -u 参数提供的 manifest Git 库,如克隆 android 库时:

    $ repo init -u git://android.git.kernel.org/platform/manifest.git
  • 如果不提供 -b REVISION 或者 –manifest-branch=REVISION参数,则检出 manifest Git 库的 master 分支
  • 如果不提供 -m NAME.xml 或者 –manifest-name=NAME.xml 参数,则使用缺省值 default.xml
  • 如果提供 –mirror 参数,则后续同步操作会有相应的体现

Repo start 干了些什么?

Android 源码网站在介绍 repo 的使用模型中,有一个图片: http://source.android.com/images/git-repo-1.png , 介绍了 repo 的使用流程。其中 “repo start” 是紧接着 “repo sync” 后的第一个动作。那么这个动作是干什么的呢?

得益于 repo 对 git 操作的封装,”repo start” 命令的处理代码只有区区 68 行。

 37   def Execute(self, opt, args):

 41     nb = args[0]

 47     projects = []

 48     if not opt.all:

 49       projects = args[1:]

 54     all = self.GetProjects(projects)

 57     for project in all:

 59       if not project.StartBranch(nb):

 60         err.append(project)

看到第 59 行了么,就是对 repo 同步下来的项目的多个 Git 版本库,逐一执行 project.StartBranch 操作。 nb 是 repo start 的第一个参数,即分支名称。

关于 StartBranch 的代码,在 project.py 中:

 857   def StartBranch(self, name):

 858     """Create a new branch off the manifest‘s revision.

 859     """

 894     if GitCommand(self,

 895                   [‘checkout‘, ‘-b‘, branch.name, revid],

 896                   capture_stdout = True,

 897                   capture_stderr = True).Wait() == 0:

 898       branch.Save()

 899       return True

原来如此, repo start <branch_name> 就是逐一为各个版本库创建工作分支,以便在此分支下进行工作。

读者可以按图索骥,找到 repo 各个命令的实现,破解心中的疑惑。

repo的用法(zz)

注:repo只是google用Python脚本写的调用git的一个脚本,主要是用来下载、管理Android项目的软件仓库。(也就是说,他是用来管理给git管理的一个个仓库的)

下载 repo 的地址: http://android.git.kernel.org/repo ,可以用以下二者之一来下载 repo

wget http://android.git.kernel.org/repo

或者

curl http://android.git.kernel.org/repo > ~/bin/repo

下载完成后须修改repo的权限: chmod a+x ~/bin/repo

用repo sync 在抓去 android source code 的时候,会经常出现一些错误导致 repo sync 中断,每次都要手动开始。 可以用如下的命令,来自动重复

$?=1;

while [ $? -ne 0 ] ;

do  repo sync ;

done

获取帮助:

repo help [ command ]   //显示command 的详细的帮助信息内容

示例: repo help init 来获取 repo init 的其他用法

repo init -u URL 用以在当前目录安装 repository ,会在当前目录创建一个目录 ".repo"  -u 参数指定一个URL, 从这个URL 中取得repository 的 manifest 文件。

示例:repo init -u git://android.git.kernel.org/platform/manifest.git

获取的manifest文件放在.repo目录中。命名为manifest.xml。这个文件的内容其实就是所有被git管理的仓库的列表!

可以用 -m 参数来选择获取 repository 中的某一个特定的 manifest 文件,如果不具体指定,那么表示为默认的 namifest 文件 (default.xml)

repo init -u git://android.git.kernel.org/platform/manifest.git -m dalvik-plus.xml

(有诸多供我们选择的manifest文件,所有的manifest文件都放在目录.repo/manifests中,该目录本身亦被git所管理,你可以cd进去看看)

可以用 -b 参数来指定某个manifest 分支。

repo init -u git://android.git.kernel.org/platform/manifest.git -b release-1.0

你会发现.repo/manifests是个被git管理的仓库,这里放的是所有的manifest文件(*.xml),因为被git管理,固然有分支,-b可以切换到你想要的分支然后再下载相关的xml文件,当然具体下载那个xml还要看-m参数了,所以如果你仅仅指定-b而没有-m的话,就是下载-b指定分支下的default.xml文件

如果不指定-b参数,那么会默认使用master分支

4. repo sync [project-list]

下载最新本地工作文件,更新成功,这本地文件和repository 中的代码是一样的。 可以指定需要更新的project , 如果不指定任何参数,会同步整个所有的项目。

如果是第一次运行 repo sync , 则这个命令相当于 git clone ,会把 repository 中的所有内容都拷贝到本地。 如果不是第一次运行 repo sync , 则相当于 git remote update ;  git rebase origin/branch .  repo sync 会更新 .repo 下面的文件。 如果在merge 的过程中出现冲突, 这需要手动运行  git  rebase --continue

5. repo update[ project-list ]

上传修改的代码 ,如果你本地的代码有所修改,那么在运行 repo sync 的时候,会提示你上传修改的代码,所有修改的代码分支会上传到 Gerrit (基于web 的代码review 系统), Gerrit 受到上传的代码,会转换为一个个变更,从而可以让人们来review 修改的代码。

6. repo diff [ project-list ]

显示提交的代码和当前工作目录代码之间的差异。

7. repo download  target revision

下载特定的修改版本到本地, 例如:  repo download pltform/frameworks/base 1241 下载修改版本为 1241 的代码

8. repo start newbranchname .

创建新的branch分支。 "." 代表当前工作的branch 分支。

9.  repo prune [project list]

删除已经merge 的 project

10. repo forall -c

这个命令会遍历所有的git仓库,并在每个仓库执行-c所指定的命令(这个被执行的命令就不限于仅仅是git命令了,而是任何被系统支持的命令,比如:ls 、 pwd 、cp 等等的 )

当我想通过这个命令遍历所有的仓库并在每个仓库执行"git checkout . "用以将每个仓库的改动都清除的时候,我这么输入命令:

repo forall -c git checkout . 

我发现这样根本不行。看来repo不能遍历执行checkout这个命令。今天我终于想到了另外一个命令"git reset --hard HEAD" 哈哈

repo forall -c git git reset --hard HEAD

再说一个新发现:以前用repo forall 执行一些命令的时候,可能再遍历到某个仓库的时候出了问题,但是我却苦于不知道这个仓库到底是哪个!一直也没有解决。今天终于找到了。。。。  关键时候还是要看命令自己带的帮助手册呀。。。

repo help forall  用这个命令查看下针对forall的帮助吧。说的很清楚,repo执行的时候加上-p参数就可以在遍历到每个仓库的时候先打印出当前的pwd,然后再继续执行-c所指定的命令。举例如下:

repo forall -p -c git branch    

 

//该命令会遍历所有仓库并打印每个仓库的分支情况,由于有了-p参数,这样便会打印出每个仓库的路径!!!

 

11. repo status

显示 project 中每个仓库的状态,并打印仓库名称

时间: 2024-08-30 02:46:06

Repo用法详解的相关文章

js的offsetParent属性用法详解

js的offsetParent属性用法详解:此属性是javascript中较为常用的属性,对于它的良好掌握也是非常有必要的,下面就通过代码实例介绍一下它的用法,希望能够给需要的朋友带来一定的帮助.一.基本介绍:此属性可以返回距离指定元素最近的采用定位(position属性值为fixed.relative或者absolute)父级元素,如果父级元素中没有采用定位的元素,则返回body对象的引用.语法结构: obj.offsetParent 二.代码实例: <!DOCTYPE html> <

python处理word文件:win32com用法详解

目标:用python处理doc文件 方法:引入win32com模块 ************************************************************************** 一.安装 ************************************************************************** 首先要先下载安装win32com模块(起先在linux下装不成功,后在windows下面成功了...) 下载地址:http

jQuery 事件用法详解

jQuery 事件用法详解 目录 简介 实现原理 事件操作 绑定事件 解除事件 触发事件 事件委托 事件操作进阶 阻止默认事件 阻止事件传播 阻止事件向后执行 命名空间 自定义事件 事件队列 jquery中文文档 简介 jquery 之所以成为最受欢迎的前端库,很大一部分是得益于它的事件具有良好的语义,优秀的兼容性,并且便于管理和扩展. 在这里我会介绍 jquery 事件的一些比较基础的用法. 实现原理 jquery 事件脱胎于浏览器的 addEventListener (W3) 和 attac

(转)ProgressDialog用法详解

转载自: ProgressDialog用法详解 ProgressDialog的基本用法 ProgressDialog为进度对话框.android手机自带的对话框显得比较单一,我们可以通过ProgressDialog来自己定义对话框中将要显示出什么东西. 首先看看progressDialog里面的方法 setProgressStyle:设置进度条风格,风格为圆形,旋转的.  setTitlt:设置标题  setMessage:设置提示信息:  setIcon:设置标题图标:  setIndeter

BigDecimal用法详解(转)

BigDecimal用法详解    http://www.cnblogs.com/linjiqin/p/3413894.html 一.简介Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算.双精度浮点型变量double可以处理16位有效数.在实际应用中,需要对更大或者更小的数进行运算和处理.float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal.BigDecimal所创建的是对象

mapminmax的用法详解 _MATLAB

============外一篇 有关mapminmax的用法详解 by faruto==================================转自:http://www.ilovematlab.cn/thread-47224-1-1.html几个要说明的函数接口:[Y,PS] = mapminmax(X)[Y,PS] = mapminmax(X,FP)Y = mapminmax('apply',X,PS)X = mapminmax('reverse',Y,PS) 用实例来讲解,测试数据

Nmap用法详解

nmap是一个网络探测和安全扫描程序,系统管理者和个人可以使用这个软件扫描大型的网络,获取那台主机正在运行以及提供什么服务等信息.nmap支持很多扫描技术,例如:UDP.TCP connect().TCP SYN(半开扫描).ftp代理(bounce攻击).反向标志.ICMP.FIN.ACK扫描.圣诞树(Xmas Tree).SYN扫描和null扫描.从扫描类型一节可以得到细节.nmap还提供了一些高级的特征,例如:通过TCP/IP协议栈特征探测操作系统类型,秘密扫描,动态延时和重传计算,并行扫

CSS中伪类及伪元素用法详解

原文:CSS中伪类及伪元素用法详解 伪类的分类及作用: 注:该表引自W3School教程 伪元素的分类及作用: 接下来让博主通过一些生动的实例(之前的作业或小作品)来说明几种常用伪类的用法和效果,其他的读者可以自己尝试: :active  大致效果为用鼠标点击时,元素增加特效,鼠标松开时,特效消失.多用在按钮的点击上. 写法: 这里id为box的是一div块,在css中首先设置了他的基本样式,下面为加入:active伪类后需要修改的样式. 未点击时: 点击之后: :active.:hover.:

C# ListView用法详解

一.ListView类 1.常用的基本属性: (1)FullRowSelect:设置是否行选择模式.(默认为false) 提示:只有在Details视图该属性才有意义. (2) GridLines:设置行和列之间是否显示网格线.(默认为false)提示:只有在Details视图该属性才有意义. (3)AllowColumnReorder:设置是否可拖动列标头来对改变列的顺序.(默认为false)提示:只有在Details视图该属性才有意义. (4)View:获取或设置项在控件中的显示方式,包括D