眾所周知的是,vim 的代碼是 Bram 用 patch 的方式維護的,一種典型的集約式管理,雖然 edyfox 在
https://vim.svn.sourceforge.net/svnroot/vim 維護了 svn 版本,但這也只是匯入 CVS
的內容而已,別人無法往裡面加入代碼,問題是,當你想開發一系列實驗性功能時,沒法直接在 vim 的 svn 倉庫上工作
(比如建立分支),而只能用自己的版本管理倉庫。
這便造成了一個顯然的維護問題,以我自己為例,vim-cocoa 的代碼原本使用 code.google.com 提供的 svn
服務進行維護,但 Subversion 是以目錄為單位跟蹤修改的,所以,同一個代碼目錄,要麼來自 vim 的代碼倉庫,要麼來自 google
code 的代碼倉庫,二者不可兼得。
所以我原來使用了一套非常麻煩的維護方式:
$ svn co https://vim.svn.sourceforge.net/svnroot/vim/vim7
$ cp -r vim7/ vim-cocoa/
$ cd vim-cocoa; find . -name ".svn/*" -exec rm -rf {};
$ svn import src/gui_mac.m https://vim-cocoa.googlecode.com/gui_mac.m
...
也就是說,抓下一份 vim 的代碼來,複製一份,去掉其 svn 的資料,然後將我修改過的部分匯入 google code
的版本倉庫。在我完成一部分修改,代碼達到穩定之後,再返回 vim7 目錄,更新原來用 svn 下載的代碼,然後將我在 vim-cocoa/
下做出的修改 back port 回最新的 vim7 代碼裡,產生針對最新版本的 patch,並編譯,發布。
顯然這裡要花大量的時間在沒有必要的手工操作上,而且很容易出錯。這便是 git 該出現的時候了。再簡單複述一下我的需求:
- 能夠通過 svn 經常更新到最新的 vim 代碼
- 自己正在工作的 vim-cocoa 分支代碼不受影響
- 能把主幹代碼和分枝代碼按需合并
- vim 的 svn 庫裡有些自動產生的檔案,應該刪除,因為 Bram 不願意,所以我應該可以在自己的分支裡刪除,這樣可以避免每次 commit 之前需要恢複這些自動產生的檔案
下面是用 git 完成的步驟,主要就是利用了 git-svn 這套方便的工具:
$ mkdir vim; cd vim
$ git-svn init https://vim.svn.sourceforge.net/svnroot/vim/vim7
$ git-svn fetch -r 625 # 這裡為了減少消耗,不複製整個 svn 版本倉庫,只抓最新的 revision
這時 git-svn 會產生一個叫做 git-svn 的 remote branch,並讓本地的 master 指向這個 branch。所以,我們可以從 master 分支出一個自己的版本來:
$ git checkout -b cocoa
# 下面是把所有原來 vim-cocoa 做的修改在這個最新版的 vim 代碼中打上
$ git commit -m "import vim-cocoa changes into git repo"
此後,如果上遊的 vim svn 庫更新了,我們可以用 git fetch git-svn 把更新下載下來,然後,用 git merge
git-svn 將這些更新 merge 到當前的 branch 裡,當然,也可以用 git pull git-svn
把兩步合在一起完成,只要你確定 merge 不會出現衝突。
那麼,現在就有很好的一個的平台來做本地修改了,但 vim 的一個問題是,src/auto/ 中自動產生的檔案也被放在 svn repo
裡,這是一個很麻煩的問題,因為 vim 也不支援 off-directory build,所以在我們測試、調試過後,如果要產生
patch,就不得不先把這些 (configure/make 過程中) 必然會產生的檔案先恢複到初始狀態,無謂的增加了操作,如果在 git 裡
commit,也會提示你這些檔案更新了,但你顯然不願意把這些改動都算進你的 commit 裡,那怎麼讓這些檔案不煩人呢?
簡單,我們不管上遊的 vim svn 庫怎麼維護,可以在本地 git 倉庫中把這些檔案刪除,也就是不跟蹤的改動了:
# --cached 表示只刪除 git 緩衝,不刪除實際檔案
$ git rm --cached src/auto/config.h
$ git rm --cached src/auto/config.mk
$ git rm --cached src/auto/configure
...
$ git commit -m "stop tracking auto generated files"
因為就算這些檔案不在跟蹤中,一旦它們修改過了,git status 還是會提示你它們更新了,而且這樣用 git commit -a 把所有修改過的檔案加入下一次 commit 也不方便,怎麼辦呢?用 .gitignore 檔案:
$ vi .gitignore
加入以下內容:
.*.swp
.DS_Store
src/TAGS
src/tags
src/Vim
src/auto/*
src/auto/configure
src/auto/config.h
src/auto/config.mk
src/auto/if_perl.c
src/auto/link.log
src/auto/link.sed
src/auto/osdef.h
src/auto/pathdef.c
src/config.log
src/config.status
src/objects
src/xxd/*
src/Vim.app/*
這樣不管這些檔案怎麼變,git 都不會提示了。
現在我們需要一個用來作為參考的分支,以定期產生 patch,這個分支必須隨著上遊 svn 的更新而更新,但我們這裡刪除這些自動組建檔案的記錄又不應該包含在內,怎麼辦呢?可以用 git-svn 自動產生的 master branch 來做這件事情:
$ git checkout master
$ git rm --cached src/auto/config.h
...
$ git commit -m "blahblahblah"
這樣,以後每次要產生一個獨立的 vim-cocoa 分支相對 vim 主乾的 patch 時,我都可以先在 master 分支上:
$ git-svn rebase
$ git pull git-svn
然後切換回 cocoa 分支:
$ git checkout cocoa
$ git diff master > vim-cocoa.patch
這樣便完整了 patch 的產生。
最後,如果我們需要把現在這個 vim-cocoa 像原來 google code 的代碼倉庫一樣,隨時公布到網上該怎麼辦呢?http://repo.or.cz 提供了公開的代碼倉庫,申請以後可以獲得一個 push 地址:
git+ssh://repo.or.cz/srv/git/vim-cocoa.git
push 需要添加一個使用者,然後上傳它的 ssh 公開金鑰 (在本地用 ssh-keygen 產生)。然後,如果我要把本地的 cocoa 分支發布到網上,就可以執行:
$ git push git+ssh://repo.or.cz/srv/git/vim-cocoa.git cocoa:master
其中 cocoa 指的是來源 (本地) 分支,master 指的是目的 (遠程) 分支,為什麼要 push 到另一個名字的分支去呢?因為
master 是 git 預設 clone 下來的分支,為了方便其他使用者的抓取,以及 gitweb 的資訊顯示,還是保持公開倉庫裡的
master 分支是你最常更新的那個分支為好。
This entry was written by jjgod and posted on November 3, 2007 at 1:00 am and filed under Mac, Programming, Tools. Bookmark the permalink. Follow any comments here with the RSS feed for this post.Post a comment or leave a trackback: Trackback URL.