VSTS2010版本控管
1 前言
版本控管主要用於管控程式碼異動,對於開發、測試階段以及後續維護階段,都是不可或缺的角色。VSTS2010提供了十分成熟完整的程式碼管控(Source Control)功能,並與開發工具Visual Studio深度整合,對於開發團隊提供很大的助益。
2 相關工具介紹
2.1 Solution Explorer
透過它可以進行簽入、簽出、取得新版本動作,並可從Solution、Project角度了解相關檔案版本管控狀態,如檔案是否納入程式碼管控狀態、簽入或簽出。
圖1 Solution Explorer
2.2 Source Control Explorer
在Team Explorer視窗,點選您的Team Project -> Source Control節點,點擊兩下即可顯示。它用於顯示TFS上程式碼管控目錄結構與狀態,您可以透過它設定權限、進行Branch與Merge、利用Workspace設定與本機目錄的對應關係。
圖2 Source Control Explorer
2.3 Pending Changes
點選Menu -> View -> Other Windows -> Pending Changes,即可叫出此視窗。它是以平面方式(Flat Mode)、不分目錄階層展現所有正在異動的檔案列表,您可以一目瞭然了解目前有那些檔案正在異動中。並可透過它連結Work Item、Check-in Notes、執行Shelve、Unshelve等動作。
圖3 Pending Changes視窗
3 相關功能介紹
圖4 程式碼管控功能架構
Changeset(變動集)是VSTS2010程式碼管控的最基本單位,每一次的簽入(Check In)皆會自動產生一組編號,代表本次的異動,Changeset裡包含所有相關檔案的異動,如新增檔案、刪除檔案、修改檔案內容,更改檔名、更改目錄等。Changeset一旦產生後便無法刪除。ChangeSet之間可以互相比較,顯示差異的內容。
Label(標籤)用於標註Changeset,因為Changeset只是一組編號,不具可讀性,透過Label您可以使用有意義的名稱加以標示,如Beta1、Beta2,Versio1.0等。
Branch(分支)的應用時機在於多個版本同時發展的情境,例如我們完成了版本1.0,並且上線了,後續仍有維護的工作進行,但是我們仍須持續發展版本2.0,加上新功能,此時透過Branch分出兩個版本,其實是兩個不同目錄,如此兩個版本便不會互相干擾。過了一段時間,在版本1.0會修改一些Bug,想當然耳,這些Bug一定也存在版本2.0,此時可透過Merge(合併)功能進行比對,將異動部份更新至版本2.0。
Shelve用於下列情境:
l 當您的開發工作做到一半,是您的程式碼需要別人幫您檢視或驗證
l 半成品的程式碼想要備份
您可以透過此功能分享程式碼給其他人,而不會干擾到實際版本管控裡的程式碼。
Check-in Policy用於當程式碼簽入之前,您可以應用一些規則來檢查是否有違反,若有不符合之處,便不允許簽入。
Changeset與Shelveset都可以跟Work Item進行連結,這樣的好處是後續可以追溯當初修改這段程式碼是為了什麼目的。
4 程式碼管控步驟
為什麼要刻意提供程式碼管控流程?因為VSTS提供了很大的彈性,同樣的功能,您可以透過不同的方法執行,以簽入(Check In)程式碼為例,您可以在Solution Explorer 對欲任一檔案按右鍵選”Check In”,也可以對某一目錄、某一專案或整個Solution按右鍵選”Check In”,或是在Pending Changes視窗,勾選檔案後按[Check In]鈕。因為有這麼多種方式都能執行簽入(Check In)動作,但執行結果其實是有差異的,如透過Pending Changes視窗只會簽入(Check In)勾選項目,但是透過Solution根節點簽入,會遞迴簽入(Check In)所有異動的項目。
所以若沒有流程規範程式碼管控,會導致簽入(Check In)檔案是不一致,如程式碼已簽入,但相關專案檔卻未簽入(Check In),造成其他專案成員拿不到完整專案程式碼,無法編譯程式,最後程式碼管控會變成垃圾堆,專案成員想到就丟進去,但它不是最新、完整、且一致的程式碼儲存庫。
以下介紹的流程是筆者自身的經驗,並經多年試鍊證明,確實可以達成程式碼管控的目標。
圖5 程式碼管控步驟
4.1 簽入Solution
時機:在系統設計階段尾聲及系統實作階段初始之間,系統設計人員架構出整個系統雛型時。
說明:完整性很重要,Solution檔、專案檔、資源檔一個都不可漏。目標是讓專案開發人員只要執行後續”取得最新程式碼”動作,不須額外步驟即可編譯、執行程式碼,進行測試。
步驟:
- 將Solution整理好,並確定可正常編譯。
- 在Solution Explorer,對根節點選”Add Solution to Source Control”
- 確認程式碼管控目錄名稱(The Solution Folder),預設為Solution名稱,按[OK]鈕。
圖6 確認程式碼管控目錄
此時所有目錄與檔案前面皆有”+”符號,表示這些目錄或檔案屬於新增項目,對Solution根節點按右鍵選”Check In”,完成後”+”會變成鎖頭符號,表示整個Solution簽入(Check In)成功。
圖7 整個Solution加入版本管控
4.2 取得完整Solution
時機:開發人員首次取得完整程式碼時。
說明:透過這個步驟,開發人員完成本機測試環境設置,如安裝Visual Studio、安裝SQL Server,接下來取得完整專案程式碼後,便可直接進行程式編譯,開始他的開發工作。
步驟:
- 在Source Control Explorer選擇對應的.sln檔,按右鍵選”Get Latest Version”。
圖8 選擇.sln檔
- 選擇本機路徑,然後按[Map]鈕。
圖9 選擇本機路徑
- 在Source Control Explorer,對.sln檔滑鼠點擊兩下。如此.sln檔會自動取得相關的專案檔,如.csproj檔、.vbproj檔,接下來連接到相關目錄與檔案,如同一串粽子,只要提起最上面繩頭,一整串都提起來了。
4.3 取得最新程式碼
時機:每日開發工作開始前,或程式碼有重大更新,需要所有開發人員馬上同步更新時。
說明:透過這個步驟,開發人員完成本機測試環境設置,如安裝Visual Studio、安裝SQL Server等,接下來取得完整專案程式碼後,便可直接進行程式編譯,開始他的開發工作。
步驟:
- 在Solution Explorer視窗點選Solution根節點,按右鍵選擇"Get Latest Version"。若有發生衝突,請務必解決!
- 若發生衝突,會在Pending Changes視窗之最後一頁”Conflicts”,有四個選項可用。
圖10 Pending Changes視窗之”Conflicts”頁
功能 | 說明 |
AutoMerge | TFS自動幫您進行合併動作,筆者強烈建議不要使用此選項,因為自動合併無法考慮到真實邏輯,合併後的結果可能會變成不合邏輯、無法執行的程式碼。 |
Merge Changes In Merge Tool | 使用Merge Tool功能,讓使用者手動進行合併動作,筆者建議儘量使用此功能解決衝突。 |
Take Server Version | 放棄本機端的異動,以伺服器端最新版本來取代本機端的。 |
Keep Local Version | 保留本機端的異動,屆時可直接覆蓋掉伺服器端版本。 |
表1 解決衝突選項
點選[Merge Changes In Merge Tool]鈕,會出現以下畫面,左上角代表伺服器端版本,右上角是本機端版本,下方則是編輯窗格,是您解決衝突後的結果,TFS會嘗試自動合併,如兩個版本雖然修改同一檔案,但是不同列,自動合併的結果會顯示在編輯窗格;若不幸兩個版本異動在同一列,則必須由讀者自行決定最終結果,您可以使用下方[Previous Change]、[Next Change]鈕來移動各個程式碼有異動的地方,若所有衝突皆已解決,[OK]鈕會Enable。
注意!衝突解決後的結果會先保留在本機端,讀者仍須執行下一步驟完成簽入動作。 |
圖11 Merge Tool視窗
4.4 簽入程式碼
時機:程式已完成實作,並完成相關程式碼檢查,如命名規則,以及單元測試。
說明:透過這個步驟,您可以將完成的程式碼置入TFS程式碼管控系統。檔案從程式碼管控系統取出後,在Solution Explorer裡會顯示鎖頭標記,並且這些檔案會是唯讀的。
步驟:
- 執行上一步驟”取得最新程式碼”。
- 在"Pending Changes"視窗,檢查是否有檔案是您不小心改到的或只是用於測試的修改,您可以選擇它們按右鍵選”Undo”,以回復到程式碼管控系統裡的最新版本。
- 編譯程式,確認程式可正常編譯。
- 在"Pending Changes"視窗,勾選所有該簽入的檔案,基本上除了web.config,及一些您很確認是因為本機測試環境差異所引起的修改,其他檔案請一律勾選,不管是不是您親自改過,因為一些控制檔修改,如.sln、.csproj、.vbproj,是由Visual Studio引發的,但它們仍需要簽入(Check In)。
注意!建議不要透過Solution Explorer進行簽入(Check In)動作,因為會很容易遺漏該簽入(Check In)的檔案。 |
圖12 勾選須簽入(Check In)檔案
- 連結對應的Work Item,表示本次Check In是為了那一項工作而做。先選[Work Items]鈕,勾選對應Work Item,Check-in Action請選”Associate”選項,最後按[Check In]鈕。
注意!此動作並不是強制要求的,但筆者建議它是一個好習慣,因為後續程式碼維護時,您會有充足的資訊可用。 您可以讓此動作變成強制要求,請參考”Check-in Policy”(會放在專案管理章節) |
圖13 連結Work Item
5 執行擱置(Shelve)步驟
時機: 當您的程式碼完成一半,想要請其他專案成員幫忙偵錯或檢視、或想要在正式簽入(Check In)程式碼管控系統前,備份程式碼,以防萬一。
說明:執行此步驟不會干擾到程式碼管控系統裡的程式碼。
步驟:
- 在Pending Changes視窗,勾選您欲擱置(Shelve)的檔案,然後按[Shelve]鈕。
圖14 進行擱置(Shelve)動作
- 輸入Shelveset名稱,筆者建議以模組名稱加入日期來命名,如”Module1 100302”,然後按[Shelve]鈕,到此完成擱置(Shelve)動作。
圖15 輸入Shelveset Name
注意!其他專案成員若要取得您的Shelveset,首先須確認他沒有異動到相同的檔案,若有他必須先進行上一步驟—先擱置(Shelve) 他自已的異動部份,然後放棄(Undo)這些異動,才能進行Unshelve動作,因為執行Unshelve時並不提供解決衝突的功能。 |
- 輸入這個Shelveset擁有者帳號,再按[Find]鈕,會列出此帳號相關的Shelveset,若您要取得所有人的Shelveset,可輸入”*”。選擇您要的Shelveset後按[Unshelve]鈕。
圖16 進行Unshelve動作
6 執行分支(Branch)步驟
時機:需要一個系統多個版本同時發展時,如版本1.0已經上線了,但我們需要向前發展版本2.0,且同時需要維護版本1.0。
說明:執行分支(Branch)步驟後會在程式碼管控系統複製一份到另外一個目錄,之後兩個目錄彼此獨立,程式碼管控不會互相干擾,但後續可以執行合併(Merge)動作將其中一版本差異部份分享給另一版本。例如版本1.0修正了一些Bug,版本2.0是以版本1.0為基底分支出來的,所以這些Bug一定也存在於版本2.0,透過合併(Merge)功能可以回饋修正程式給版本2.0。
注意!執行合併(Merge)後並不會將兩個分支版本合併成一個版本,僅是內容同步而已,筆者認為合併(Merge)這個詞並不適切,容易造成誤解,同步化(Synchronize)應該比較合適。 |
步驟:
- 在Souce Control Explorer,對您欲執行Branch的目錄按右鍵選”Branching and Merging” -> “Branch”。
- 輸入Branch後的目錄名稱,建議名稱可以是系統名稱加上新版本編號,如”DemoVersionControl20”:
圖17 輸入Branch後的目錄名稱
- 輸入新Branch之本機對應目錄,完成後按[Map]鈕:
圖18 輸入新Branch之本機對應目錄
它會以遞廻方式將欲分支(Branch)目錄下所有檔案進行複製動作,所有新複製的目錄與檔案皆會出現在Pending Changes視窗,此時這些檔案尚未完成分支 (Branch)動作。若確認無誤,請按[Check In]鈕簽入(Check In)所有分支(Branch)異動。
圖19 所有新複製的目錄與檔案會出現在Pending Changes視窗
- 簽入後在Source Control Explorer視窗會出現兩個目錄有分支(Branch)標示。
圖20 目錄有Branch標示
在Source Control Explorer選擇某一分支(Branch)目錄,按右鍵選”Branching and Merging” -> “View Hierarchy”,會顯示各分支(Branch)的階層關係,若您的系統已經超過三個以上分支(Branch),這張圖可以讓您明瞭各個分支(Branch)的來龍去脈。
圖21 View Hierarchy
7 執行合併(Merge)步驟
時機:執行過分支(Branch)後,兩個分支(Branch)目錄已各自發展一段時間,例如有一些Bug修正,我們想要將這些修正同步更新至另一個分支(Branch)目錄。
注意!執行合併(Merge)步驟的頻率建議不要隔太久時間,一兩個禮拜時間為宜,因為若差異過大,發生衝突機會愈高,程式碼會難以合併。 |
說明:執行Branch步驟後會在程式碼管控系統複製一份到另外一個目錄,之後兩個目錄彼此獨立,程式碼管控不會互相干擾,但後續可以執行Merge動作將其中一版本差異部份分享給另一版本。例如版本1.0修正了一些Bug,版本2.0是以版本1.0為基底,所以這些Bug一定也存在於版本2.0,透過Merge功能可以回饋修正程式給版本2.0。
步驟:
- 在Souce Control Explorer,對您欲執行Merge的目錄按右鍵選”Branching and Merging” -> “Merge”,會出現以下畫面,預設Target branch為您所選擇的目錄,Source branch預設為其關聯的分支(Branch)目錄,如父階分支(Branch)目錄。
注意!執行合併(Merge)方式有兩種,第一種是選擇更新至指定版本;第二種是選擇更新那些Changeset,系統會列出那些Changeset是未曾同步過的。 |
圖22 輸入來源、目的分支(Branch)目錄
- 選擇Version type如下表,請選”Latest Date”:
功能 | 說明 |
Changeset | 以指定的Changeset進行合併。 |
Date | 以指定的日期進行合併。 |
Label | 以指定的標籤(Label)進行合併。 |
Latest Date | 為預設值,以程式碼管控系統裡最新版本進行合併。 |
Workspace Version | 以本機端版本進行合併。 |
表2 Version type選項
圖23 選擇Version type
- 在Pending Changes視窗會因合併(Merge)而異動的檔案,按[Check In]鈕以完成最後的確認動作。
8 執行標籤(Label)步驟
時機:當您的系統已經發展到一個里程碑,如程式已實作完畢,並完成單元測試,準備進入整合測試階段時。
說明:透過標籤(Label)來標註Changeset,因為Changeset只是一組流水編號,不具可讀性,透過標籤(Label)您可以使用有意義的名稱加以標示,如Beta1、Beta2,Version1.0等,後續我們可以透過標籤(Label)取得特定版本進行相關測試。
步驟:
- 執行標籤(Label)前首先確認所有Pending Changes都已簽入。
- 在Source Control Explorer裡,對欲標註Label的目錄按右鍵選”Apply Label”,並輸入Label名稱,建議名稱為專案里程碑名稱或階段名稱,如Beta1,預設”Version”欄位為”Latest Version”,再按[Create]鈕,到此便完成Label標註。
圖24 輸入Label名稱
- 接下來我們要透過標籤(Label)取出程式碼,在Solution Explorer,對根節點按右鍵選”Get Specific Version”,接著在Version Type欄位選”Label”,再按右邊按鈕進行查詢。
圖25 依標籤(Label)取指定版本
- 按[Find]進行查詢,Find options可讓您輸入一些條件進行過濾。找到您要的Label,選擇後按[Ok]鈕。
圖26 Find Label
- 在Label欄位會出現查詢結果,最後按[Get]鈕以取得指定程式碼。
圖27 按[Get]鈕以取得指定程式碼
9 疑難排解
9.1 如何變更本機端程式碼管控目錄?
說明:本機端程式碼管控目錄是由Workspace來管理,所以當您的本機端程式碼目錄想要重整,如C糟硬碟空間不夠,想移至D糟,就必須變更您的Workspace對應關係。
步驟:
- 在Source Control Explorer裡,下拉選擇右上角”Workspace”欄位,選擇”Workspaces..”,再按[Edit]鈕。
圖28 管理Workspaces畫面
- 在編輯Workspace畫面裡,下方之Working folders窗格區域有:”Source Control Folder”為程式碼管控系統之目錄;”Local Folder”為本機端對應目錄,按右方按鈕進行變更,完成後請按[OK]鈕。
圖29 變更本機端目錄
- 詢問是否重新從程式碼管控系統取得一份最新程式碼置於新目錄,請按[是(Y)]鈕,如此即開始取得最新程式碼,完成後之前的舊目錄並不會自動清除,您仍須自行手動刪除。
圖30 詢問是否重新從程式碼管控系統取得一份取新程式碼置於新目錄
9.2 如何將某一檔案回復至上一版本?
說明:有時某個已簽入的程式碼異動(Changeset)經過測試發現有問題,此時需要回復上一個穩定的版本,再進行後續的測試或修改。雖然我們透過”Get Specific Version”暫時取得舊版本,但是無法強制要求所有專案成員直接回復舊版本。透過本步驟可以達成永久回復舊版本的效果。
注意!我們無法刪除在TFS裡的任何一個Changeset,所以只能透過覆蓋的方式來達成我們要的目的。 |
步驟:
- 在Solution Explorer,對欲回復上一版本的檔案按右鍵選”View History”,查詢此檔案所有的簽入紀錄,如下圖:
圖31 View History
- 假設我們要回復的上一版本是Changeset 8,而最新版本是Changeset 11,回到Solution Explorer,對欲回復上一版本的檔案按右鍵選”Get Specific Version”,輸入”Changeset”欄位,如”8”,按[Get]鈕。
圖32 取得舊版本
- 在Solution Explorer裡,對此檔案按右鍵選”Check Out for Edit”,再按[Check Out]鈕,此時此檔案會標示成修改中。
圖33 Check Out檔案
- 在Solution Explorer裡,對此檔案按右鍵選”Check In”。
圖34 進行Check In動作
- 此時一定會發生衝突,請直接按[確定]鈕。
圖35 發生衝突
- 在Pending Changes視窗裡,按[Keep Local Version]鈕,意思是以目前本機端版本覆蓋掉伺服器端版本,接著要[Check In]鈕。
圖36 以目前本機端版本覆蓋掉伺服器端版本
- 完成後再以View History查詢,會多出一個新的Changeset,它的內容會與上上一個Changeset相同,如此即達成我們要的版本回復效果。
圖37 再以View History查詢
9.3 程式碼管控進入離線狀態後如何回復?
說明:當碰到網路斷線時,我們仍然可以開啟Visual Studio進行程式編輯與執行,不過後續再連上TFS,Visual Studio並不會自動回復連線狀態,並將離線期間的異動更新回TFS。
步驟:
- 當您的機器與TFS斷了網路連線時,開啟Visual Studio會出現以下畫面:
圖38 Visual Studio無法連上TFS之訊息
- 接下來會詢問您是否要進入離線模式(Offline),請按[確定]鈕。
圖39 詢問您是否要進入離線模式
注意!Visual Studio的離線模式是指此Solution暫時脫離程式碼管控,之後所有程式碼管控相關功能都不能用,如Check In、Check Out等,後續仍可執行”Go Online”功能回復程式碼管控相關功能。 |
- 在Solution Explorer裡,您可以發現關於程式碼管控相關標誌都不見了,如鎖頭,勾勾等。此時您仍可以進行程式碼編輯與編譯等功能。
圖40 離線模式
- 待與TFS連線回復後,記得要重新開啟Visual Studio,在Solution Explorer裡,對根節點按右鍵選”Go Online”,會出現以下視窗,列出離線期間所有異動的檔案,可能會包含許多執行檔(.exe)、函式庫(.dll)等,您僅需要勾選您確實有異動的檔案即可,執行檔、函式庫請略過,然後按[Go Online]鈕。
圖41 選擇已變更的檔案,然後按[Go Online]鈕
- 回復線上(Online)模式成功後,程式碼管控相關標誌都回來啦,如下圖。後續即可進行簽入(Check In)動作。
圖42 回復至線上(Online)模式
9.4 如何檢視程式碼異動情形?
說明:檢視程式碼異動紀錄、分支(Branch)紀錄,同一檔案裡每一區段之異動人員與相應Work Item,從Work Item查詢相關程式碼異動。
步驟:
- 在Solution Explorer裡,對欲查詢的檔案按右鍵選”View History”,會顯示所有的Changeset清單,您可以任選兩者進行比較,按[Ctrl]鈕進行選擇,再按右鍵選[Compare]。
圖43 View History
- 差異視窗會分成兩邊,上方列出其所屬Changeset編號,內容差異的部份會成不同顏色標示:綠色代表新增內容;藍色代表修改內容;紅色代表刪除內容。
圖44 差異視窗
- 若您想要查詢某一Changeset實際異動內容,在Visual History視窗,選擇欲查詢之Changeset,按右鍵選”Changeset Details”,即可查到此Changeset所有異動檔案清單。若選擇某一檔案,按右鍵選”Compare” -> “With Previous Version”,即可查詢此檔案之異動內容。
圖45 查詢相關異動檔案
- 點選[Work Items]鈕,可查詢相關Work Item。
圖46 查詢相關Work Item
- 回到View History視窗,若您要查詢相關分支(Branch)紀錄,選擇某一Changeset,按[Track Change]鈕,會列出所有相關的Branch清單,請都勾選起來,再按[Visualize]鈕。
圖47 選擇Branch
- 會發現此Changeset目前只有套用於”DemoVersionControl”這個Branch(DemoVersionControl方塊裡有Changeset編號且底色是比較深的),而沒有在”DemoVersionControl20”分支,若您想把這個Changeset合併至”DemoVersionControl20”,可直接從”DemoVersionControl”拖曳至”DemoVersionControl20”,即會出現合併(Merge)精靈。
圖48 Tracking Changeset
圖49 合併(Merge)精靈
- 若您要查詢同一檔案裡每一區段之異動人員與相應Work Item,請開啟欲查詢的檔案內容,對任一處按右鍵選”Source Control” -> “Annotation”,會顯示一個唯讀視窗,右半邊是程式碼內容;左半邊是每一區段最後異動的Changeset編號、修改人員、修改日期,對Changeset連結處點選即可進一步查詢Changeset細節。
圖50 Annotated畫面
- 若Changeset有連結到Work Item的話還可以查詢到對應的Work Item,以了解修改此段程式碼是為了什麼目的。
圖51 從Changeset查詢Work Item
- 從Work Item也能查詢相關程式碼異動,切換至Team Explorer,點選您的Team Project -> Work Items -> Team Querys -> 任一查詢,開啟某一Work Item,再切換至”All Links”頁。
圖52 Work Item查詢
圖53 Work Item之”All Links”頁
10 結語
程式碼管控系統相關功能滿多的,且相當複雜,對於初學者需要一些時間練習才能熟悉,對於專案經理而言,落實版本管控流程是很重要的,不然很容易流於形式,變成一個垃圾堆就可惜了。