假設:我們要将 source 倉庫(repo)下的 foo 檔案夾 移動到 destination 倉庫下,除了檔案内容遷移外,還包括相關的所有日志。
source倉庫: https://github.com/user/source.git
destination倉庫: https://github.com/user/destination.git
步驟1
為了不改變目前克隆出來的版本,我們需要重新克隆一個原始備份出來,在原始備份裡進行操作,依次執行如下指令
mkdir backup
cd backup
git clone https://github.com/user/source.git
cd source
步驟2
将我們需要複制的檔案夾更改到目前備份克隆裡的根目錄下,這裡 git 提供了 git filter-branch 指令允許我們調整整個倉庫的目錄結構:隻保留過濾器指定的檔案及相關日志, 删除其他檔案内容。
為了防止我們誤操作導緻覆寫線上倉庫的内容,我們需要先解除備份倉庫與線上倉庫的關系,是以此步驟依次執行如下指令
git remote rm origin
git filter-branch --subdirectory-filter foo -- --all
這裡如果存在 tag 被覆寫(rewritten),則會報警告要求使用 "--tag-name-filter cat", 不過可以忽略不管。當然,如果要複制的目錄存在分支(branch)或者标簽(tag),不确定是不是也能一起複制過去,但按照最終複制過去是一個分支的做法,可能并沒有,沒有試驗過(了解的同學可以告知下)。
另外,filter指令要在根目錄下執行,foo如果是子目錄下的檔案夾,則需要使用相對路徑,而不是隻有一個檔案夾名。
步驟3(可選)
如果我們需要将目錄原封不動複制過去,包含它的檔案夾,那麼我們還需要建立一個同樣名字的目錄到根目錄下,将 步驟2 中過濾到根目錄下的所有檔案移動到該目錄下,最後添加并送出到本地。指令依次如下
mkdir foo
mv * foo
git add .
git commit
如果我們不需要原目錄,隻需要它裡面的内容,那麼就直接跳過此步驟即可
這裡 commit時會要求輸入日志, 使用的是 vim, 使用相關指令編輯即可。
謹記,目前所有的操作都是臨時操作,不會影響到線上倉庫的。
步驟4
有了步驟3的臨時倉庫,接下來就是将其合并到目标倉庫中去。
假設目标倉庫已經克隆到 "projects/destination" 裡面,依次執行如下指令
cd ../../projects/destination
git remote add modified-source ../../backup/source
git pull modified-source master --allow-unrelated-histories
git remote rm modified-source
上述操作, 将臨時倉庫添加為目标倉庫的一個分支(modified-source), 然後将其(master分支)合并到主幹(注意,紅色字型為一體,即拉的是modified-source的master到目前分支),最後移除臨時分支(modified-source)
步驟5
檢查目标倉庫是否符合自己的需求,确定後送出即可
最後,可以直接删除備份倉庫。