轉自文章《Android內核開發:理解和掌握repo工具》和《Repo的理解和用法小結2》
1. repo是什麼?
repo是一種代碼版本管理工具,它是由一系列的Python腳本組成,封裝了一系列的Git命令,用來統一管理多個Git倉庫。
2. 爲什麼要用repo?
因爲Android源碼引用了很多開源項目,每一個子項目都是一個Git倉庫,每個Git倉庫都有很多分支版本,爲了方便統一管理各個子項目的Git倉庫,需要一個上層工具批量進行處理,因此repo誕生。
repo也會建立一個Git倉庫,用來記錄當前Android版本下各個子項目的Git倉庫分別處於哪一個分支,這個倉庫通常叫做:manifest倉庫。
3. 怎麼安裝repo?
官方的repo腳本下載方法:
curl http://commondatastorage.googleapis.com/git-repo-downloads/repo > ./repo
由於官網被牆,目前可以使用的repo腳本下載方法如下(兩者選一):
$ git clone git://git.omapzoom.org/git-repo.git $ git clone git://aosp.tuna.tsinghua.edu.cn/android/git-repo.git/ $ cp git-repo/repo ./repo
或者修改手頭已有的被牆的repo文件:
REPO_URL = ‘git://git.omapzoom.org/git-repo.git‘ REPO_URL = ‘git://aosp.tuna.tsinghua.edu.cn/android/git-repo‘ REPO_REV = ‘stable‘
當然,你也可以去我的GitHub下載這個repo文件,地址:
https://github.com/Jhuster/AOSP/blob/master/repo
4. 怎麼下載源碼?
上面說過,Android源碼分支其實由一個叫manifest倉庫來管理起來的,因此,下載源碼首先要clone這個manifest倉庫。這個倉庫裏面有一個XML文件,其實就是一個文件清單,列出了本代碼倉庫依賴哪些代碼,該去哪下載,分支是什麼。
一般用repo init命令來clone這個manifest倉庫,例如,如果要下載Android源碼,則方法如下:
$ repo init -u https://android.googlesource.com/platform/manifest
當然,上面的官網被牆了,因此,推薦如下鏡像(兩者選一):
$ repo init -u git://git.omapzoom.org/platform/manifest.git $ repo init -u git://aosp.tuna.tsinghua.edu.cn/android/platform/manifest
初始化完畢後,你會在本地的.repo文件夾中看到manifest倉庫的內容,這個文件夾中最重要的文件是manifest.xml(有的倉庫用的是default.xml,然後指向具體的xml),它就是上面說到的文件清單。
如果要選擇特定版本的Android源碼,或者在已下載的源碼基礎上切換到其他版本,則可以使用-b選項:
$ repo init -u git://git.omapzoom.org/platform/manifest.git -b android-5.0.2_r1 $ repo init -u git://aosp.tuna.tsinghua.edu.cn/android/platform/manifest -b android-5.0.2_r1
然後使用 repo sync 命令進行同步即可下載好全部的Android源碼了。
5. manifest.xml文件清單的組成
上面提到了repo init需要初始化一個manifest倉庫,倉庫中含有一個很重要的manifest.xml文件清單,其實這個manifest.xml並不複雜的,它就是用XML文件的格式記錄了本項目依賴的各個Git倉庫的名稱、地址,以及分支等信息。常用的元素如下所示:
(1) manifest 最頂層的XML元素
(2) remote 設置遠程git服務器的屬性,如名稱、根URL地址等
(3) project 需要clone的Git倉庫,path表示本機路徑,name表示遠程版本庫的相對路徑
(4) copyfile 執行拷貝操作,把URL/$src地址的文件拷貝到./$dest
其實,如果不使用repo工具,也是可以對照manifest.xml文件清單直接使用“git clone”的方式一個project一個project的下載的,然後對每個project進行git checkout特定的分支。
7. 常用repo命令
這一塊網上文章很多,我就不詳細講解了,只列出常用命令。
(1) repo init // 初始化repo倉庫
(2) repo sync // 下載源碼
(3) repo start // 創建分支
(4) repo checkout //切換分支
(5) repo branches //查看分支
(6) repo status //查看文件狀態
下面對其中的命令進行詳細介紹:
1. repo init
repo init -u manifest_git_path -m manifest_file_name -b branch_name --repo-url=repo_url --no-repo-verify
- 1
在當前目錄下安裝 Repo。這會產生一個 .repo/ 目錄,目錄包括裝 Repo 源代碼和標準 Android 清單文件的 Git 倉庫。.repo/ 目錄還包括 manifest.xml,是一個在 .repo/manifests/ 目錄選擇清單的符號鏈接。
選項:
-u: 指定Manifest庫的Git訪問路徑。
-m: 指定要使用的Manifest文件。
-b: 指定要使用Manifest倉庫中的某個特定分支。
–repo-url: 指定要檢查repo是否有更新的遠端repoGit庫的訪問路徑。
–no-repo-verify: 指定不檢查repo庫是否需要更新。
2. repo sync
repo sync [project_name]
- 1
用於參照清單文件克隆並同步版本庫。可以使用repo sync project_name的形式只克隆某個項目。。
實現參照清單.repo/manifests.xml克隆並同步版本庫,如果版本庫不存在,則相當於執行
git clone
- 1
如果版本庫已經存在,則相當於執行
#對每個remote源進行fetch操作
git remote update
#針對當前分支的跟蹤分支進行rebase操作
git rebase/origin/branch
- 1
- 2
- 3
- 4
選項:
-d:切換指定項目回到清單修正。如果該項目目前是一個主題分支那就有幫助,但清單修正是暫時需要。
-s:同步到一個已知的構建 manifest-server 在當前清單指定的元素。
-f:繼續同步其他項目,即使有項目同步失敗。
3. repo start
repo start <newbranchname> [--all|<project>...]
- 1
創建並切換分支。剛克隆下來的代碼是沒有分支的,repo start實際是對git checkout -b命令的封裝。
爲指定的項目或所有的項目(若使用-all),以清單文件中爲設定的分支,創建特定的分支。
這條指令與git checkout -b 還是有很大區別的。
· git checkout -b 是在當前所在的分支的基礎上創建特性分支。
· 而repo start 是在清單文件設定的分支的基礎上創建特性分支。
repo start stable --all
- 1
假設清單文件中設定的分支是gingerbread-exdroid-stable,那麼執行以上指令就是對所有項目,在gingerbread-exdroid-stable的基礎上創建特性分支stable。
repo start stable platform/build platform/bionic
- 1
假設清單文件中設定的分支是gingerbread-exdroid-stable,那麼執行以上指令就是對platform/build、platform/bionic項目,在gingerbread-exdroid-stable的基礎上創建特性分支stable。
4. repo checkout
<branchname> [<rpoject>...]{{{
repo checkout <branchname> [<project>...]
}}}
- 1
- 2
- 3
切換分支。 實際上是對git checkout命令的封裝,但不能帶-b參數,所以不能用此命令來創建特性分支。
示例:
repo checkout liuq-dev
repo checkout liuq-dev skipper/build platform/bionic
- 1
- 2
5. repo branches
repo branches [<project>...]
- 1
查看分支。
示例:
repo branches
repo branches skipper/build skipper/release
#查看可切換的分支
cd .repo/manifests
git branch -a | cut -d / -f 3
- 1
- 2
- 3
- 4
- 5
6. repo diff
repo diff [<project>...]
- 1
查看工作區文件差異。實際是對git diff命令的封裝,用於分別顯示各個項目工作區下的文件差異。在 commit 和工作目錄之間使用 git diff 顯示明顯差異的更改。
示例:
#查看所有項目
repo diff
#只查看其中的兩個項目
repo diff skipper/build skipper/release
- 1
- 2
- 3
- 4
7. repo stage
repo stage -i [<project>...]
- 1
把文件添加到index表中。實際上是對git add –interactive命令的封裝,用於挑選各個項目中的改動以加入暫存區。
-i表示git add –interactive命令中的–interactive,給出一個界面供用戶選擇。
8. repo prune
repo prune [<project>...]
- 1
刪除已經合併分支。實際上是對git branch -d 命令的封裝,該命令用於掃描項目的各個分支,並刪除已經合併的分支。
9. repo abandon
repo abandon <branchname> [<rpoject>...]
- 1
刪除指定分支。實際是對git brance -D命令的封裝。
10. repo status
repo status [<project>...]
- 1
查看文件狀態。
示例:
#輸出skipper/build項目分支的修改狀態
repo status skipper/build
- 1
- 2
每個小節的首行顯示項目名稱,以及所在的分支的名稱。
每個字母表示暫存區的文件修改狀態。
字母 含義 描述 - 無變化 沒有修改,在 HEAD 和在索引中是一樣的 A 添加 不在HEAD中,在暫存區中 M 修改 在HEAD中, 在暫存區中,內容不同 D 刪除 在HEAD中,不在暫存區 R 重命名 不在HEAD中,在暫存區中 C 拷貝 不在HEAD中,在暫存區,從其他文件拷貝 T 文件狀態改變 在HEAD中,在暫存區,內容相同 U 未合併 需要衝突解決 第二個字符表示工作區文件的更改狀態。
字母 含義 描述 - 新/未知 不在暫存區,在工作區 m 修改 在暫存區,在工作區,被修改 d 刪除 在暫存區,不在工作區 兩個表示狀態的字母后面,顯示文件名信息。如果有文件重名還會顯示改變前後的文件名及文件的相似度。
11. repo remote
repo remote add <remotename> <url> [<project>...]
repo remote rm <remotename> [<project>...]
- 1
- 2
設置遠程倉庫。
示例:
repo remote add org ssh://10.11.10.11/git_repo
- 1
這個指令根據xml文件添加的遠程分支,方便於向服務器提交代碼,執行之後的build目錄下看到新的遠程分支org。
#刪除遠程倉庫
repo remote rm org
- 1
- 2
12. repo push
repo push <remotename> [--all|<project>...]
- 1
向服務器提交代碼。repo會自己查詢需要向服務器提交的項目並提示用戶。
示例:
repo push org
- 1
13. repo forall
repo forall [<project>...] -c <command>
- 1
迭代器,可以在所有指定的項目中執行同一個shell指令。
選項:
-c 後面所帶的參數是shell指令,即執行命令和參數。命令是通過 /bin/sh 評估的並且後面的任何參數就如 shell 位置的參數通過。
-p 在shell指令輸出之前列出項目名稱,即在指定命令的輸出前顯示項目標題。這是通過綁定管道到命令的stdin,stdout,和 sterr 流,並且用管道輸送所有輸出量到一個連續的流,顯示在一個單一的頁面調度會話中。
-v 列出執行shell指令輸出的錯誤信息,即顯示命令寫到 sterr 的信息。
附加環境變量:
REPO_PROJECT 指定項目的名稱
REPO_PATH 指定項目在工作區的相對路徑
REPO_REMOTE 指定項目遠程倉庫的名稱
REPO_LREV 指定項目最後一次提交服務器倉庫對應的哈希值
REPO_RREV 指定項目在克隆時的指定分支,manifest裏的revision屬性
如果-c後面所帶的shell指令中有上述環境變量,則需要用單引號把shell指令括起來。
13.1. 添加環境變量
repo forall -c 'echo $REPO_PROJECT'
repo forall -c 'echo $REPO_PATH'
- 1
- 2
13.2. 合併多個分支
repo forall -p -c git merge topic
- 1
把所有項目都切換到master分支,執行上述指令將topic分支合併到master分支。
13.3. 打標籤
repo forall -c git tag crane-stable-1.6
- 1
在所有項目下打標籤。
13.4. 設置遠程倉庫
repo forall -c 'git remote add korg ssh://[email protected]/$REPO_PROJECT.git'
- 1
引用環境變量REPO_PROJECT添加遠程倉庫。
#刪除遠程倉庫。
repo forall -c git remote rm korg
- 1
- 2
13.5. 創建特性分支
repo forall -c git branch crane-dev
repo forall -c git checkout -b crane-dev
- 1
- 2
14. repo grep
repo grep {pattern | -e pattern} [<project>...]
- 1
打印出符合某個模式的行。相當於對 git grep 的封裝,用於在項目文件中進行內容查找。
示例:
#要找一行, 裏面有#define, 並且有'MAX_PATH' 或者 'PATH_MAX':
repo grep -e '#define' --and -\( -e MAX_PATH -e PATH_MAX \)
#查找一行, 裏面有 'NODE'或'Unexpected', 並且在一個文件中這兩個都有的.
repo grep --all-match -e NODE -e Unexpected
- 1
- 2
- 3
- 4
15. repo manifest
repo manifest [-o {-|NAME.xml} [-r]]
- 1
manifest檢驗工具,用於顯示manifest文件內容。
選項:
-h, –help 顯示這個幫助信息後退出
-r, –revision-as-HEAD 把某版次存爲當前的HEAD
-o -|NAME.xml, –output-file=-|NAME.xml 把manifest存爲NAME.xml
16. repo version
repo version
- 1
顯示repo的版本號。
選項:
-h, –help 顯示這個幫助信息後退出.
17. repo upload
repo upload [--re --cc] {[<project>]...|--replace <project>}
- 1
repo upload 相當於git push,但是又有很大的不同。它不是將版本庫改動推送到代碼審覈服務器(Gerrit軟件架設)的特殊引用上,使用SSH協議。代碼審覈服務器會對推送的提交進行特殊處理,將新的提交顯示爲一個待審覈的修改集,並進入代碼審覈流程,只有當審覈通過後,纔會合併到官方正式的版本庫中。
選項:
-h, –help 顯示幫助信息
-t 發送本地分支名稱到Gerrit代碼審覈服務器
–replace 發送此分支的更新補丁集
–re=REVIEWERS 要求指定的人員進行審覈
–cc=CC 同時發送通知到如下郵件地址
18. repo download
repo download {project change[/patchset]}...
- 1
repo download命令主要用於代碼審覈者下載和評估貢獻者提交的修訂。
貢獻者的修訂在Git版本庫中refs/changes//引用方式命名(缺省的patchset爲1),和其他Git引用一樣,用git fetch獲取,該引用所指向的最新的提交就是貢獻者待審覈的修訂。
使用repo download命令實際上就是用git fetch獲取到對應項目的refs/changes//patchset>引用,並自動切換到對應的引用上。
19. repo selfupdate
repo selfupdate
- 1
用於 repo 自身的更新。如果有新版本的repo存在, 這個命令會升級repo到最新版本。通常這個動作在repo sync時會自動去做, 所以不需要最終用戶手動去執行。
選項:
-h, –help 顯示這個幫助信息後退出.
–no-repo-verify 不要驗證repo源碼.
20. repo help
repo help [--all|command]
- 1
顯示命令的詳細幫助。
選項:
-h, –help 顯示這個幫助信息後退出
-a, –all 顯示完整的命令列表