SVN,一個(gè)版本控制系統(tǒng),用于團(tuán)隊(duì)協(xié)作開發(fā)。
版本控制:
標(biāo)記不同的版本需要使用編號(hào),SVN使用Revision來作為版本編號(hào)。
Revision是一個(gè)隨著提交遞增且唯一的自然數(shù),每次新的提交Revision都會(huì)加一。
Revision應(yīng)用于整個(gè)倉(cāng)庫(kù),不只在單個(gè)文件上生效。(修改了倉(cāng)庫(kù)中一個(gè)文件,提交之后其實(shí)整個(gè)倉(cāng)庫(kù)Revision都增加了,每個(gè)Revision可以理解為整個(gè)倉(cāng)庫(kù)在某次提交之后的快照。)

協(xié)作:
協(xié)作開發(fā)需要關(guān)注問題就是多人修改同一個(gè)文件時(shí)如何保證修改正確的合并起來。File Sharing和Lock-Modify-Unlock模式都有各自的缺陷,SVN使用的Copy-Modify-Merge模式很好的解決了這個(gè)問題,如下是對(duì)三種模式的介紹。
File Sharing,會(huì)有操作覆蓋的問題。

Lock-Modify-Unlock,同時(shí)只能有一個(gè)人在讀寫,影響協(xié)作效率。

Copy-Modify-Merge,SVN采用的模式,不會(huì)有覆蓋的問題,且不影響相互的工作進(jìn)度。


版本管理
SVN常用于代碼版本管理,常用的版本管理模型分為兩種。
主線開發(fā)模型:

- 在trunk上進(jìn)行版本開發(fā)
- 版本完成開發(fā)并測(cè)試通過,準(zhǔn)備發(fā)布,從trunk copy 一個(gè)release分支出來進(jìn)行發(fā)布。
- 新版本繼續(xù)在trunk上進(jìn)行開發(fā),重復(fù)步驟1和2
- 如果有一些特殊的功能模塊需要獨(dú)立開發(fā)(比如可能無法和版本一起上線),從trunk上copy Feature Branch進(jìn)行開發(fā),完成開發(fā)后merge 回 trunk 進(jìn)行發(fā)布。
使用場(chǎng)景:維護(hù)人員較少,定期發(fā)布,團(tuán)隊(duì)成員一般都是一起做一個(gè)版本的功能,且同時(shí)發(fā)布。
release主線,功能分支開發(fā)模型

- 主線為release版本,用作發(fā)布
- 有新版本或新功能,從release中copy一個(gè)feature branch來,進(jìn)行開發(fā),開發(fā)完成之后merge 回release分支進(jìn)行發(fā)布。
使用場(chǎng)景:維護(hù)人員多,發(fā)布頻繁,無固定發(fā)布周期,多功能分支。
合并
上述兩種方案都涉及到兩種合并:
- feature merge 回主線。
- feature 定期和主線代碼同步,將主線代碼merge到feature中。
- SVN建議盡量避免該種情況,因?yàn)閙erge起來沖突會(huì)比較多。實(shí)在有必要,建議只定期merge有價(jià)值的改動(dòng)
- 完成同步操作,將主線merge到feature上和從主線copy一個(gè)分支將feature merge上去,兩種做法本質(zhì)上沒有區(qū)別,后者并不會(huì)避免沖突的發(fā)生,同時(shí)后者還多操作。
沖突:
因?yàn)槭菂f(xié)作開發(fā),所以會(huì)有各種分支,在分支合并時(shí)肯定會(huì)有沖突,SVN中將沖突分為兩種。
- text conflicts:兩個(gè)人同時(shí)修改了相同文件,且修改無法很清楚的merge(修改了同一行,但是修改不同),會(huì)報(bào)該問題。
- tree conflicts:目錄層面的conflicts。本地修改了一個(gè)別人刪除的文件,在更新merge時(shí)會(huì)報(bào)該問題。其他可以歸為目錄conflicts的操作都會(huì)報(bào)該問題。
特殊情況舉例
除了上述提到的,feature可能需要和主分支保持定期同步,同時(shí)還可能需要和別的feature保持同步,我們?cè)谝詒elease為主線的情況下舉例該情況,并支持一些錯(cuò)誤的操作方案以及正確的操作方案,有助于加深對(duì)Revision和conflicts的理解。
場(chǎng)景
- release作為穩(wěn)定主線版本。
- feature-1從release copy出來進(jìn)行開發(fā)。
- feature-2從release copy出來進(jìn)行開發(fā)。
- feature-2在開發(fā)期間需要使用feature-1的新功能,且在feature-1上線前就要使用(feature-1 在 feature-2前上線),所以需要把feature-1 同步到feature-2上。

錯(cuò)誤操作
- feature-1 merge到了feature-2中。
- feature-1 繼續(xù)后續(xù)開發(fā),開發(fā)完成后 merge 回release,發(fā)布release。
- feature-2 開發(fā)完成后,merge回release時(shí),在feature-1中新增的文件(feature-2中未修改)產(chǎn)生了tree conflict。

產(chǎn)生conflict原因分析:feature-1 merge進(jìn)feature-2后,相當(dāng)于feature-1的改動(dòng)在feature-2上實(shí)現(xiàn)了一遍,會(huì)生成一個(gè)新的Revision = X;然后將feature-1 merge進(jìn)release,feature-1的改動(dòng)會(huì)在release上生成一個(gè)新的Revision = Y(X != Y,兩者除了Y比X大其他沒有任何關(guān)系,可以理解為兩次單獨(dú)的修改);后續(xù)feature-2 merge 到 release時(shí),對(duì)于在feature-1中新增的文件,相當(dāng)于在兩個(gè)不同的Revision中,該文件都被新建,所以產(chǎn)生了tree conflicts。
正確操作
- 從release中copy出feature-3
- 將feature-1 merge 到feature-3
- 從feature-3 中copy出 feature-4 來進(jìn)行feature-1 的后續(xù)開發(fā),完成開發(fā)后merge回release。
- 將feature-2 merge到 feature-3中,在feature-3中繼續(xù)feature-2的開發(fā)。

核心理念
不要把feature merge到兩個(gè)分支中,同時(shí)這兩個(gè)分支后續(xù)還需要進(jìn)行merge,這樣會(huì)出現(xiàn)沖突。因?yàn)橄喈?dāng)于兩個(gè)分支上各自進(jìn)行了feature的開發(fā),兩者并無關(guān)聯(lián)關(guān)系,雖然merge來源一致。