文章大綱
- 引言
- 一、repo 概述
- 1、repo的作業原理概述
- 2、repo 庫的主要結構:**repo庫,manifest庫,子專案倉庫**
- 2.1、專案清單庫(.repo/manifests)
- 2.2、repo腳本庫(.repo/repo)
- 2.3、子專案倉庫(.repo/repo/projects倉庫目錄和作業目錄)
- 二、repo 基本操作
- 1、repo init -u ssh://xxxx/manifest -m 初始化repo倉庫
- 2、repo sync 同步遠程倉庫代碼
- 2.1、本地修改后,未commit 此次修改
- 2.2、本地修改后,已經commit 此次修改
- 3、repo forall -c
引言
repo 極簡操作指南…
一、repo 概述
Git是一種分布式的代碼管理工具,不需要一個中心服務器,在Android中,就包含了上百個專案,每一個專案都是一個獨立的Git倉庫,這意味著,如果我們要創建一個分支來做feature開發,那么就需要到每一個子專案去創建對應的分支,這顯然不能手動地到每一個子專案里面去創建分支,必須要采用一種自動化的批量的方式來處理,repo應運而生,
repo是Android為了方便管理多個git庫而開發的一系列Python腳本(Python通過呼叫git命令來完成自己的功能),repo的出現,并非為了取代git,而是讓Android開發者更為有效的利用git,(Android原始碼包含數百個git庫,僅僅是下載這么多git庫就是一項繁重的任務,所以在下載原始碼時,Android就引入了repo)官方推薦通過Linux curl命令下載repo,下載完后,為repo腳本添加可執行權限,
$ curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
$ chmod a+x ~/bin/repo
$ export PATH=$PATH:~/bin
#初始化一個repo庫,其中,-u 表示清單庫的地址, -m表示使用清單庫中的哪份清單檔案,
$ repo init -m <manifest.xml> -u <manifest-url>
1、repo的作業原理概述
repo需要關注當前git庫的數量、名稱、路徑等,有了這些基本資訊,才能對這些git庫進行操作,通過集中維護所有git庫的清單,repo可以方便的從清單中獲取git庫的資訊,清單會隨著版本升級而產生變化,同時也有一些本地的修改定制需求,所以repo是通過一個名為**manifests的git庫來管理專案的清單檔案的,當打開repo這個可執行的python腳本后,發現代碼量并不大(不超過1000行),難道僅這一個腳本就完成了AOSP數百個git庫的管理嗎?并非如此, repo是一系列腳本的集合,這些腳本也是通過名為repo的git庫來維護的**,當客戶端使用repo命令初始化一個專案時,就會從遠程把manifests和repo這兩個git庫拷貝到本地(但對于Android開發來說,一般通過檔案管理器,是無法看到這兩個git庫的)repo將自動化的管理資訊都隱藏根目錄的.repo子目錄中,
2、repo 庫的主要結構:repo庫,manifest庫,子專案倉庫
所有的這些腳本,repo使用了一個單獨的git倉庫去負責維護它,即repo庫,repo庫中有一個腳本——repo,在將其添加到系統環境變數PATH中后,就可以執行repo命令,而repo庫的下載,可以使用命令repo init --repo-url=< repo庫地址 >,repo實作主要由三部分構成:repo庫,manifest庫,子專案倉庫,
2.1、專案清單庫(.repo/manifests)
一份位于作業目錄(.repo/manifests)的.git目錄下,另一份獨立存放于.repo/manifests.git,清單庫
- 指定不同的清單庫檔案,可以將各倉庫代碼切換到對應的不同節點
- 指定清單庫不同的分支,可以切換不同的清單庫檔案
repo倉庫可通過manifest庫可以獲得所有AOSP子專案倉庫的元資訊,通過這些元資訊我們就可以通過repo倉庫里面的Python腳本來操作AOSP的子專案,而記錄這些元資訊的檔案即以xml格式保存的清單檔案,對這些清單檔案的管理,repo又是單獨使用一個git庫去負責維護它,即清單庫,AOSP專案清單git庫下,只有一個檔案default.xml,是一個標準的XML,描述了當前repo管理的所有資訊, AOSP的default.xml的檔案內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="aosp"
fetch=".."
review="https://android-review.googlesource.com/" />
<default revision="master"
remote="aosp"
sync-j="4" />
<project path="build" name="platform/build" groups="pdk,tradefed" >
<copyfile src="core/root.mk" dest="Makefile" />
</project>
<project path="abi/cpp" name="platform/abi/cpp" groups="pdk" />
<project path="art" name="platform/art" groups="pdk" />
...
<project path="tools/studio/translation" name="platform/tools/studio/translation" groups="notdefault,tools" />
<project path="tools/swt" name="platform/tools/swt" groups="notdefault,tools" />
</manifest>
可以包含以下節點:
-
remote——描述了遠程倉庫的基本資訊,- name——遠程git服務器的名字,默認命名為origin,直接用于git fetch, git remote 等操作
- alias—— 遠程git服務器的別名,如果指定了,則會覆寫name的設定,在一個manifest中,name不能重名,但alias可以重名,
- fetch—— 所有projects的git URL 前綴
- review——用作code review的server地址,指定Gerrit的服務器名,用于repo upload操作,如果沒有指定,則repo upload沒有效果,
-
default——default標簽的定義的屬性,將作為project標簽的默認屬性,在project標簽中,也可以重寫這些屬性,-
remote—— 默認使用的遠程倉庫名稱,之前定義的某一個remote元素中name屬性值,用于指定使用哪一個遠程git服務器,
-
revision—— git分支的名字,表示當前的版本,例如master或者refs/heads/master
-
sync_j—— 在repo sync中sync-j表示在同步遠程代碼時,并發的任務數量,配置高的機器可以將這個值調大,
-
sync_c—— 如果設定為true,則只同步指定的分支(revision 屬性指定),而不是所有的ref內容,
-
sync_s—— 如果設定為true,則會同步git的子專案
-
-
manifest-server元素——只能有一個該元素,它的url屬性用于指定manifest服務的URL,通常是一個XML RPC 服務,它要支持一下RPC方法:- GetApprovedManifest(branch, target)—— 回傳一個manifest用于指示所有projects的分支和編譯目標,
target引數來自環境變數TARGET_PRODUCT和TARGET_BUILD_VARIANT,組成 T A R G E T P R O D U C T ? TARGET_PRODUCT- TARGETP?RODUCT?TARGET_BUILD_VARIANT, - GetManifest(tag)—— 回傳指定tag的manifest
- GetApprovedManifest(branch, target)—— 回傳一個manifest用于指示所有projects的分支和編譯目標,
-
project——每一個repo管理的git庫,就是對應到一個project標簽,path描述的是專案相對于遠程倉庫URL的路徑,同時將作為對應的git庫在本地代碼的路徑; name用于定義專案名稱,命名方式采用的是整個專案URL的相對地址, 譬如,AOSP專案的URL為https://android.googlesource.com/,命名為platform/build的git庫,訪問的URL就是https://android.googlesource.com/platform/build- name—— 唯一的名字標識project,同時也用于生成git倉庫的URL,格式如下:
r e m o t e f e t c h / {remote_fetch}/ remotef?etch/{project_name}.git - path—— 可選的路徑,指定git clone出來的代碼存放在本地的子目錄,如果沒有指定,則以name作為子目錄名,
- remote—— 指定之前在某個remote元素中的name,
- revision—— 指定需要獲取的git提交點,可以是master, refs/heads/master, tag或者SHA-1值,
- groups—— 列出project所屬的組,以空格或者逗號分隔多個組名,所有的project都自動屬于"all"組,每一個project自動屬于
name——‘name’ 和path——'path’組,例如,它自動屬于default, name——monkeys, and path——barrel-of組,如果一個project屬于notdefault組,則,repo sync時不會下載, - sync_c—— 如果設定為true,則只同步指定的分支(revision 屬性指定),而不是所有的ref內容,
- sync_s—— 如果設定為true,則會同步git的子專案,
- upstream—— 在哪個git分支可以找到一個SHA1,用于同步revision鎖定的manifest(-c 模式),該模式可以避免同步整個ref空間,
- annotation—— 可以有多個annotation,格式為name-value pair,在repo forall 命令中這些值會匯入到環境變數中,
- remove-project—— 從內部的manifest表中洗掉指定的project,經常用于本地的manifest檔案,用戶可以替換一個project的定義,
- include—— 通過name屬性可以引入另外一個manifest檔案(路徑相對與manifest repository’s root),
- name—— 唯一的名字標識project,同時也用于生成git倉庫的URL,格式如下:
如果需要新增或替換一些git庫,可以通過修改default.xml來實作,repo會根據配置資訊,自動化管理,但直接對default.xml的定制,可能會導致下一次更新專案清單時,與遠程default.xml發生沖突, 因此,repo提供了一個種更為靈活的定制方式local_manifests:所有的定制是遵循default.xml規范的,檔案名可以自定義,譬如local_manifest.xml, another_local_manifest.xml等, 將定制的XML放在新建的.repo/local_manifests子目錄即可,repo會遍歷.repo/local_manifests目錄下的所有*.xml檔案,最終與default.xml合并成一個總的專案清單檔案manifest.xml,
$ ls .repo/local_manifests
local_manifest.xml
another_local_manifest.xml
$ cat .repo/local_manifests/local_manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<project path="manifest" name="tools/manifest" />
<project path="platform-manifest" name="platform/manifest" />
</manifest>
2.2、repo腳本庫(.repo/repo)
repo對git命令進行了封裝,提供了一套repo的命令集(包括init, sync等),所有repo管理的自動化實作也都包含在這個git庫中, 在第一次初始化的時候,repo會從遠程把這個git庫下載到本地,所有的這些腳本,repo使用了一個單獨的git倉庫去負責維護它,即repo庫,repo庫中有一個腳本——repo,在將其添加到系統環境變數PATH中后,就可以執行repo命令,而repo庫的下載,可以使用命令repo init --repo-url=< repo庫地址 >
2.3、子專案倉庫(.repo/repo/projects倉庫目錄和作業目錄)
倉庫目錄保存的是歷史資訊和修改記錄,作業目錄保存的是當前版本的資訊,子專案本身就是git管理的完成倉庫,因此都有一個.git目錄,就在子專案的根目錄,repo管理模式下,每一個AOSP子專案的作業目錄也有一個.git目錄,不過這個.git目錄是一個符號鏈接,實際鏈接到.repo/repo/projects對應的Git目錄,即子專案的作業目錄和Git目錄都是分開存放的,其中,作業目錄位于AOSP根目錄下,Git目錄位于.repo/repo/projects目錄下,這樣我們就既可以在AOSP子專案的作業目錄下執行Git命令,也可以在其對應的Git目錄下執行Git命令,一般要訪問到作業目錄的命令(例如git status)需要在作業目錄下執行,而不需要訪問作業目錄(例如git log)可以在Git目錄下執行,
二、repo 基本操作
1、repo init -u ssh://xxxx/manifest -m 初始化repo倉庫
2、repo sync 同步遠程倉庫代碼
要取得 upstream 最新的 code,只要執行下 repo sync 就行,等價于對每個 project 做 git pull 的批量處理,不過如果你本地曾對 source tree 進行過一些修改,repo sync 可能遇到不同的問題,
-
-d——同步repo所管理的各個git工程的代碼,要不丟失本地修改,強制同步遠端服務器代碼并將各子工程的當前分支detach到no branch狀態,repo sync -d命令會將 HEAD 強制指向 repo manifest 版本,而忽略本地的改動,即使同時提供-d和--force-sync兩個選項,還是不能強制覆寫本地修改,若第一次運行 repo sync ,則相當于 git clone ,會把 repository 中的所有內容都拷貝到本地,若不是第一次運行 repo sync ,則相當于 git remote update ; git rebaseorigin/branch . repo sync 會更新 .repo 下面的檔案,如果在merge 的程序中出現沖突,需要手動運行 git rebase --continue
-
-c——
repo sync的正確使用姿勢:
2.1、本地修改后,未commit 此次修改
若只是單純地修改,還未進行 git commit 操作時,執行 repo sync 時會將 upstream 和你的本地修改做合併(merge);如果若有沖突(conflict),則repo sync 就會失敗(不過,你的修改依然存在,不會被蓋掉),為了避免因沖突導致的失敗,最好是先用 git stash 快取你的修改,再 repo sync,最后再git stash pop 將修改apply到repo sync 后的結果上(若有沖突可能需要手動修正),假如你修改的是frameworks/base:
$ cd frameworks/base
$ git stash
$ cd ../..
$ repo sync frameworks/base
$ cd frameworks/base
$ git stash pop
2.2、本地修改后,已經commit 此次修改
若已將修改 commit ,執行 repo sync 時會根據你的 branch 是否為 remote-tracking branch 而有所不同,若不是 remote-tracking branch,則 repo sync 的等價于 git checkout 至 upstream 相對應 branch 的 tip (即最新的 commit),可能會顯示以下的資訊:
$ repo sync frameworks/base
frameworks/base/: discarding 3 commits
不要擔心,它只代表你的 HEAD 已被切換到 upstream,你原來的 commit 并沒有真的被丟掉,你仍然可以通過以下命令切換回來
$ cd frameworks/base
$ git checkout ORIG_HEAD
其中ORIG_HEAD 指 repo sync 切換前的 HEAD,然后再用 git rebase把你的修改 apply 到 upstream tip 上:
# (如果你在弄的是 froyo-x86、… 就把 gingerbread-x86 換成 froyo-x86、…)
$ git rebase m/gingerbread-x86
以上這些操作能不能自動完成? 當然可以,這就是 remote-tracking branch 的意義,若你的 commit 是在一個remote-tracking branch 上,則repo sync 就會將你的 commit apply 到 upstream tip 上,例如:
$ repo sync frameworks/base
project frameworks/base/
First, rewinding head to replay your work on top of it...
Applying: fix wifi issues
git branch -v 時顯示(no branch)
$ git checkout -b mybranch m/gingerbread-x86
Branch mybranch set up to track remote branch gingerbread-x86 from x86.
Switched to a new branch ‘mybranch’
3、repo forall -c <git 命令> 批量執行git 命令
4、repo 分支管理
repo上創建分支很簡單,就是git創建新分支一樣,repo只不過是利用git(manifest倉庫)來記錄管理多個git倉庫而已,因此我們利用repo創建一個新的分支,即給repo管理的每個git倉庫創建一個一樣的新分支,
4.1、repo 創建新分支
4.1.1、repo start new_branch_name創建,
“.” 代表當前作業的branch 分支
4.1.2、repo forall -c “git checkout -b new_branch_name”
repo forall -c 意思是遍歷所有的git倉庫(除了管理的倉庫manifest外),并在每個倉庫(除了管理的倉庫manifest外)執行-c后面所指定的命令,-c即command,
repo forall -c "git checkout -b new_branch_name"
如上面就是在每個倉庫(除了管理的倉庫manifest外)都執行git checkout -b new_branch_name命令,那么這樣就可以給每個倉庫創建了一個一樣的新分支了,
4.2、repo 推送到遠程代碼倉庫
repo forall -c "git push origin local_branch_name"
4.3、新分支添加到manifest倉庫
manifest倉庫是管理repo下面其他倉庫的,因此我們要讓repo知道我們創建了新分支,好讓同步的時候可以根據分支名來同步分支,
- 為manifest倉庫創建新分支new_branch_name
因為repo forall -c的命令是除了.repo/manifest下的倉庫都進行git命令,所以我們還需要在.repo/manifest也創建一個分支.
.repo/manifests$ git checkout -b new_branch_name
- 修改清單default.xml
<default remote="origin" revision="new_branch_name" sync-j="4"/>
-
把新分支推上服務器
git add default.xml git commit -m "add a new branch" git push origin new_branch_name
5、repo管理的倉庫怎么切換
repo forall -c + git 命令,可以實作,但不建議,我們推薦使用基于manifest的分支切換,好處是敲的命令更短,而且不容易出錯,
repo init -m xxx.xml
repo sync -d
使用前保證本地代碼是都已經提交了,也就是干凈的代碼,
5.1、如何得知應該是哪個xxx.xml?
xxx.xml實際是清單庫,記錄的是repo管理的各個子代碼倉庫的分支資訊,一般保存在工程根目錄 .repo/manifests/ 檔案夾, 里面可以看到各種xxx.xml,為了方便記憶,我們一般清單庫的名字和分支的名字是一樣的,示例:打開platform.xml,內容如下,關注 <default revision=“platform” 這一行,其中的revision="platform"表示默認分支是platform,
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="origin" review="review.source.android.com" fetch="../../" />
<default revision="platform" remote="origin" sync-j="4" />
<project path="bionic" name="xinyun/qcom/bionic" />
<project path="hardware" name="xinyun/qcom/hardware" />
<project path="device" name="xinyun/qcom/device" />
5.2、如何得知當前代碼的具體提交節點資訊呢
repo manifest -r
結果如下,注意revision欄位,全部是具體的hash
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote fetch=".." name="origin" review="http://review.omapzoom.org/"/>
<default remote="origin" revision="mpt320" sync-j="4"/>
<project name="xxxx/DVRIP" path="DVRIP" revision="21446707a55885b0d85c4251841bb6fc0beaebd6" upstream="mpt320"/>
<project name="xxxx/MPT" path="MPT" revision="02dea0e19fa224c46760d075137c7fe9ec24ab00" upstream="mpt320">
<copyfile dest="build.sh" src="Tools/build.sh"/>
<copyfile dest="ssh-login.sh" src="Tools/ssh-login.sh"/>
</project>
<project name="xxxx/MPTApp" path="MPTApp" revision="04b0734cf2888759ba28be70d683f25401aca7bf" upstream="mpt320"/>
<project name="xxxx/MPTRpcServer" path="MPTRpcServer" revision="d1ebb9d4676abc287c127e47baa65cac8c85a92f" upstream="mpt320
<project name="xxxx/Manager" path="Manager" revision="4e3803aa0984158cf2511b2efd2b4384d2c52cae" upstream="mpt320"/>
<project name="xxxx/Media" path="Media" revision="28a3bba254b30c29b74527e4d7132c044c345176" upstream="mpt320"/>
<project name="xxxx/PAL" path="PAL" revision="23986988975fed2f0b0b2ee6bcefea1cd2040f6d" upstream="mpt320"/>
<project name="xxxx/Record" path="Record" revision="e6594eb6f7942365c0157e47d7020b11b3ac084e" upstream="mpt320"/>
</manifest>
6、repo download target_revision 下載指定版本
下載特定的版本到本地,例如: repo downloadpltform/frameworks/base 1241 下載修改版本為 1241 的代碼
未完待續…
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/272521.html
標籤:其他
