repo的安装和使用

Posted Rainmicro

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了repo的安装和使用相关的知识,希望对你有一定的参考价值。

前言

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一个文本文件,里面包含所有项目名字的列表
projectsprojects该文件夹下包含所有 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 repo
   repo2                     |
  • 第一个字段显示分支的状态:是否是当前分支,分支是否发布到代码审核服务器上?

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

  • 第二个字母若为大写字母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

svn的安装和使用

1.直接安装
sudo apt-get install subversion 

2.创建版本库
 sudo mkdir /home/.svn    #创建隐藏文件夹
 sudo svnadmin create /home/.svn/repos 

3.了解版本库,进入版本库查看生成的相关文件 
cd /home/.svn/repos/ 
ls  
    conf db format hooks locks README.txt 

# 我们主要关心的是conf和db文件,conf文件夹下是存放主配置文件和用户、权限位置,db文件夹是存放svn转储后的数据。 

cd conf/  
ls 
    authz  passwd  svnserve.conf 

# authz文件是设置用户权限,passwd文件是存储用户及密码,svnserve.conf是主配置文件,先配置主配置文件。 

4.配置版本库
sudo vi svnserve.conf   

#将以下参数去掉注释

[general]
anon-access = none    #匿名访问权限,默认read,none为不允许访问
auth-access = write    #认证用户权限password-db = passwd  
(注:一定要顶满格,前面不要有空格,不然使用的时候回报错) 
#用户信息存放文件,默认在版本库/conf下面,也可以绝对路径指定文件位置

authz-db = authz   

# sudo vi passwd   
#格式是用户名=密码,采用明文密码   
[users]   
meng = 123 

# sudo vi authz
[groups]  #定义组的用户 
manager = meng 

[repos:/] #以根目录起始的repos版本库manager组为读写权限 
@manager = rw 

5.启动svn服务器,停止svn服务器

sudo svnserve -d -r /home/svn 

# 查看是否启动成 功,可看的监听3690端口 
sudo netstat -antp |grep svnserve 
   tcp 0 0 0.0.0.0:3690 0.0.0.0:* LISTEN 28967/svnserve 

# 如果想关闭服务,可使用killall svnserve 

6.访问svn
访问repos版本库地址svn://192.168.1.100/repos 
其中的ip地址可以使用ifconfig查看

7.导入文件
svn add text.sh
svn ci  

8.导出文件
#svn co svn://192.168.1.100/repos  

以上是关于repo的安装和使用的主要内容,如果未能解决你的问题,请参考以下文章

Android 代码开发工作流

简记Ubuntu下载 Android源码

在Android Repo项目中切换Git分支

在 Android Repo 项目中切换 Git 分支

如何使用 pip 从 git 子目录安装?

git入门(6.repo)