前言

Android 采用 Gerrit 提供代码评审服务,并且开发了一个客户端工具 repo,实现多仓库管理。Git 的开发者对服务端的 Git 源码做了扩展,使得基于 Git(cgit)的代码平台可以很容易引入新的集中式工作流。同样 git-repo 兼容 Android 的 repo 工具,支持对多仓库的协同管理。

git-repo 实现和安卓 repo 使用习惯上的兼容,两者的差异如下:

  1. Android repo 只支持 Gerrit 服务器。git-repo 采用了一套新的服务发现协议,支持 AGit-Flow 及其兼容的工作流,也支持 Gerrit 工作流。
  2. Android repo 只支持 manifests 仓库管理下的多仓库,而 git-repo 在此基础上,还支持单一 Git 代码仓的集中式工作流协同,并提供快捷的别名命令 git peer-review,或 git pr
  3. Android repo 使用 Python 脚本语言开发,git-repo 使用 Go 语言开发,包含了完整测试用例。git-repo 安装简单,除了 Git 外,别无其他软件依赖。

安装repo

首先下载repo的引导脚本,可以使用wget、curl甚至浏览器从地址http://android.git.kernel.org/repo下载。把repo脚本设置为可执行,并复制到可执 行的路径中。在Linux上可以用下面的指令将repo下载并复制到用户主目录的bin目录下。

mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
## 如果上述 URL 不可访问,可以用下面的:
## curl -sSL  'https://gerrit-googlesource.proxy.ustclug.org/git-repo/+/master/repo?format=TEXT' |base64 -d > ~/bin/repo
chmod a+x ~/bin/repo

为什么说下载的repo只是一个引导脚本(bootstrap)而不是直接称为repo呢?因为repo的大部分功能代码不在其中,下载的只是一个帮助完成整个repo程序的继续下载和加载工具。

repo init完成repo工具的完整下载,现在仅有的不过是repo 的引导程序。初始化操作会从repo脚本里设定的镜像地址中克隆repo.git库到当前的目录下。一个隐藏的.repo目录。
克隆创建的清单库manifest.git(地址来自与-u参数),清单库实际上只包含一个default.xml文件,这个XML文件定义了多个版本库和本地地址的映射关系,是repo工作的指引文件。
克隆的清单库位于.repo/manifests.git中,本地克隆到.repo/manifests。

repo巧妙的实现了多Git版本库的管理。因为 repo使用了清单版本库,所以repo这一工具并没有被局限于Android项目,可以在任何项目中使用。

下载repo.git

在repo引导脚本中,定义了缺省的repo.git的版本库位置以及要检出的缺省分支。

如果不想从缺省任务获取repo,或者不想获取稳定版(stable分支)的repo,可以在repo init命令中通过下面的参数覆盖缺省的设置,从指定的源地址克隆repo代码库。

  • 参数--repo-url,用于设定repo的版本库地址。
  • 参数--repo-branch,用于设定要检出的分支。
  • 参数--no-repo-verify,设定不要对repo的里程碑签名进行严格的验证。

实际上,完成repo.git版本库的克隆,这个repo引导脚本就江郎才尽了,init命令的后续处理(以及其他命令)都交给刚刚克隆出来的.repo/repo/main.py来继续执行。

清单库是什么?从哪里下载?

清单库实际上只包含一个default.xml文件。这个XML文件定义了多个版本库和本地地址的映射关系,是repo工作的指引文件。所以在使用repo引导脚本进行初始化的时候,必须通过-u参数指定清单库的源地址。

清单库的下载,是通过repo init命令初始化时,用-u参数指定清单库的位置。例如repo针对Android代码库进行初始化时执行的命令:

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

  • Repo引导脚本的 init命令可以使用下列和清单库相关的参数:

    • 参数-u--manifest-url):设定清单库的Git服务器地址。
    • 参数-b--manifest-branch):检出清单库特定分支。
    • 参数--mirror:只在repo第一次初始化的时候使用,以和Android服务器同样的结构在本地建立镜像。
    • 参数-m--manifest-name):当有多个清单文件,可以指定清单库的某个清单文件为有效的清单文件。缺省为default.xml
  • Repo初始化命令(repo init)可以执行多次:

    • 不带参数的执行repo init,从上游的清单库获取新的清单文件default.xml
    • 使用参数-u--manifest-url)执行repo init,会重新设定上游的清单库地址,并重新同步。
    • 使用参数-b--manifest-branch)执行repo init,会使用清单库的不同分支,以便在使用repo sync时将项目同步到不同的里程碑。

清单库和清单文件

当执行完毕repo init之后,工作目录内空空如也。实际上有一个.repo目录。在该目录下除了一个包含repo的实现的repo库克隆外,就是manifest库的克隆,以及一个符号链接链接到清单库中的default.xml文件。
当执行 repo init 命令来初始化仓库的时候首先执行的就是 Repo 的引导脚本,该脚本会到我们指定的地方去下载 Manifest 仓库,以及 Repo 命令主体部分。下载好之后工作目录内空空如也。实际上有一个.repo目录。在该目录下除了一个包含repo的实现的repo库克隆外,就是manifest库的克隆,以及一个符号链接链接到清单库中的default.xml文件。其中:

文件夹 用途
manifests 清单文件的仓库
manifests.git 清单文件的 Git 裸仓库,不带工作区
manifest.xml 这是一个链接文件,指向你的用于初始化工作区的清单文件,即manifests/default.xml
project.list 一个文本文件,里面包含所有项目名字的列表
projects projects该文件夹下包含所有 git project 的裸仓库,文件夹的层次结构跟工作区的布局一样
repo 这是 repo 命令的主体,其中也包含最新的 repo 命令,推荐使用这里面的 repo 命令

在工作目录下的.repo/manifest.xml文件就是清单文件的 git 仓库。Repo命令的操作,都要参考这个清单文件。这些 xml 文件中包含了各个 git project 的名称,检出的 reversion,检出到哪个目录等等信息。Repo 就是利用这些 manifest 文件去分别获取各个 project,比如这样一个 manifest 文件:

元素 详情
manifest 元素 xml 文件的根元素
remote 元素 可以存在一个或者多个 remote 元素,remote 元素指定了使用 repo upload 命令的时候,会将改变提交到哪个服务器
default 元素 default 元素中指定的属性都是一些缺省的属性。即如果 project 元素中不存在该属性,则使用在 default 元素中指定的属性。revision:Git 分支的名字。如果 project 元素没有指定 revision 属性,那么就使用 default 元素的该属性。revision 属性的值可以是一个 git branch,git tag,也可以是一个 commit id。sync-j:sync 的时候,并行工作的任务数。sync-c:如果设置为 true,则在同步代码的时候,将只会同步 project 元素中 revision 属性中指定的分支。如果 project 元素没有指定 revision 属性,则使用 default 元素的 revision 属性。
project 元素 xml 文件中可以指定一个或者多个 project 元素。 每一个 project 元素都描述了一个需要 pull 到本地的 git 仓库。project 元素中有很多可以使用的属性,在此只介绍几个我们经常使用的属性。name:git project 的名字,path:该 project 的本地工作区的路径,revision:该 project 要跟踪的分支的名字即之后提交PR的目标分支。名字可以是相对于 refs/heads 命名空间的,如:master,或者绝对的,如:refs/heads/master。标签或者 48 位的 SHA-1 值理论上也可以工作。如果没有提供该属性,则使用 default 元素中的 revision 属性。

repo命令的工作流

repo的命令

Repo命令实际上是Git命令的简单或者复杂的封装。每一个repo命令都对应于repo源码树中subcmds目录下的一个同名的Python脚本。每一个repo命令都可以通过下面的命令获得帮助。

repo help <command>

## repo init

repo init -u URL [OPTIONS]

常用选项参数如下,其它参数通过repo help init查询:

-u(–manifest-url):指定要从中检索清单Git服务器代码库的网址

-m(–manifest-name):当有多个清单文件时,在代码库中选择清单文件。如果未选择任何清单名称,则会默认选择 default.xml

-b(–manifest-branch):指定修订版本,即特定的清单分支

命令repo init 要完成如下操作:

  • 完成repo工具的完整下载,执行的Repo脚本只是引导程序
  • 克隆清单版本库manifest.git (地址来自于-u 参数)
  • 克隆的清单库位于manifest.git中,克隆到本地.repo/manifests。在之前的Repo版本中清单.repo/manifest.xml只是符号链接,它指向.repo/manifests/default.xml。在目前的repo版本中清单.repo/manifest.xml是一个实际的文件,通过include的方式引用.repo/manifests/default.xml
  • 如果.repo/manifests中有多个xml文件,repo init可以任意选择其中一个,默认选择是default.xml
  • .repo/manifests中执行git branch -a | cut -d / -f 3可以查看本地存放的已有的所有分支信息,但是该信息只是同步到你上次下载时的信息,如果需要最新信息需要先在该目录中执行git pull操作。

实际上,完全可以进入到.repo/manifests目录,用git命令操作清单库。对manifests的修改不会因为执行repo init而丢失,除非是处于未跟踪状态。

repo sync

repo sync [<project>…]
-j:开启多线程同步操作,一般8核心可以开到16任务,过多会起反作用。默认情况下,使用4个线程并发进sync
-c:只同步指定的远程分支。默认情况下,sync会同步所有的远程分支,当远程分支比较多的时候,下载的代码量就大。使用该参数,可以缩减下载时间,节省本地磁盘空间
-d:脱离当前的本地分支,切换到manifest.xml中设定的分支。在实际操作中这个参数很有用,当我们第一次sync完代码后,往往会切换到dev分支进行开发。如果不带该参数使用sync, 则会触发本地的dev分支与manifest设定的远程分支进行合并,这会很可能会导致sync失败
-f:当有git库sync失败了,不中断整个同步操作,继续同步其他的git库
–no-clone-bundle:在向服务器发起请求时,为了做到尽快的响应速度,会用到内容分发网络(CDN, Content Delivery Network)。同步操作也会通过CDN与就近的服务器建立连接, 使用HTTP/HTTPS的$URL/clone.bundle来初始化本地的git库,clone.bundle实际上是远程git库的镜像,通过HTTP直接下载,这会更好的利用网络带宽,加快下载速度

repo sync命令用于参照清单文件克隆或者同步版本库。如果某个项目版本库尚不存在,则执行repo sync命令相当于执行git clone。如果项目版本库已经存在,则相当于执行下面的两个命令:

  • git remote update
    相当于对每一个remote源执行fetch操作。

  • git rebase origin/branch
    针对当前分支的跟踪分支,执行rebase操作。不采用merge而是采用rebase,目的是减少提交数量,方便评审(Gerrit)。

如果直接执行repo sync会同步所有project,如果后面指定project则只会同步指定的project。如repo sync platform/build

repo start

repo start <newbranchname> [--all | <project>…]

repo start命令实际上是对git checkout -b命令的封装。为指定的项目或者所有项目(若使用--all参数),以清单文件中为项目设定的分支或里程碑为基础,创建特性分支。特性分支的名称由命令的第一个参数指定。相当于执行git checkout -b
此命令会更新manifest xml文件中的信息给对应的远程分支创建相应的本地分支。

repo status

repo status [<project>...]

repo status命令实际上是对git diff-indexgit diff-files命令的封装,同时显示暂存区的状态和本地文件修改的状态。

例输出:

project repo/                                   branch devwork-m     subcmds/status.py...

上面示例输出显示了repo项目的devwork分支的修改状态。

  • 每个小节的首行显示项目名称,以及所在分支名称。

  • 之后显示该项目中文件变更状态。头两个字母显示变更状态,后面显示文件名或者其他变更信息。

  • 第一个字母表示暂存区的文件修改状态。

    其实是git-diff-index命令输出中的状态标识,并用大写显示。

    • -:没有改变
    • A:添加 (不在HEAD中, 在暂存区 )
    • M:修改 ( 在HEAD中, 在暂存区,内容不同 )
    • D:删除 ( 在HEAD中,不在暂存区 )
    • R:重命名 (不在HEAD中, 在暂存区,路径修改 )
    • C:拷贝 (不在HEAD中, 在暂存区,从其他文件拷贝)
    • T:文件状态改变 ( 在HEAD中, 在暂存区,内容相同 )
    • U:未合并,需要冲突解决
  • 第二个字母表示工作区文件的更改状态。

    其实是git-diff-files命令输出中的状态标识,并用小写显示。

    • -:新/未知 (不在暂存区, 在工作区 )
    • m:修改 ( 在暂存区, 在工作区,被修改 )
    • d:删除 ( 在暂存区,不在工作区 )
  • 两个表示状态的字母后面,显示文件名信息。如果有文件重命名还会显示改变前后的文件名以及文件的相似度。

repo checkout

repo checkout <branchname> [<project>...]

repo checkout命令实际上是对git checkout命令的封装。检出之前由repo start创建的分支。

repo branches命令

repo branches [<project>...]
repo branches命令读取各个项目的分支列表并汇总显示。该命令实际上是通过直接读取.git/refs目录下的引用来获取分支列表,以及分支的发布状态等。

输出示例:

*P nocolor                   | in reporepo2                     |
  • 第一个字段显示分支的状态:是否是当前分支,分支是否发布到代码审核服务器上?

  • 第一个字母若显示星号(*),含义是此分支为当前分支

  • 第二个字母若为大写字母P,则含义是分支所有提交都发布到代码审核服务器上了。

  • 第二个字母若为小写字母p,则含义是只有部分提交被发布到代码审核服务器上。

  • 若不显示P或者p,则表明分支尚未发布。

  • 第二个字段为分支名。

  • 第三个字段为以竖线(|)开始的字符串,表示该分支存在于哪些项目中。

    • | in all projects

      该分支处于所有项目中。

    • | in project1 project2

      该分支只在特定项目中定义。如:project1project2

    • | not in project1
      该分支不存在于这些项目中。即除了project1项目外,其他

repo diff

repo diff [<project>...]

epo diff命令实际上是对git diff**命令的封装,用以分别显示各个项目工作区下的文件差异。

repo stage

repo stage -i [<project>…]

-i:代表git add --interactive命令中的--interactive,给出个界面供用户选择。

实际是对git add --interactive命令的封装、用于挑选各个项目工作区中的改动以加入暂存区。

repo upload

repo upload [--re --cc] {[<project>]... | --replace <project>}

repo upload命令相当于git push,但是又有很大的不同。执行repo upload不是将版本库改动推送到克隆时的远程服务器,而是推送到代码审查服务器(由Gerrit软件架设)的特殊引用上,使用的是SSH协议(特殊端口)。代码审核服务器会对推送的提交进行特殊处理,将新的提交显示为一个待审核的修改集,并进入代码审查流程。只有当审核通过,才会合并到官方正式的版本库中。

-h, --help:显示帮助信息。
-t:发送本地分支名称到 Gerrit 代码审核服务器。
--replace:发送此分支的更新补丁集。注意使用该参数,只能指定一个项目。
--re=REVIEWERS, --reviewers=REVIEWERS:要求由指定的人员进行审核。
--cc=CC:同时发送通知到如下邮件地址。

repo download

repo download {project change[/patchset]}...

repo download命令主要用于代码审核者下载和评估贡献者提交的修订。贡献者的修订在Git版本库中以refs/changes/<changeid>/<patchset>引用方式命名(缺省的patchset为1),和其他Git引用一样,用git fetch获取,该引用所指向的最新的提交就是贡献者待审核的修订。使用repo download命令实际上就是用git fetch获取到对应项目的refs/changes/<changeid>/patchset>引用,并自动切换到对应的引用上。

repo rebase

repo rebase {[<project>...] | -i <project>...}

-h, --help:显示帮助并退出
-i, --interactive:交互式的变基(仅对一个项目时有效)
-f, --force-rebase:向 git rebase 命令传递 --force-rebase 参数
--no-ff :向 git rebase 命令传递 -no-ff 参数
-q, --quiet:向 git rebase 命令传递 --quiet 参数
--autosquash :向 git rebase 命令传递 --autosquash 参数
--whitespace=WS:向 git rebase 命令传递 --whitespace 参数

repo rebase命令实际上是对git rebase命令的封装,该命令的参数也作为git rebase命令的参数。但 -i 参数仅当对一个项执行时有效。

repo prune

repo prune [<project>...]

repo prune命令实际上是对git branch -d命令的封装,该命令用于扫描项目的各个分支,并删除已经合并的分支。

repo abandon

repo abandon <branchname> [<project>...]

相比repo prune命令,repo abandon命令更具破坏性,因为repo abandon是对git branch -D命令的封装。该命令非常危险,直接删除分支,请慎用。

repo grep

相当于对git grep的封装,用于在项目文件中进行内容查找。

repo smartsync

相当于用-s参数执行repo sync,可以通过一些选项设置同步的方式,比如是否在遇到第一个错误的时候就停止,是否强制删除含有未提交修改的项目等等。

repo forall

repo forall [<project>…] –c <command>

迭代器,可以对repo管理的项目中执行同一个shell命令

-c:后面所带的参数是shell指令
-p:在shell指令输出之前列出项目名称
-v:列出执行shell指令输出的错误信息
-r:使用正则

额外的环境变量:
REPO_PROJECT:指定项目的名称
REPO_PATH:指定项目在工作区的相对路径
REPO_REMOTE:指定项目远程仓库的名称
REPO_LREV:指定项目最后一次提交服务器仓库对应的哈希值
REPO_RREV:指定项目在克隆时的指定分支,manifest里的revision属性
另外,如果-c后面所带的shell指令中有上述环境变量,则需要用单引号把shell指令括起来。

repo forall -c 'echo $REPO_PROJECT' # 输出项目的名称
repo forall -p -c git merge aosp-my-dev # 把所有项目切换到master分支,该指令将会把aosp-my-dev分支合并到master分支
repo forall -c git tag aosp-mytag-1.0 # 在所有项目下打标签
repo forall -c 'git remote add origin_1 ssh://jiangxin@192.168.0.125/$REPO_PROJECT.git' # 引用环境变量REPO_PROJECT添加远程仓库
repo forall -c git remote add origin_1 # 删除远程仓库
repo forall –c git branch aosp-dev # 切换分支
repo forall –c git checkout –b aosp-dev # 创建分支
repo forall -c git reset --hard # 当repo sync时如果提示discarding xx commits时可以通过该命令废弃所有提交,然后继续repo sync
repo forall -c 'commitID=`git log --before "2020-01-31 00:00:00" -1 --pretty=format:"%H"`; git reset --hard $commitID' /* repo回退当前分支下所有仓库到指定日期前的最新代码版本*/

repo manifest

repo manifest –o android.xml

显示manifest文件内容,可以通过-o参数输出到指定的文件中。

repo version

显示repo的版本号,还会同时显示Git/Python等依赖的应用版本。

repo selfupdate

用于repo自身的更新。如果提供--repo-upgraded参数,还会更新各个项目的钩子脚本。

repo官方教程:https://source.android.com/source/using-repo.html

repo的安装和使用相关推荐

  1. 在Oracle Linux 7上通过官方Repo在线安装SQL Server 2017

    挂载数据盘 #vgdispaly的Total PE 安装SQL Server服务端 1.下载SQL Server Red Hat Repository配置文件: curl -o /etc/yum.re ...

  2. 从git repo分支安装pip

    本文翻译自:pip install from git repo branch Trying to pip install a repo's specific branch. 试图pip安装回购协议的特 ...

  3. python安装库失败cannot determine archive_python - 私有Github python repo无法安装 - 堆栈内存溢出...

    我想从私有存储库安装此Python包 . 我试过多种方式解决在这里 . 但是,我遇到了以下错误: 1. MakotonoMacBook-ea:~ makotomiyazaki$ pip install ...

  4. CentOS8 安装 Docker repo ‘appstream‘ 下载元数据失败

    关闭防火墙 #查看当前防火墙状态 systemctl status firewalld #暂时关闭防火墙 systemctl stop firewalld #永久关闭防火墙 systemctl dis ...

  5. Docker的安装、镜像源更换与简单应用

    Docker的安装.镜像源更换与简单应用[阅读时间:约20分钟] 一.概述 二.系统环境&项目介绍 1.系统环境 2.项目的任务要求 三.Docker的安装 四.Docker的简单应用 1. ...

  6. RabbitMQ超详细安装教程(Linux)

    目录 1.简介 2.下载安装启动RabbitMQ 2.1.下载RabbitMQ 2.2.下载Erlang 2.3.安装Erlang 2.4.安装RabbitMQ 2.5.启动RabbitMQ服务 3. ...

  7. linux CentOS7 下 Docker安装

    Docker在CentOS安装介绍地址:https://docs.docker.com/install/linux/docker-ce/centos/ 使用root权限安装的. 1.安装所需的包. $ ...

  8. Centos7 上安装Docker

    1 . Docker社区版 Centos官网安装文档 https://docs.docker.com/install/linux/docker-ce/centos/#install-docker-en ...

  9. 一键安装lamp系统

    lamp环境搭建,安装过程中出现的一些错误,绝大部分应该是下载软件的网址过期了,可以再换一个,选择的软件版本尽量选择脚本中所用的版本或者比较接近的,避免在搭建过程中发生错误! #!/bin/bash ...

  10. repo入门和基本用法

    repo是什么? 官方的定义:Repo是谷歌用Python脚本写的调用git的一个脚本,可以实现管理多个git库. 个人理解:repo这个工具,是一个脚本.这个脚本是对git库的管理. 类似什么呢,类 ...

最新文章

  1. note-在VisualStudio中使用正则表达式
  2. android将被代替的控件,Android 控件被忽略的属性
  3. 复制类中的属性值到另一个类的相同属性中
  4. 《mysql必知必会》学习_第11章_20180801_欢
  5. 10.27 afternoon similated match
  6. LiveVideoStackCon 2022 上海站 专题抢先看(2)
  7. redis钟setnx命令
  8. QML工作笔记-NumberAnimation、RotationAnimation、Timer综合使用
  9. 物联网通信之Coap 协议
  10. VIM快捷键(转载)
  11. linux java 错误日志_求大神解决啊啊 啊,看看这个怎么了,在LINUX运行完的错误日志...
  12. VMware虚拟机中windows7系统的安装
  13. 机械革命Z3 Pro测试,从开箱到翻车到上岸到发烧(多图预警)
  14. C++实现Rhino中画准均匀B样条曲线功能
  15. 二元函数对xy同时求导_2020.5.6 | 考研数学—多元函数微分学重要考点攻克
  16. 我国有了密码法,将2020年1月1日起施行!
  17. html蔚蓝网注册页面,如何在网站中添加手机短信验证码注册功能?
  18. 校招社招互联网面试经验总结
  19. 【Python】列表排序,用 sort() 还是 sorted()?
  20. 计算机的组成部件有,电脑的组成部件

热门文章

  1. 【samba】Wodows同步Linux文件|搭建共享文件服务器——在windows上映射网络驱动器...
  2. 极品婆媳龙争虎斗---终极PK王者之战(10)
  3. openwrt路由器挂载sdcard为overlay
  4. 定时器 java qua_Quartz定时任务调度机制解析(CronTirgger、SimpleTrigger )
  5. 【论文笔记】AliMe Assist阿里小蜜(未完。。。)
  6. 华为手机word插件加载失败_word加载项启动失败
  7. 浅谈留存率到底有多少种统计方式(口径问题)
  8. c语言gets和puts的区别,C 语言 gets()和puts()
  9. 笔记本计算机的清洁保养知识,笔记本电脑怎么维护 笔记本电脑维护保养技巧【详解】...
  10. 什么是服务器、云服务的优缺点是什么、为什么要使用云服务器?