[英]How to split a git repository and follow directory renames?
我目前有一個包含許多項目的大型git存儲庫,每個項目都在自己的子目錄中。 我需要將它拆分為單獨的存儲庫,每個項目都在自己的倉庫中。
我試過git filter-branch --prune-empty --subdirectory-filter PROJECT master
但是,許多項目目錄在其生命中經歷了多次重命名,並且git filter-branch
不遵循重命名,因此有效地提取的repo在上次重命名之前沒有任何歷史記錄。
如何從一個大的git repo中有效地提取子目錄,並將所有該目錄重命名回到過去?
感謝@Chronial,我根據自己的需要制作了一個腳本來按摩我的git repo:
git filter-branch --prune-empty --index-filter '
# Delete files which are NOT needed
git ls-files -z | egrep -zv "^(NAME1|NAME2|NAME3)" |
xargs -0 -r git rm --cached -q
# Move files to root directory
git ls-files -s | sed -e "s-\t\(NAME1\|NAME2\|NAME3\)/-\t-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
( test ! -f "$GIT_INDEX_FILE.new" \
|| mv -f "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE" )
'
基本上這是做什么的:
刪除我需要的三個目錄NAME1,NAME2或NAME3 之外的所有文件(一個項目在其生命周期內重命名為NAME1 - > NAME2 - > NAME3)。
一切行動這三個目錄內到庫的根。
我需要測試“$ GIT_INDEX_FILE.new”是否存在,因為將svn導入git會創建沒有任何文件的提交(僅限目錄的提交)。 僅當repo最初是使用'git svn clone'創建時才需要。
我認為git沒有內置功能。 您必須構建自己的過濾器。 只需使用git filter-branch --prune-empty --tree-filter YOURSCRIPT
。 然后,您的腳本必須識別正確的文件夾(可能是其中的特定文件的名稱,或者您可能有此項目過去所有名稱的列表),刪除其他所有文件夾並將文件夾內容移動到一個級別。
如果您的repo非常大並且您沒有夜間運行此腳本,那么使用--index-filter
可以更快地實現相同的效果,但編寫該腳本會更復雜。 您將不得不使用git命令來修改索引而不是文件系統修改命令。
我有一個非常大的存儲庫,我需要從中提取一個文件夾; 甚至--index-filter
預計需要8個小時才能完成。 這是我做的事情:
old-name
和new-name
。 對於每個名字:
$ git checkout master $ git checkout -b filter-old-name $ git filter-branch --subdirectory-filter old-name
這將為您提供多個斷開連接的分支,每個分支包含其中一個名稱的歷史記錄。
filter-old-name
分支應以重命名文件夾的提交結束 , filter-new-name
分支應以相同的提交開頭 。 (如果存在多個重命名,則同樣適用:您將使用相同數量的分支,每個分支都與下一個分支共享。)一個應該刪除所有內容,另一個應該重新創建它。 確保這兩個提交具有相同的內容; 如果不這樣做,除了重命名之外,文件也被修改,您需要合並更改。 (在我的情況下,我沒有這個問題所以我不知道如何解決它。)
檢查這個的一個簡單方法是嘗試在filter-old-name
之上重新設置filter-new-name
,然后將兩個提交壓縮在一起:git應該抱怨這會產生一個空提交。 (請注意,您需要在備用分支上執行此操作,然后將其刪除:rebasing從提交中刪除提交者信息,從而丟失您要保留的一些歷史記錄。)
下一步是將兩個分支移植到一起, 跳過重命名文件夾的兩個提交。 (否則將會有一個奇怪的跳轉,其中所有內容都被刪除並重新創建。)這包括找到兩個提交的完整SHA(全部40個字符!)並將它們放入git的信息中,首先使用新名稱分支的提交,然后使用舊的 name branch的提交秒。
$ echo $NEW_NAME_SECOND_COMMIT_SHA1 $OLD_NAME_PENULTIMATE_COMMIT_SHA1 >> .git/info/grafts
如果你做得對, git log --graph
現在應該顯示從新歷史的結尾到舊歷史的開頭的一行。
這種移植物目前是暫時的:它還不是歷史的一部分,也不會跟隨克隆或推動。 使它永久化:
$ git filter-branch
這將重新filter-new-name
分支而不嘗試進行任何進一步的更改,使移植永久化(更改filter-new-name
分支中的所有提交)。 您現在應該能夠刪除.git/info/grafts
文件。
在所有這些結束時,您現在應該在filter-new-name
分支上具有該文件夾的兩個名稱的所有歷史記錄。 然后,您可以使用此單獨的存儲庫,或將其合並到另一個存儲庫中,或者您想要對此歷史記錄執行的任何操作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.