本文需要有對git repo gerrit的基本使用,
這裏不提及過多的基本用法.
00. Books
- ProGit/ProGit 2nd https://git-scm.com/book/zh/v2
建議至少把 第2章 git基礎 看一遍
- Git權威指南 http://www.worldhello.net/gotgit/
建議僅看repo gerrit相關的章節
Android式多版本庫協同
Gerrit代碼審覈服務器
01. Repo 的產生
Android版本庫衆多的原因,主要原因是版本庫太大以及Git不能部分檢出。
如果所有的東西都放在一個庫中,而某個開發團隊感興趣的可能就是某個驅動,
或者是某個應用,卻要下載如此龐大的版本庫,是有些說不過去。
git也有submodule供多個庫下載,但這功能使用不方便,
其侷限性和麻煩可參看
http://www.worldhello.net/got...
如果是你,有什麼方案來管理這麼多的庫?
Repo是Google開發的用於管理Android版本庫的一個工具。
Repo並不是用於取代Git,是用Python對Git進行了一定的封裝,簡化了對多個Git版本庫的管理。
對於repo管理的任何一個版本庫,都還是需要使用Git命令進行操作
02 Repo 如何組織這麼多庫 --manifest文件?
<?xml version="1.0" encoding="UTF-8"?>
<manifest>
<remote name="aosp"
fetch=".." />
<default revision="refs/tags/android-7.1.0_r4"
remote="aosp"
sync-j="4" />
<project path="build" name="platform/build" groups="pdk,tradefed" >
<copyfile src="core/root.mk" dest="Makefile" />
</project>
<project path="build/blueprint" name="platform/build/blueprint" groups="pdk,tradefed" />
......
從上看出,repo用清單文件來管理, 其內容爲版本的地址,默認分支名,遠程庫和本地路徑對應關係。
一個project對應一個庫,path爲本地切出來的工作目錄的路徑,也就是我們看到的代碼路徑,
name爲對應的遠程git庫的名字/路徑。
注意,一般說來,一套安卓代碼都由好幾百個庫組成,上面只截取了一部分。
關於manifests更多的信息可查看你代碼根目錄的
.repo/repo/docs/manifest-format.txt
這裏只說下revision,
- 你可以在project裏通過revision指定與清單文件default裏不一樣的分支,
revision的值可能是分支/tag/commitID等形式
- 你也可以用repo manifest -r命令生成帶revision信息的清單文件,可用於代碼發佈
生成的一個例子:
<project name="device/qcom/common" revision="3a83da1dff148dd709caac602693d3295bd0a18b" upstream="refs/heads/省略">
03 repo init 在幹什麼?
$repo init --help
Usage: repo init [options]
Options:
...... Manifest options:
-u URL, --manifest-url=URL
manifest repository location
-b REVISION, --manifest-branch=REVISION
manifest branch or revision
-m NAME.xml, --manifest-name=NAME.xml
initial manifest file
--mirror create a replica of the remote repositories rather
than a client working directory
--reference=DIR location of mirror directory
--depth=DEPTH create a shallow clone with given depth; see git clone
...... repo Version options:
--repo-url=URL repo repository location
--repo-branch=REVISION
repo init用法如上, 我們一般下載code的方式爲
repo init -u xxx -b yyy -m zzz.xml
repo sync -c
注意
- -m 當有多個清單文件,可以指定清單庫的某個清單文件爲有效的清單文件
repo init命令執行後主要乾了兩件事
- 下載repo到.repo/repo裏
- 下載並檢出-u所指定的manifest庫,並建立.repo/manifest.xml鏈接
對於第一步大家可能比較疑問,不是已經有個repo了嗎?爲什麼還在下載repo?
實際上,我們執行的repo命令只是相當於個當函數,真正的執行命令(如repo sync)
都是.repo/repo/subcmds裏的,
該子命令都用python寫的, 所以當有需要,或者執行出錯時想查看源碼的話可在此目錄下查看.
04 --mirror --reference作用
讓我們想個問題,假設你一套代碼有100G,
- 你們是異地協作協作,如需要上海/北京兩地辦公,主服務器在北京,網絡很慢,
如何爲上海的同事減少下代碼時間? 如何緩解主服務器的壓力? - 你們都在一個地辦公,多人公用一個服務器, 如何節省下載代碼時間? 節省服務器空間?
- 你作爲SCM,每天都要完全clean編譯版本, 如何更快的構建?
當然我們這隻講repo本身提供的方法,
- --mirror 建立和上游Android的版本庫一模一樣的鏡像
-
--reference 通過引用已下載的mirror或者代碼加快下載速度,常用使用場景:
- DailyBuild
- 一套代碼兼容多個機型
- 一套代碼需要多個副本
- 多個人共用服務器
具體操作爲
先通過
repo init .... --mirror
建立一個本地的鏡像,
然後下載代碼時引用這個鏡像
repo init .... --reference=鏡像路徑
repo sync -c
如果此時主服務器庫容量增加到120G,而你的鏡像沒更新,
那麼理論上新下載代碼只需要下載20G的數據,
N套代碼佔用的空間爲100G(鏡像的) + 20G*N (新代碼)
大家可用
du -sh .repo
命令統計.
注意:
不用擔心你用reference下的代碼和主服務器的不同步,
git會自動進行三方對比的,保證能獲取到-u 指定的地址裏的代碼是最新的.
05 Gerrit Change-Id
graph TD;
title(repo gerrit簡單工作流程);
init(repo init/sync) --> start(repo start xxx --all);
start --> gitmodify(單個庫的修改和git流程一樣);
gitmodify --> upload(上傳到Gerrit repo upload/git push);
upload --> review(審覈 +1 +2);
review-- 通過 --> submit(Gerrit submit);
review-- 不通過 --> gitmodify;
Change-Id由git commit時調用.git/hooks/commit-msg鉤子生成的,
gerrit靠該id來區分同一分支下是否爲同一個提交,
事實上,只要gerrit未submit,可以在本地git commit XX --amend修正提交後,
可以再次提交,成爲新的patchset,但提交號不變.
06 repo upload時gerrit帳號名與郵箱前綴不一致
repo upload時默認是用配置的郵箱前綴做爲push的用戶名,
如果您的郵箱前綴和gerrit賬戶名不一致,需要做如下配置
$ cat ~/.gitconfig
[review "您的地址"]
username = 您的帳號名
07 Gerrit command
該功能可能SCM用得多,用於實現批處理腳本.
此處只看下用法
$ ssh -p 端口號 用戶名@地址 gerrit
Available commands of gerrit are:
apropos Search in Gerrit documentation
ban-commit Ban a commit from a project's repository
create-account Create a new batch/role account
create-branch Create a new branch
create-group Create a new account group
create-project Create a new project and associated Git repository
flush-caches Flush some/all server caches from memory
gc Run Git garbage collection
gsql Administrative interface to active database
ls-groups List groups visible to the caller
ls-members List the members of a given group
ls-projects List projects visible to the caller
ls-user-refs List refs visible to a specific user
plugin
query Query the change database
receive-pack Standard Git server side command for client side git push
rename-group Rename an account group
review Verify, approve and/or submit one or more patch sets
set-account Change an account's settings
set-members Modify members of specific group or number of groups
set-project Change a project's settings
set-project-parent Change the project permissions are inherited from
set-reviewers Add or remove reviewers on a change
show-caches Display current cache statistics
show-connections Display active client SSH connections
show-queue Display the background work queues
stream-events Monitor events occurring in real time
test-submit
version Display gerrit version
See 'gerrit COMMAND --help' for more information.
08 cherry-pick rebase
這個可看下git書箱學習下,工作中也用得多,提高效率.
09 repo sync (-n -l)
-n -l參數解釋如下:
-l, --local-only only update working tree, don't fetch
-n, --network-only fetch only, don't update working tree
其實repo sync = repo sync -n + repo sync -l
如果你只想獲取更新到.repo庫裏, 不更新本地代碼, 可加上 -n參數
如果你之前已經獲取了更新,只有一兩個庫更新出錯,
而你重新repo sync -c一次都得半小時,
那可以先repo sync -l, 然後單獨的更新出錯的庫.
我一般更新都用命令
repo sync -c -f
repo sync -c -l
備註:
再運行次加-l主要是更新時可能信息很多,中間有些出錯,
而我有不想慢慢看終端找出錯信息,所以乾脆再讓他更新下
本地工作目錄,這樣方便查找出錯信息.
10 Debug
有時候有些運行命令出錯了,可加--trace參數查看更多信息
(git的調試方法請查看progit一書)
eg:
repo --trace sync -c
11 建議
-
新下載代碼後,分支處於no branch狀態,建議下載代碼後用
repo start 本地分支名 --all
建個分支,該分支名爲本地分支名,可任意取名
-
該分支僅用於和服務同步,更新代碼,要修改的話用repo start xx建立個新分支
不然你本地在修改,服務器也修改,會造成歷史記錄很亂,
有時導致編譯出來的代碼有啥隱含bug.
當然,您也可用git pull --rebase