Git之深入解析如何将项目迁移到Git
生活随笔
收集整理的這篇文章主要介紹了
Git之深入解析如何将项目迁移到Git
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
一、前言
- 如果我們現(xiàn)在有一個正在使用其他 VCS 的代碼庫,但是已經(jīng)決定開始使用 Git,必須通過某種方式將項目遷移至 Git,那該怎么辦呢?
- Git 有一些通用系統(tǒng)的導(dǎo)入器,也可以開發(fā)自己定制的導(dǎo)入器,這里將會學(xué)習(xí)如何從幾個大型專業(yè)應(yīng)用的 SCM 系統(tǒng)中導(dǎo)入數(shù)據(jù),不僅因為它們是大多數(shù)想要轉(zhuǎn)換的用戶正在使用的系統(tǒng),也因為獲取針對它們的高質(zhì)量工具很容易。
二、Subversion
- 如果了解了關(guān)于 git svn 的內(nèi)容,可以輕松地使用那些指令來 git svn clone 一個倉庫,停止使用 Subversion 服務(wù)器,推送到一個新的 Git 服務(wù)器,然后就可以開始使用。 如果想要歷史,可以從 Subversion 服務(wù)器上盡可能快地拉取數(shù)據(jù)來完成這件事(這可能會花費一些時間)。還不熟悉 git svn 相關(guān)內(nèi)容的,請參考:Github之深入解析如何在那些托管在不同系統(tǒng)的項目上使用Git客戶端。
- 然而,導(dǎo)入并不完美,因為花費太長時間,可能我們用其他方法也許早已完成導(dǎo)入操作。導(dǎo)入產(chǎn)生的第一個問題就是作者信息,在 Subversion 中,每一個人提交時都需要在系統(tǒng)中有一個用戶,它會被記錄在提交信息內(nèi)。如果想要將上面的 Subversion 用戶映射到一個更好的 Git 作者數(shù)據(jù)中,需要一個 Subversion 用戶到 Git 用戶的映射。創(chuàng)建一個 users.txt 的文件包含像下面這種格式的映射:
- 為了獲得 SVN 使用的作者名字列表,可以運行這個:
- 這會將日志輸出為 XML 格式,然后保留作者信息行、去除重復(fù)、去除 XML 標(biāo)記,很顯然這只會在安裝了 grep、sort 與 perl 的機器上運行;然后,將輸出重定向到 users.txt 文件中,這樣就可以在每一個記錄后面加入對應(yīng)的 Git 用戶數(shù)據(jù)。
- 如果在 Windows 上運行它,那么到這里就會遇到問題,微軟提供了一些不錯的建議和示例,具體請參考:Learn how to migrate from Subversion (SVN) to Git, including history。
- 可以將此文件提供給 git svn 來幫助它更加精確地映射作者數(shù)據(jù),也可以通過傳遞 --no-metadata 給 clone 與 init 命令,告訴 git svn 不要包括 Subversion 通常會導(dǎo)入的元數(shù)據(jù)。在導(dǎo)入過程中,Git 會在每個提交說明的元數(shù)據(jù)中生成一個 git-svn-id。
- 當(dāng)想要將 Git 倉庫中的提交鏡像回原 SVN 倉庫中時,需要保留元數(shù)據(jù),如果不想在提交記錄中同步它,請直接省略掉 --no-metadata 選項。這會使 import 命令看起來像這樣:
- 現(xiàn)在在 my_project 目錄中應(yīng)當(dāng)有了一個更好的 Subversion 導(dǎo)入,并不像是下面這樣的提交:
- 反而它們看起來像是這樣:
- 不僅是 Author 字段更好看了,git-svn-id 也不存在了。之后,應(yīng)當(dāng)做一些導(dǎo)入后的清理工作,第一步應(yīng)當(dāng)清理 git svn 設(shè)置的奇怪的引用,首先移動標(biāo)簽,這樣它們就是標(biāo)簽而不是奇怪的遠(yuǎn)程引用,然后會移動剩余的分支這樣它們就是本地的。
- 為了將標(biāo)簽變?yōu)楹线m的 Git 標(biāo)簽,運行:
- 這會使原來在 refs/remotes/tags/ 里的遠(yuǎn)程分支引用變成真正的(輕量)標(biāo)簽。接下來,將 refs/remotes 下剩余的引用移動為本地分支:
- 可能會看到一些額外的分支,這些分支的后綴是 @xxx (其中 xxx 是一個數(shù)字),而在 Subversion 中只會看到一個分支,這實際上是 Subversion 一個叫做“peg-revisions”的功能,Git 在語法上沒有與之對應(yīng)的功能。因此, git svn 只是簡單地將 SVN peg-revision 版本號添加到分支名稱中,這同在 SVN 中修改分支名稱來定位一個分支的“peg-revision”是一樣的。如果對于 peg-revisions 完全不在乎,通過下面的命令可以輕易地移除他們:
- 現(xiàn)在所有的舊分支都是真正的 Git 分支,并且所有的舊標(biāo)簽都是真正的 Git 標(biāo)簽。
- 還有最后一點東西需要清理,git svn 會創(chuàng)建一個名為 trunk 的額外分支,它對應(yīng)于 Subversion 的默認(rèn)分支,然而 trunk 引用和 master 指向同一個位置。鑒于在 Git 中 master 最為常用,因此可以移除額外的分支:
- 最后一件要做的事情是,將新 Git 服務(wù)器添加為遠(yuǎn)程倉庫并推送到上面。如下所示,將服務(wù)器添加為遠(yuǎn)程倉庫:
- 因為想要上傳所有分支與標(biāo)簽,現(xiàn)在可以運行:
- 通過以上漂亮、干凈地導(dǎo)入操作,所有分支與標(biāo)簽都應(yīng)該在新 Git 服務(wù)器上。
三、Mercurial
- 因為 Mercurial 與 Git 在表示版本時有著非常相似的模型,也因為 Git 擁有更加強大的靈活性,將一個倉庫從 Mercurial 轉(zhuǎn)換到 Git 是相當(dāng)直接的,使用一個叫作“hg-fast-export”的工具,需要從這里拷貝一份:
- 轉(zhuǎn)換的第一步就是要先得到想要轉(zhuǎn)換的 Mercurial 倉庫的完整克隆:
- 下一步就是創(chuàng)建一個作者映射文件,Mercurial 對放入到變更集作者字段的內(nèi)容比 Git 更寬容一些,所以這是一個清理的好機會,只需要用到 bash 終端下的一行命令:
- 這會花費幾秒鐘,具體要看項目提交歷史有多少,最終 /tmp/authors 文件看起來會像這樣:
- 在這個例子中,同一個人(Bob)使用不同的名字創(chuàng)建變更集,其中一個實際上是正確的,另一個完全不符合 Git 提交的規(guī)范。hg-fast-export 通過對每一行應(yīng)用規(guī)則 “”="" ,將 映射到 來修正這個問題。在 和 字符串中,所有 Python 的 string_escape 支持的轉(zhuǎn)義序列都會被解釋。如果作者映射文件中并不包含匹配的 ,那么該作者將原封不動地被發(fā)送到 Git。如果所有的用戶名看起來都是正確的,那我們根本就不需要這個文件。在本例中,會使文件看起來像這樣:
- 當(dāng)分支和標(biāo)簽 Mercurial 中的名字在 Git 中不允許時,這種映射文件也可以用來重命名它們。
- 下一步是創(chuàng)建一個新的 Git 倉庫,然后運行導(dǎo)出腳本:
- -r 選項告訴 hg-fast-export 去哪里尋找我們想要轉(zhuǎn)換的 Mercurial 倉庫,-A 標(biāo)記告訴它在哪找到作者映射文件(分支和標(biāo)簽的映射文件分別通過 -B 和 -T 選項來指定),這個腳本會分析 Mercurial 變更集然后將它們轉(zhuǎn)換成 Git“fast-import”功能需要的腳本,這會花一點時間(盡管它比通過網(wǎng)格 更 快),輸出相當(dāng)?shù)娜唛L:
- 看起來非常好,所有 Mercurial 標(biāo)簽都已被轉(zhuǎn)換成 Git 標(biāo)簽,Mercurial 分支與書簽都被轉(zhuǎn)換成 Git 分支。現(xiàn)在已經(jīng)準(zhǔn)備好將倉庫推送到新的服務(wù)器那邊:
四、Bazaar
- Bazaar 是一個和 Git 非常類似的分布式版本控制系統(tǒng)(DVCS),因此將 Bazzar 倉庫轉(zhuǎn)換成 Git 倉庫是非常簡單易懂的。
- 想要完成轉(zhuǎn)換,需要安裝 bzr-fastimport 插件。
① 安裝 bzr-fastimport 插件
- 安裝 fastimport 插件的步驟在類 UNIX 操作系統(tǒng)和 Windows 上是不一樣的。在類 UNIX 系統(tǒng)上,最簡單的辦法就是安裝 bzr-fastimport 包,這種方法將會自動安裝所有需要的依賴。
- 例如,使用 Debian 及其派生系統(tǒng),只需要進行以下操作:
- 紅帽企業(yè)版系統(tǒng)(RHEL),使用以下命令:
- Fedora 從 22 版本開始,采用了新的包管理器 dnf,使用以下命令:
- 如果直接安裝包的方法不行,可能需要使用安裝插件的方法:
- 為了確保插件工作,同時也需要安裝有 fastimport 這一 Python 模塊,使用下面的命令可以檢查這一模塊安裝與否,如果沒有則安裝這一模塊:
- 如果上面的命令安裝失敗,可以直接到這個地址下載 fastimport 0.9.14。
- 在 Windows 上,bzr-fastimport 插件在 Git 使用脫機安裝并保持默認(rèn)安裝選項不變(可選框全部選中)的情況下是自動安裝的,在這種情況下,什么都不用做。
- 接下來,導(dǎo)入 Bazaar 倉庫的方法根據(jù)倉庫是有一個分支還是有多個分支而不同。
② 單分支項目
- cd 到包含 Bazaar 倉庫的路徑,然后初始化 Git 倉庫:
- 現(xiàn)在可以使用以下命令輕松地導(dǎo)出 Bazaar 倉庫并把它轉(zhuǎn)化成 Git 倉庫:
- 根據(jù)項目的大小,Git 倉庫會在幾秒鐘到幾分鐘之間構(gòu)建。
③ 多分支項目
- 同樣也能夠?qū)氚鄠€分支的 Bazaar 倉庫,讓我們假設(shè)有兩個分支,一個代表主分支(myProject.trunk),另一個是工作分支(myProject.work):
- 創(chuàng)建一個 Git 倉庫并 cd 進去:
- 將 master 分支拉入 Git:
- 將工作分支拉入 Git:
- 現(xiàn)在 git branch 會同時顯示 master 分支和 work 分支,檢查日志以確保它們是完整的,并刪除 marks.bzr 和 marks.git 文件。
④ 同步暫存區(qū)
- 無論有多少分支以及使用的導(dǎo)入方法如何,暫存區(qū)都不會與 HEAD 同步,并且在導(dǎo)入多個分支時,工作目錄也不會同步。這種情況使用下面的命令可以輕松解決:
⑤ 忽略被 .bzrignore 文件指明忽略的文件
- 現(xiàn)在看看要忽略的文件,第一件事情就是將 .bzrignore 重命名為 .gitignore,如果 .bzrignore 文件里面有一行或數(shù)行以“!!”或“RE:”開頭的內(nèi)容,必須修改它,并且可能還要創(chuàng)建幾個 .gitignore 文件,以便忽略與 Bazaar 忽略的文件完全相同的文件。
- 最后,必須創(chuàng)建一個提交,其中包含此次遷移的修改:
⑥ 推送你的倉庫到服務(wù)器
- 終于到這一步了,現(xiàn)在可以推送倉庫到它的“云端新家”了:
- Git 倉庫準(zhǔn)備就緒。
五、Perforce
- 下一個將要看到導(dǎo)入的系統(tǒng)是 Perforce,就像之前討論過的,有兩種方式讓 Git 與 Perforce 互相通信:git-p4 與 Perforce Git Fusion。
① Perforce Git Fusion
- Git Fusion 使這個過程毫無痛苦,只需要使用在 Git Fusion 中討論過的配置文件來配置項目設(shè)置、用戶映射與分支,然后克隆整個倉庫。Git Fusion 讓我們處在一個看起來像是原生 Git 倉庫的環(huán)境中,如果愿意的話可以隨時將它推送到一個原生 Git 托管中,如果喜歡的話甚至可以使用 Perforce 作為我們的 Git 托管。
② Git-p4
- Git-p4 也可以作為一個導(dǎo)入工具。作為例子,我們將從 Perforce 公開倉庫中導(dǎo)入 Jam 項目,為了設(shè)置客戶端,必須導(dǎo)出 P4PORT 環(huán)境變量指向 Perforce 倉庫:
- 為了繼續(xù)后續(xù)步驟,需要連接到 Perforce 倉庫,在我們的例子中將會使用在 public.perforce.com 的公開倉庫,但是可以使用任何有權(quán)限的倉庫。
- 運行 git p4 clone 命令從 Perforce 服務(wù)器導(dǎo)入 Jam 項目,提供倉庫、項目路徑與想要存放導(dǎo)入項目的路徑:
- 這個特定的項目只有一個分支,但是如果在分支視圖(或者說一些目錄)中配置了一些分支,可以將 --detect-branches 選項傳遞給 git p4 clone 來導(dǎo)入項目的所有分支。
- 此時,幾乎已經(jīng)完成了,如果進入 p4import 目錄中并運行 git log,可以看到導(dǎo)入工作:
- 可以看到 git-p4 在每一個提交里都留下了一個標(biāo)識符,如果之后想要引用 Perforce 的修改序號的話,標(biāo)識符保留在那里也是可以的。然而,如果想要移除標(biāo)識符,現(xiàn)在正是這么做的時候,在開始在新倉庫中工作之前。可以使用 git filter-branch 將全部標(biāo)識符移除:
- 如果運行 git log,會看到所有提交的 SHA-1 校驗和都改變了,但是提交信息中不再有 git-p4 字符串了:
- 現(xiàn)在導(dǎo)入已經(jīng)準(zhǔn)備好推送到新 Git 服務(wù)器上了。
六、TFS
- 如果我們的團隊正在將他們的源代碼管理從 TFVC 轉(zhuǎn)換為 Git,會想要最高程度的無損轉(zhuǎn)換,在這里只分析介紹 git-tfs,因為 git-tfs 支持分支,而使用 git-tf 代價太大。這是一個單向轉(zhuǎn)換,意味著 Git 倉庫無法連接到原始的 TFVC 項目。
- 第一件事是映射用戶名,TFVC 對待變更集作者字段的內(nèi)容相當(dāng)寬容,但是 Git 需要人類可讀的名字與郵箱地址,可以通過 tf 命令行客戶端來獲取這個信息,像這樣:
- 這會將歷史中的所有變更集抓取下來并放到 AUTHORS_TMP 文件中,然后我們將會將 User 列(第二個)取出來。打開文件找到列開始與結(jié)束的字符并替換,在下面的命令行中,cut 命令的參數(shù) 11-20 就是我們找到的:
- cut 命令只會保留每行中第 11 個到第 22 個字符,tail 命令會跳過前兩行,就是字段表頭與 ASCII 風(fēng)格的下劃線。所有這些的結(jié)果通過管道送到 sort 和 uniq 來去除重復(fù),然后保存到 AUTOHRS 文件中。下一步是手動的,為了讓 git-tfs 有效地使用這個文件,每一行必須是這種格式:
- 左邊的部分是 TFVC 中的 “User” 字段,等號右邊的部分是將被用作 Git 提交的用戶名。一旦有了這個文件,下一件事就是生成一個需要的 TFVC 項目的完整克隆:
- 接下來要從提交信息底部清理 git-tfs-id 區(qū)塊,如下的命令會完成這個任務(wù):
- 那會使用 Git 終端環(huán)境中的 sed 命令來將所有以 “git-tfs-id:” 開頭的行替換為 Git 會忽略的空白。
- 全部完成后,就已經(jīng)準(zhǔn)備好去增加一個新的遠(yuǎn)程倉庫,推送所有的分支上去,然后我們的團隊就可以開始用 Git 工作了。
① 一個自定義的導(dǎo)入器
- 如果系統(tǒng)不是上述中的任何一個,需要在線查找一個導(dǎo)入器,針對許多其他系統(tǒng)有很多高質(zhì)量的導(dǎo)入器,包括 CVS、Clear Case、Visual Source Safe,甚至是一個檔案目錄。如果沒有一個工具適合,需要一個不知名的工具,或者需要更大自由度的自定義導(dǎo)入過程,應(yīng)當(dāng)使用 git fast-import,這個命令從標(biāo)準(zhǔn)輸入中讀取簡單指令來寫入特定的 Git 數(shù)據(jù)。通過這種方式創(chuàng)建 Git 對象比運行原始 Git 命令或直接寫入原始對象更容易些,可以編寫導(dǎo)入腳本,從要導(dǎo)入的系統(tǒng)中讀取必要數(shù)據(jù),然后直接打印指令到標(biāo)準(zhǔn)輸出,然后可以運行這個程序并通過 git fast-import 重定向管道輸出。
- 為了快速演示,現(xiàn)在寫一個簡單的導(dǎo)入器,假設(shè)在 current 工作,有時候會備份項目到時間標(biāo)簽 back_YYYY_MM_DD 備份目錄中,想要將這些導(dǎo)入到 Git 中,目錄結(jié)構(gòu)看起來是這樣:
- 為了導(dǎo)入一個 Git 目錄,需要了解 Git 如何存儲它的數(shù)據(jù),我們知道,Git 在底層存儲指向內(nèi)容快照的提交對象的鏈表,因此所有要做的就是告訴 fast-import 哪些內(nèi)容是快照,哪個提交數(shù)據(jù)指向它們,以及它們進入的順序。策略是一次訪問一個快照,然后用每個目錄中的內(nèi)容創(chuàng)建提交,并且將每一個提交與前一個連接起來。
- 使用強制策略,我們將會使用 Ruby 寫這個,因為它是我們平常工作中使用的并且它很容易讀懂,可以使用任何熟悉的東西來非常輕松地寫這個例子,它只需要將合適的信息打印到標(biāo)準(zhǔn)輸出。然而,如果在 Windows 上,這意味著需要特別注意不要引入回車符到行尾—— git fast-import 非常特別地只接受換行符(LF)而不是 Windows 使用的回車換行符(CRLF)。
- 現(xiàn)在開始,需要進入目標(biāo)目錄中并識別每一個子目錄,每一個都是要導(dǎo)入為提交的快照,要進入到每個子目錄中并為導(dǎo)出它打印必要的命令,基本主循環(huán)像這個樣子:
- 在每個目錄內(nèi)運行 print_export,將會拿到清單并標(biāo)記之前的快照,然后返回清單并標(biāo)記現(xiàn)在的快照;通過這種方式,可以將它們合適地連接在一起。“標(biāo)記”是一個給提交標(biāo)識符的 fast-import 術(shù)語;當(dāng)創(chuàng)建提交,為每一個提交賦予一個標(biāo)記來將它與其他提交連接在一起,這樣,在 print_export 方法中第一件要做的事就是從目錄名字生成一個標(biāo)記:
- 可以創(chuàng)建一個目錄的數(shù)組并使用索引做為標(biāo)記,因為標(biāo)記必須是一個整數(shù)。方法類似這樣:
- 既然有一個整數(shù)代表你的提交,那還要給提交元數(shù)據(jù)一個日期,因為目錄名字表達(dá)了日期,所以將會從中解析出日期, print_export 文件的下一行是:
- 那會返回每一個目錄日期的整數(shù),最后一項每個提交需要的元數(shù)據(jù)是提交者信息,它將會被硬編碼在全局變量中:
- 現(xiàn)在準(zhǔn)備開始為導(dǎo)入器打印出提交數(shù)據(jù),初始信息聲明定義了一個提交對象與它所在的分支,緊接著一個生成的標(biāo)記、提交者信息與提交信息、然后是一個之前的提交,如果它存在的話,代碼看起來像這樣:
- 我們將硬編碼時區(qū)信息(-0700),因為這樣很容易,如果從其他系統(tǒng)導(dǎo)入,必須指定為一個偏移的時區(qū),提交信息必須指定為特殊的格式:
- 這個格式包括文本數(shù)據(jù)、將要讀取數(shù)據(jù)的大小、一個換行符、最終的數(shù)據(jù),因為之后還需要為文件內(nèi)容指定相同的數(shù)據(jù)格式,需要創(chuàng)建一個幫助函數(shù),export_data:
- 剩下的工作就是指定每一個快照的文件內(nèi)容,這很輕松,因為每一個目錄都是一個快照,可以在目錄中的每一個文件內(nèi)容后打印 deleteall 命令,Git 將會適當(dāng)?shù)赜涗浢恳粋€快照:
- 因為大多數(shù)系統(tǒng)認(rèn)為他們的版本是從一個提交變化到另一個提交,fast-import 也可以為每一個提交執(zhí)行命令來指定哪些文件是添加的、刪除的或修改的與新內(nèi)容是哪些,可以計算快照間的不同并只提供這些數(shù)據(jù),但是這樣做會很復(fù)雜;也可以把所有數(shù)據(jù)給 Git 然后讓它為我們指出來,如果這更適合數(shù)據(jù),查閱 fast-import man 幫助頁來了解如何以這種方式提供數(shù)據(jù)。
- 這種列出新文件內(nèi)容或用新內(nèi)容指定修改文件的格式如同下面的內(nèi)容:
- 這里,644 是模式(如果有可執(zhí)行文件,反而需要檢測并指定 755),inline 表示將會立即把內(nèi)容放在本行之后,inline_data 方法看起來像這樣:
- 可以重用之前定義的 export_data 方法,因為它與定義的提交信息數(shù)據(jù)的方法一樣。
- 最后一件需要做的是返回當(dāng)前的標(biāo)記以便它可以傳給下一個迭代:
- 如果在 Windows 上還需要確保增加一個額外步驟,正如之前提到的,Windows 使用 CRLF 作為換行符而 git fast-import 只接受 LF,為了修正這個問題使 git fast-import 正常工作,需要告訴 ruby 使用 LF 代替 CRLF:
- 就是這樣,這是全部的腳本:
- 如果運行這個腳本,會得到類似下面的內(nèi)容:
- 為了運行導(dǎo)入器,將這些輸出用管道重定向到想要導(dǎo)入的 Git 目錄中的 git fast-import,可以創(chuàng)建一個新的目錄并在其中運行 git init 作為開始,然后運行腳本:
- 正如所看到的,當(dāng)它成功完成時,它會給我們一串關(guān)于它完成內(nèi)容的統(tǒng)計。這本例中,一共導(dǎo)入了 13 個對象、4 次提交到 1 個分支,現(xiàn)在可以運行 git log 來看一下你的新歷史:
- 做得很好,一個漂亮、干凈的 Git 倉庫,要注意的一點是并沒有檢出任何東西,一開始工作目錄內(nèi)并沒有任何文件。為了得到他們,必須將分支重置到 master 所在的地方:
- 可以通過 fast-import 工具做很多事情,處理不同模式、二進制數(shù)據(jù)、多個分支與合并、標(biāo)簽、進度指示等。一些更復(fù)雜情形下的例子可以在 Git 源代碼目錄中的 contrib/fast-import 目錄中找到。
總結(jié)
以上是生活随笔為你收集整理的Git之深入解析如何将项目迁移到Git的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: GitHub之深入解析脚本·自定义与修改
- 下一篇: Git内部原理之深入解析Git对象