共用方式為


瞭解如何從 Subversion (SVN) 遷移至 Git,包括歷程記錄

Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019

從 Subversion(SVN)等其他版本控制系統移至 Git 時,我們通常建議您進行「僅遷移最新版本」,這樣只會移轉存放庫最新內容,而不包含歷程記錄。 不過,許多人想要執行更進階的遷移,包括歷史。 本文中提供的指引介紹具有歷程記錄的遷移

SVN 移轉至 Git 的複雜度可能會有所不同,這取決於存放庫的久遠程度、已建立和合併的分支數量,以及您是否使用標準的 SVN 或類似的工具如 SVK。

可以很簡單,如果:

  • 您有新的存放庫
  • 您有主幹、分支和標記目錄的標準配置

可能會很複雜,如果:

  • 您的小組已執行許多分支和合併作業
  • 您的存放庫遵循非標準目錄設定
  • 您的目錄設定已隨著時間變更

有數種方式可從 SVN 遷移至 Git。 本文中所述的方法是以使用 Git-svn 為基礎,這是一種 Git 延伸模組,可用來將 Subversion 存放庫簽出至本機 Git 存放庫,然後將變更從本機 Git 存放庫推送回 Subversion 存放庫。 這些步驟詳細說明了在 Windows 環境中從 SVN 遷移至 Git 的過程,並且不需要同步回原始的 SVN 存放庫。 結果將會是一個裸的 Git 儲存庫,可與小組其他成員共用。

先決條件

類別 需求
專案存取 專案的成員。
許可 - 在私人項目中檢視程式碼:至少 基本 權限。
- 複製或貢獻私人專案中的程式碼:作為 貢獻者 安全群組的成員或在專案中具有相應的許可權。
- 設定分支或存放庫許可權:管理分支或存放庫的許可權 許可權。
- 變更預設分支:編輯原則 存放庫的許可權。
- 匯入存放庫:專案管理員成員 安全組或 Git 專案層級 建立存放庫 許可權設定為 允許。 如需詳細資訊,請參閱 設定 Git 存放庫許可權
服務 啟用 Repos
工具 選擇性。 使用 az repos 命令:Azure DevOps CLI

注意

在公用專案中,具有 項目關係人 存取權的使用者具有 Azure Repos 的完整存取權,包括檢視、複製及參與程式代碼。

類別 需求
專案存取 專案的成員。
許可 - 查看程式碼:至少 基本 權限。
- 複製程式碼或貢獻程式碼:屬於 參與者安全組 的成員或具有專案中的對應許可權。
服務 啟用 Repos

注意

在您嘗試將原始程式碼從集中式版本控制系統移轉至 Git 之前,請確定您已熟悉集中式和分散式版本控制系統之間的差異,並 規劃小組的移轉。 準備好之後,您就可以開始移轉。

從 SVN 移轉至 Git 的高階工作流程如下所示:

  • 準備移轉環境
  • 將來源 SVN 存放庫轉換為本機 Git 存放庫
  • (選擇性)在開發人員繼續使用 SVN 的同時,同步本機 Git 存放庫與 SVN 存放庫的任何變更。
  • 將本機 Git 存放庫推送至裝載於 Azure Repos 上的遠端 Git 存放庫
  • 鎖定 SVN 存放庫、將 SVN 存放庫的任何剩餘變更同步至本機 Git 存放庫,並將最終變更推送至 Azure Repos 上的遠端 Git 存放庫
  • 開發人員切換至 Git 作為主要原始檔控制系統

準備移轉環境

在本機工作站上設定移轉環境,並安裝下列軟體:

您也需要為組織建立 Git 存放庫來裝載已轉換的 SVN 存放庫,您可以遵循 在專案中建立新的 Git 存放庫

將來源 SVN 存放庫轉換為本機 Git 存放庫

此步驟的目標是將來源 Subversion 存放庫轉換成本機 Git 存放庫。 裸 Git 存放庫沒有可變更檔案的本地工作區,而僅包含存放庫的歷史記錄和有關該存放庫本身的元數據。 這是建議的格式,可透過裝載在 Azure Repos 等服務上的遠端存放庫共用 Git 存放庫。

提示

裸存儲庫 Git 存放庫的結構不同,因為它沒有工作目錄,所以無法直接提交到存放庫。

裸 Git 存放庫

擷取所有 Subversion 作者的清單

Subversion 只會在每次提交中使用用戶名稱,而 Git 則儲存真實姓名和電子郵件地址。 根據預設,git-svn 工具會在作者和電子郵件欄位中列出 SVN 使用者名稱。 不過,您可以為 SVN 使用者建立一個對應檔案,其中包含相應的 Git 名稱和電子郵件。

Subversion 使用者

Subversion 使用者

Git 使用者

git 使用者

若要從本機 Subversion 簽出根目錄擷取所有 SVN 使用者的清單,請執行下列 PowerShell 命令:

如要獲得在 utf8NoBOM 編碼中的結果,請執行下列命令:

svn.exe log --quiet | ? { $_ -notlike '-*' } | % { "{0} = {0} " -f ($_ -split ' | ')[1] } | Select-Object -Unique | Sort-Object | Out-File 'authors-transform.txt' -Encoding utf8NoBOM

如需取得ASCII編碼結果,請執行下列命令:

svn.exe log --quiet | ? { $_ -notlike '-*' } | % { "{0} = {0} " -f ($_ -split ' | ')[1] } | Select-Object -Unique | Sort-Object | Out-File 'authors-transform.txt' -Encoding ASCII

此命令會擷取所有記錄訊息、擷取使用者名稱、排除任何重複的用戶名稱、排序用戶名稱,並將其放入 UTF-8格式的authors-transform.txt 檔案中(或ASCII 格式,視您指定的編碼方式而定)。 然後,您可以編輯檔案中的每個行,以建立 SVN 用戶的對應至格式正確的 Git 使用者。 例如,您可以對應 jamal = jamal <jamal>jamal = Jamal Hartnett <jamal@fabrikam-fiber.com>

使用 git-svn 複製 Subversion 存放庫

下列命令會使用在先前步驟中建立的 authors-transform.txt 檔案,執行標準 git-svn 轉換。 它會將 Git 存放庫放在 c:\mytempdir 本機電腦的資料夾中。

git svn clone ["SVN repo URL"] --prefix=svn/ --no-metadata --authors-file "authors-transform.txt" --stdlayout c:\mytempdir

注意

--prefix=svn/是必要的,因為否則工具無法從匯入的修訂中判斷 SVN 修訂。 建議您設定前置字串(後置斜線),因為 SVN 追蹤的引用會位於 refs/remotes/$prefix/,這與 Git 自己的遠端追蹤分支配置相容(refs/remotes/$remote/)。

如果您想要追蹤共用通用存放庫的多個項目,設定前置詞也很有用。 根據預設,前置詞會設定為 origin/

如果您使用標準主幹、分支、標記配置,則就只需要放置 --stdlayout。 不過,如果您有不同的東西,您可能必須傳遞 --trunk--branches--tags 來找出哪個是什麼。 例如,如果您的存放庫結構是 trunk/companydir ,而且您已分支該結構,而不是主幹,您可能會想要 --trunk=trunk/companydir --branches=branches

git svn clone ["SVN repo URL"] --prefix=svn/ --no-metadata --trunk=/trunk --branches=/branches --tags=/tags  --authors-file "authors-transform.txt" c:\mytempdir

注意

此命令可能需要幾分鐘到數小時的時間,視 SVN 存放庫的大小而定。 完成後,您將會有您的版本庫的 Git 檢出。

轉換版本控制特定組態

如果您的 SVN 存放庫使用 svn:ignore 屬性,您可以藉由以下方式轉換成 .gitignore 文件:

cd c:\mytempdir
git svn show-ignore --id=origin/trunk > .gitignore
git add .gitignore
git commit -m 'Convert svn:ignore properties to .gitignore.'

提示

深入瞭解 .gitignore使用 Git 忽略檔案變更

將存放庫推送到裸庫 Git 存放庫

在此步驟中,您將建立裸機存放庫,並使其預設分支符合 SVN 的主幹分支名稱。

  1. 建立裸 Git 存放庫

    git init --bare c:\new-bare.git
    cd c:\new-bare.git
    git symbolic-ref HEAD refs/heads/svn/trunk
    
  2. 將本機 Git 存放庫推送至新的裸 Git 存放庫

    cd c:\mytempdir 
    git remote add bare c:\new-bare.git 
    git config remote.bare.push refs/remotes/*:refs/heads/* 
    git push bare 
    
  3. trunk 分支重新命名為 main。 您的主要開發分支將命名為「trunk」,這與它在 Subversion 中的名稱相匹配。 您可能需要使用以下指令將其重新命名為 Git 的標準 main 分支:

    cd c:\new-bare.git
    git branch -m svn/trunk main
    
  4. 清除分支和標記 git-svn 會將所有 Subversion 標籤變成 Git 中非常簡短的分支,格式為 “tags/name”。 您會想要將所有分支轉換成實際的 Git 標籤,或刪除它們。

將 SVN 標籤移至 Git 標籤

cd c:\new-bare.git
git for-each-ref --format='%(refname)' refs/heads/svn/tags | % { $_.Replace('refs/heads/svn/tags/','') } | % { git tag $_ "refs/heads/svn/tags/$_"; git branch -D "svn/tags/$_" }

進階移轉

建立所有 SVN 分支作為適當的 Git 分支

雖然將所有 SVN 分支建立為適當的 Git 分支很容易,但建議您先評估下列幾點,再繼續:

  • 如果有功能分支:您是否可以等到它們整合至主幹后再移轉?

  • 如果有發行分支:保留SVN以進行維護是否合理? 如果您移轉功能分支,您是否已準備好在 Git 之外管理分支?

如果您仍想要移轉現有的分支,請執行下列 PowerShell 命令:

git for-each-ref --format='%(refname)' refs/remotes | % { $_.Replace('refs/remotes/','') } | % { git branch "$_" "refs/remotes/$_"; git branch -r -d "$_"; }

注意

此命令可能需要幾分鐘到數小時的時間,視 SVN 存放庫的大小而定。 完成後,您將會有儲存庫的 Git 檢出。

僅移轉特定修訂

如果未指定,git-svn clone 會將所有修訂從第一次提交 (r1) 移轉到 HEAD。 如果您只需要移轉特定的一組修訂,則應在git-svn clone命令中附加-r選項。

例如,如果您需要從 rev 100 移轉至 HEAD,命令看起來會像這樣:

git svn clone ["SVN repo URL"] --prefix=svn/ --no-metadata --authors-file "authors-transform.txt" --stdlayout c:\mytempdir -r100:HEAD

更新您的工作流程

從集中式版本控制系統移至 Git 不僅僅是移轉程式代碼。 您的小組需要訓練,以瞭解 Git 與現有版本控制系統有何不同,以及這些差異如何影響日常工作。 深入了解

參考資訊

作者:霍薩姆·卡梅爾,威廉·薩拉扎爾 |尋找本文的來源,並與 ALM 連線 |DevOps Rangers 分支指引

(c) 2017 Microsoft公司。 保留所有權利。 本文件提供「as-is」。本文件中的資訊以及表達的觀點 (包括 URL 及其他網路網站參考) 如有變更,恕不另行通知。 您必須承擔使用本文件的風險。

本文件不提供您在任何 Microsoft 產品中的智慧財產權的任何法定權利。 您可以複製和使用本文件,以參考為目的供內部使用。