同步發布平台
- 博客園: https://www.cnblogs.com/jiangxinnju/
- CSDN: https://blog.csdn.net/jiangxinnju
- 掘金: https://juejin.cn/user/166781500533079
- 知乎: https://www.zhihu.com/people/jiangxinnju/posts
未經允許,謝絕轉載
Repo簡介
Android使用Git作為代碼管理工具,開發了Gerrit進行代碼審核以便更好的對代碼進行集中式管理,還開發了Repo命令行工具,對Git命令進行封裝,將幾百個Git庫有效的進行組織。Repo並不是用來取代Git,而是用Python對Git進行了一定的封裝,簡化了對多個Git版本庫的管理。對應Repo管理的任何一個版本庫,都需要使用Git命令進行操作。
Repo工作流
下圖是Repo工作流,大體分為如下幾個核心步驟:
- 運行
repo init
,克隆Android的一個清單庫。這個清單庫是通過XML技術建立的版本庫清單。清單庫中的manifest.xml文件,列出了幾百個版本庫的克隆方式。包括版本庫的地址和工作區地址的對應關系,以及分支的對應關系。 - 運行
repo sync
,分別克隆這幾百個版本庫到本地的工作區。 - 運行
repo start
創建並切換到本地工作分支。 - 本地修改代碼,通過Git相關命令在某些項目中進行操作。
- 通過
repo upload
命令將代碼修改發布到代碼審核服務器。
Repo引導腳本下載
在使用Repo前我們需要下載一個Repo引導腳本,Repo的核心功能不在其中,該引導腳本只是下載並加載完整Repo程序的工具。
mkdir ~/bin
PATH=~/bin:$PATH
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo
這里需要提到一點的是早期的Repo引導腳本是一個Shell腳本,第一行就是#!/bin/sh
,然后通過以下代碼完成Shell向Python的轉換,不過在較新版本中都是直接使用Python,第一行變成了#!/usr/bin/env python
。現在網絡上的很多介紹都過時了。
magic='--calling-python-from-/bin/sh--'
"""exec" python -E "$0" "$@" """#$magic"
Repo清單庫介紹
一個清單庫可以包含多個清單文件和多個分支,每個清單文件和分支都有對應的版本。清單文件以XML格式組織。舉個例子:
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-11.0.0_r27
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="aosp"
fetch=".."
review="https://android-review.googlesource.com/" />
<default revision="refs/tags/android-11.0.0_r27"
remote="aosp"
sync-j="4" />
<project path="build/make" name="platform/build" groups="pdk" >
<copyfile src="core/root.mk" dest="Makefile" />
<linkfile src="CleanSpec.mk" dest="build/CleanSpec.mk" />
<linkfile src="buildspec.mk.default" dest="build/buildspec.mk.default" />
<linkfile src="core" dest="build/core" />
<linkfile src="envsetup.sh" dest="build/envsetup.sh" />
<linkfile src="target" dest="build/target" />
<linkfile src="tools" dest="build/tools" />
</project>
<project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
...
</manifest>
- remote元素,定義了名為aosp的遠程版本庫,其庫的基址為https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform,還定義了代碼審核服務器的地址https://android-review.googlesource.com/。當然,還可以定義更多的remote元素。
- default元素,設置各個項目默認遠程版本庫為aosp,默認的的分支為
refs/tags/android-11.0.0_r27
。當然各個project元素還可以定義自己的remote和revision覆蓋默認的配置。 - project元素,用於定義一個項目,path屬性表示在工作區克隆的位置,name屬性表示該項目的遠程版本庫的相對路徑。
- project元素的子元素copyfile,定義了項目克隆后的一個附件動作,從src拷貝文件到dest。
通過Repo下載AOSP系統源碼
現在你可以通過Repo下載AOSP源碼了,但是由於牆的原因,我們沒有辦法直接下載,需要通過一些AOSP鏡像,其中使用比較多的是清華的鏡像,具體下載方式請參考官方介紹:https://mirrors.tuna.tsinghua.edu.cn/help/AOSP/
Repo下載AOSP過程中可能遇到的問題
- 某些project找不到:
...
Checking out projects: 58% (432/733) platform/frameworks/hardware/interfaceserror: Cannot checkout platform/frameworks/layoutlib: ManifestInvalidRevisionError: revision refs/tags/android-10.0.0_r47 in platform/frameworks/layoutlib not found
error: in `sync -c -j4`: revision refs/tags/android-10.0.0_r47 in platform/frameworks/layoutlib not found
這個問題我一直沒有找到根因,可能是鏡像的問題,也可能是網絡的問題。解決方式發現哪個project找不到就單獨同步該項目,然后再整體同步。
repo sync -c platform/frameworks/layoutlib
repo sync -c -j4
Repo常用指令
Repo子命令實際上是Git命令的封裝。每一個Repo子命令都對應於repo源碼樹中subcmds目錄下的一個同名的Python文件。每一個repo子命令都可以通過下面的命令獲得幫助。
repo help <command>
當然你也可以參考Repo官方的介紹:https://source.android.com/setup/develop/repo
repo init
repo init –u URL [OPTIONS]
常用參數如下,其它參數通過repo help init查詢:
- -u(--manifest-url):設定清單庫的Git服務器地址
- -m(--manifest-name):當有多個清單文件時,指定清單庫中的某個清單為有效的清單文件。默認為default.xml
- -b(--manifest-branch):選擇一個maniest倉庫中的一個特殊的分支
命令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 init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-11.0.0_r27 # 在當前目錄出現了.repo文件夾
repo init -u git://192.168.0.125/manifest.git –m android.xml # 選擇的是android.xml里面的配置,.repo/manifest.xml便指向.repo/manifests/android.xml
repo sync
repo sync [<project>…]
用於參照清單文件.repo/manifest.xml
克隆並同步版本庫。如果某個項目版本庫尚不存在,則執行repo sync 命令相當於執行git clone,如果項目版本庫已經存在,則相當於執行下面的兩條指令:
git remote update # 相當於對每一個remote源執行了fetch操作
git rebase origin/branch # 針對當前分支的跟蹤分支執行rebase操作
如果直接執行repo sync
會同步所有project,如果后面指定project則只會同步指定的project。如repo sync platform/build
。
repo rebase
repo smartsync
可以通過一些選項設置同步的方式,比如是否在遇到第一個錯誤的時候就停止,是否強制刪除含有未提交修改的項目等等。
repo start
repo start <newbranchname> [--all | <project>…]
剛克隆下來的代碼是沒有分支的,repo start
實際是對git checkout –b
命令的封裝。為指定的項目或所有項目(若使用—all參數),以清單文件中為設定的分支,創建特性分支。這條指令與git checkout –b
還是有很大的區別的,git checkout –b
是在當前所在的分支的基礎上創建特性分支,而repo start
是在清單文件設定分支的基礎上創建特性分支。
repo start stable --all # 假設清單文件中設定的分支是gingerbread-exdroid-stable,那么執行以上指令就是對所有項目,在gingerbread-exdroid-stable的基礎上創建特性分支stable
repo start stable platform/build platform/bionic # 假設清單文件中設定的分支是gingerbread-exdroid-stable,那么執行以上指令就是對platform/build、platform/bionic項目,在gingerbread-exdroid-stable的基礎上創建特性分支stable
repo checkout
repo checkout <branchname> [<project>…]
實際上是對git checkout
命令的封裝,檢出之前由repo start
創建的分支。但不能帶-b參數,所以不能用此命令來創建特性分支。
repo checkout aosp-dev
repo checkout aosp-dev platform/build platform/bionic
repo branches
讀取各個項目的分支列表並匯總顯示。該命令實際上通過直接讀取.git/refs
目錄下的引用來獲取分支列表,以及分支的發布狀態等。
repo branches [<project>…]
repo branches
repo branches platform/build platform/bionic
repo diff
repo diff [<project>…]
實際是對git diff 命令的封裝,用於分別顯示各個項目工作區下的文件差異。
repo diff # 查看所有項目
repo diff platform/build platform/bionic # 只查看其中兩個項目
repo stage
實際是對git add --interactive
命令的封裝、用於挑選各個項目工作區中的改動以加入暫存區。
repo stage -i [<project>…]
-i代表git add --interactive
命令中的--interactive
,給出個界面供用戶選擇。
repo prune
實際上是對git branch –d
命令的封裝,該命令用於掃面項目的各個分支,並刪除已經合並的分支,用法如下:
repo prune [<project>…]
repo abandon
實際上是對git branch –D
命令的封裝,用法如下:
repo abandon <branchname> [<project>…]
repo status
實際上是對git diff-index
、git diff-filse
命令的封裝,同時顯示暫存區的狀態和本地文件修改的狀態
repo status platform/bionic
以上的實例輸出顯示了platform/bionic項目分支的修改狀態
- 每個小節的首行顯示羡慕名稱,以及所在分支的名稱
- 第一個字母表示暫存區的文件修改狀態
- -:沒有改變
- A:添加(不在HEAD中,在暫存區中)
- M:修改(在HEAD中,在暫存區中,內容不同)
- D:刪除(在HEAD中,不在暫存區)
- R:重命名(不在HEAD中,在暫存區,路徑修改)
- C:拷貝(不在HEAD中,在暫存區,從其他文件拷貝)
- T:文件狀態改變(在HEAD中,在暫存區,內容相同)
- U:未合並,需要沖突解決
- 第二個字母表示工作區文件的更改狀態
- -:新/未知(不在暫存區,在工作區)
- m:修改(在暫存區,在工作區,被修改)
- d:刪除(在暫存區,不在工作區)
- 兩個表示狀態的字母后面,顯示文件名信息。如果有文件重名還會顯示改變前后的文件名及文件的相似度
repo remote
repo remote add <remotename> <url> [<project>…]
repo remote rm <remotename> [<project>…]
repo remote add origin_1 ssh://192.168.0.125/git_repo # 這個指令是根據xml文件添加的遠程分支,方便於向服務器提交代碼,執行之后的build目錄下看到新的遠程分支org
repo remote rm origin_1 # 刪除遠程倉庫
repo push
repo push <remotename> [--all |<project>…]
這是新添加的指令,用於向服務器提交代碼,repo會自己查詢需要向服務器提交的項目並提示用戶。
repo push org
repo forall
repo forall [<project>…] –c <command>
迭代器,可以在所有指定的項目中執行同一個shell指令
- -c:后面所帶的參數着是shell指令
- -p:在shell指令輸出之前列出項目名稱
- -v:列出執行shell指令輸出的錯誤信息
額外的環境變量:
- 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 grep
相當於對git grep 的封裝,用於在項目文件中進行內容查找。
repo manifest
顯示manifest文件內容,可以通過-o參數輸出到指定的文件中。
repo manifest –o android.xml
repo version
顯示Repo的版本號,還會同時顯示Git/Python等依賴的應用版本。
repo upload
repo upload相當於git push,但是又有很大的不同。它不是將版本庫改動推送到克隆時的遠程服務器,而是推送到代碼審核服務器(Gerrit軟件架設)的特殊引用上,使用SSH協議。代碼審核服務器會對推送的提交進行特殊處理,將新的提交顯示為一個待審核的修改集,並進入代碼審查流程,只有當審核通過后,才會合並到官方正式的版本庫中。
repo upload [--re --cc] {[<project>]… | --replace <project>}
- -h, --help:顯示幫助信息
- -t:發送本地分支名稱到Gerrit代碼審核服務器
- --replace:發送此分支的更新補丁集
- --re=REVIEWERS:要求指定的人員進行審核
- --cc=CC:同時發送通知到如下郵件地址
repo download
主要用於代碼審核者下載和評估貢獻者提交的修訂。
repo download {project change [patchset]}…
repo selfupdate
用於repo自身的更新