svn

簡介 Git

Edit: 2012-01-30 新增4圖, p.s.

隨著 Drupal 放棄 CVS 而使用 Git 之後,
作為一個 Drupal developer, 你便需要使用 Git 了

如果你之前有看過的的 SVN 教學的話,
你便會發覺 CVS 和 SVN 很類似
而這次我也會使用很多 SVN/CVS 的詞彙令大家更容易過渡到 Git

Git 是一種分散式的代碼管理系統 (DCVS)
相比 SVN/CVS, 各種操作都可以單機完成, 最後再上交到一個或者多個伺服器
具體的分別有:


1. 你可以在沒有網路的情況之下, 例如在飛機上, commit 代碼
在 SVN 的年代, 如果你要在沒有網路的地方開發的話, 你便不可以 commit
需要一次性在網路再開的時候將全部修改都放到一個 commit
違反 "一個 commit 修改一個功能" 的原則
變相令 merge 更困難
在 Git 上便沒有這個問題,
你可以 commit, 直到有網路的時候, 將積壓的多個 commit 一次再提交到網路上分享

2. 你還可以沒有網路的情況下開 branch, merge branch
同樣等到有網路的時候, 將commit 連同 branch 的資料一次提交
所以你的本機已經有整個 repo 的全部資料
可以斷線之下 checkout 舊 code, 開發另一個 branch 等等


3. 本機的 repo 需要 push 到遠端的 repo
99% 的專案你都需要和其他人一起開發
你需要用網路同步大家的 repo, 而網路上的 repo 稱為 remote
將 local 的 repo 傳送到 remote 的動作稱為 push
相反則為 pull

所以開發的流程是 pull -> commit -> commit -> ... -> push

p.s. 從圖中你還可以看到更多 git 的特性, 例如
git pull 和 push 是將 commit tree 全部複製一次
git 的 filesystem 使用連結處理內容完全相同的檔案
每一部電腦都有完整的, 每一個版本的檔案

SVN Merge

使用了 SVN 一段時間之後, 你便會遇到複雜的情況: Conflicts
例如你和你的拍擋同時在修改同一個文件, 大家都是基於 r27
你的拍擋 commit 了, 變成 r28
但係也 commit 一個基於 r27 的檔案, 想要變作 r28
而且大家修改的行數相當接近, 自動的 merge 不能完成的時候
SVN 便會提示你, 已經發生了一個 Conflict
要求你先 solve Conflict 再 commit, 也即你需要 Merge 了

有 conflict 的檔案會標示為 conflict state, 檔案的內容也會有相關 conflict 的資料

你需要做的便是先 update, 將你的拍檔修改的部份了解一下
再手動修改這個檔案, 直到它能正常執行
也包含了你和你的拍檔的修改之後
儲存, 將這個檔案摽示為 "已解決"

你便可以正常的將這個 merge 了的檔案 commit 了

Note to self: Create new svn repo for new project

sudo svnadmin create /svn/project1
sudo vi /svn/project1/conf/svnserve.conf
anon-access = none
auth-access = write
realm = Project1 Repository
sudo vi /etc/apache2/sites-available/default
#create a new vhost for svn
#define the passwd path
sudo htpasswd -cm /svn/project1/conf/passwd joe
sudo htpasswd -m /svn/project1/conf/passwd joe2

svn import 的問題

-

Svn import 的使用原意是, 將一個已經建立好的專案匯入到 svn 的管理之下
作為第一次的提交, 是假設專案已經開展了, 一次匯入多個檔案

但 svn import 最後卻得不到廣大使用者的支持
svn 的文檔中也建議使用另一個方法匯入 (ref2)
原因有二:
1. 匯入之後的本機文件不會處於svn 的客戶端管理之下 (ref1)
意思其實是 import 了 c:\htdocs\abc 之後,
你需要再從 repo 之中 checkout svn 中的檔案
因為 import 之後, 本機的文件是不會有任何改變, 包括svn 的改變

2. 匯入的文件結構指令很容易出錯
我應該匯入 c:\htdocs\abc 還是 c:\htdocs\abc\* ?
checkout 時應該 checkout 根目錄還是子目錄?

3. 應該習慣建立 trunk, branches, tags 等的根目錄作為分支時使用 (ref3)
但import 方法不支持先建立以上的目錄樹

所以, svn 的官方文件建議的做法是,
先 checkout 空的根目錄, 再用一般的 add + commit 的方式提交第一次的源代碼

ref1: http://svnbook.red-bean.com/en/1.0/re12.html
ref2: http://subversion.apache.org/faq.html#in-place-import
ref3: http://svnbook.red-bean.com/en/1.4/svn.tour.importing.html

svn 概念, 初階使用

UPDATE: 2011-01-09 SVN merge
UPDATE: 2010-04-13 images added
ORG: 2009-06-13

svn 是一個管理源碼的工具
它提供一個容許多人協作的平台, 幫助一個多人開發的團隊管理代碼
同時提供一個保存多版本的功能 (version-ing)

而我因為多數都自己一個開發, 主要為了 versioning 而使用 svn
但因為有多個開發機器
為了保持代碼在多個機器中同步, 都會使用 svn

我在 windows 機是使用 TortoiseSVN GUI client
ubuntu 上使用 nautilussvn
使用上, 介面上都很類似, 都很好用

先談一下 svn 的概念
svn server 是指在 remote 上的server
大家都將大家的code 上傳 (commit) 到這個中央的server
而開發機則是 client端 (當然, 他們其實可以在同一部機器上)
而 head 是指最新的一組檔案的集合, 統稱 head version
trunk 一般指 server 上的 head.

從日常使用次數最多的功能開始介紹
checkout
checkout
從server 上下載源碼(即 server 上己經建立好, 設定好)
在本機(即開發機上)建立一個拷貝
是在開發機上開始建立一個新的 project 的方法
完成便可以開始改動源碼, 開發的工作了
可以從 code.google.com 隨便選一個 project 使可以checkout了 (source tab 便可以找到 svn url, )

commit / add

commit
commit 是指將本機的源碼上載到 svn server 上(要已經checkout 過的檔案)
例如已經checkout 過的 project,
在改動源碼之後, 資料夾上使會有一個紅色的X, 代表需要 commit
而如果你有權力 commit, 便可以上載到 svn server 上了
而每一個commit 都儲存到 server 上, 之後的任何時候都可以調用, 還原等等 (就算commit 再覆寫過都可以)

而 add 則是新增一個沒有 svn 的檔案到 svn server.

commit 的策略是, 每午飯之前, 下班之前都commit, 原因在討論 update 之後再研究

update

update
如果我 checkout 了一個 project, 但 project code 在svn server 上有其他人 commit 了中
我應該如何更新我的 code 令自己和svn server 同步?
答案是 update.
svn 會幫我們從 server 上下載, 而且萬一需要覆寫一個我們正在修改的檔案(即一個衝突 conflict 發生了),
svn 會嘗試幫我們合併, 確保同事做的修改和我們的修改都正確的保存

如果開發團隊同意了午飯前, 下班前commit 當日的源碼,
update 的策略便是 上班的第一件事, 和午飯後的第一件事了.

change log, diff
每一次的commit 都會留下記錄在 server 上 (change log)
並有一個唯一的 版本(version) id
我們任何時候都可以將任何兩個 commit 比較
並還原, 合併任何兩個檔案

svn 在處理 conflict 的時候, 不一定能自動合併
這時 svn 會要求我們做手動合併, diff 工具都會協助我們分析兩個衝突檔案的內容的

tag / branch
這是一個進階使用者的題目, 請先確保你試過, 用過上面的功能再繼續
head 便是一個等殊tag, 這個tag 是會隨著commit 而移動
而我可以因應需求tag 一個 2009-06-08 tag
標記這些便是 09年 6月 8日 的源碼, 主要是為了方便日後的調用 (稱為日期tag)

而branch 其實和 tag 類似, 但 checkout 了 branch 的話, 你的 commit 會指定為 commit 到這個 branch,
而不是一般的主線
這樣, 你就可以將你的重大更新, refactoring 開一個 branch, 完成再 merge
令自己的重大更新的開發代碼不會干擾其他同事的開發

指令上在 GUI 都好簡單, checkout/update 了以後, 直接在資料夾上右鍵->tag/branch 便可以了

安裝 svn server @ubuntu
首先安裝 SVN
sudo apt-get install subversion

安裝 svn 在 Apache 使用的套件
sudo apt-get install libapache2-svn

進階的權限便自己 google 一下了

Project setup
安裝完便要建立一個 trunk,
而一般的資料夾習慣是:
SVN-ROOT
-PROJECT-NAME1
--trunk
--tags
--branches
-PROJECT-NAME2
--trunk
--tags
--branches

建立 SVN-ROOT 到 /home/svn:
sudo svnadmin create /home/svn

建立 PROJECT-NAME1:
GUI:
在開發資料夾 (例 /var/www) checkout file:///home/svn
checkout 後建立 trunk, branches, tags 三個資料夾
commit 三個資料夾
再 del 三個資料夾, 然後 checkout trunk
便可以開始 add了

conclusion
會使用 svn 工具絕對是其中一個進階程序員的指標 (包括 tag/branch)
工具看似複雜, 但其實真正做起來只是很簡單的概念, 但用文字真的比較難以表達
找一個人教一教, 十分鐘便什麼都懂了.

version control 的工具其實還有 cvs, git 等, 概念有一點不同
但一般的操作反而很類似, 舉一反三就是了

但svn 都不是萬能
sql server 中設定很多的 cms (drupal 便是一個明顯例子) 如何做 version control?
mysqldump + commit?
有高手能解答嗎?

SVN merge

merge 是一件麻煩事. 當然, 用了branch 或者tag 才需要 merge.

當一個或者多個commit 需要同時應用到另一個branch, 你便需要merge. 通常你都會從trunk merge 到branch 的

一開始使用merge 可能會感到害怕, 但merge 和commit, update 一樣, 用多了使自然覺得很方便了. 而且, 不需要擔心merge 錯, 因為merge 的動作本身是不會提交到svn 的. merge 完了, 你確認了代碼, 功能都沒有問題之後, commit, 才會提交到svn.

在merge 的過程, 你要選擇你merge 的 revision number, 所以, svn 的 commit message 便很重要, 會是你決定用不用某一commit 的最重要依據.

merge 時, 你應該先switch 到被merge 的branch, 再選擇trunk 的revision, 例如, trunk revision 123 需要copy 到 branch, 便應該switch 到 branch, 再用merge

2009-07-17 svn tagging and branching

svn 是一種使用之前會討厭,
但使用過以後你已經不能缺少的開發環節 (情況和測試驅動開發(TDD)一樣)

在"使用過" 並愛上的青況之下,
你很容易便會提起興趣學習進階的 branch 和 tag 的功能了
但如果沒有, 直接跳過就好了 >Read more