簡體   English   中英

如何拆分git存儲庫並按照目錄重命名?

[英]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" )
'

基本上這是做什么的:

  1. 刪除我需要的三個目錄NAME1,NAME2或NAME3 之外的所有文件(一個項目在其生命周期內重命名為NAME1 - > NAME2 - > NAME3)。

  2. 一切行動這三個目錄到庫的根。

  3. 我需要測試“$ 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個小時才能完成。 這是我做的事情:

  1. 獲取該文件夾的所有過去名稱的列表。 在我的情況下,只有兩個, old-namenew-name
  2. 對於每個名字:

     $ git checkout master $ git checkout -b filter-old-name $ git filter-branch --subdirectory-filter old-name 

    這將為您提供多個斷開連接的分支,每個分支包含其中一個名稱的歷史記錄。

  3. filter-old-name分支應以重命名文件夾的提交結束filter-new-name分支應以相同的提交開頭 (如果存在多個重命名,則同樣適用:您將使用相同數量的分支,每個分支都與下一個分支共享。)一個應該刪除所有內容,另一個應該重新創建它。 確保這兩個提交具有相同的內容; 如果不這樣做,除了重命名之外,文件也被修改,您需要合並更改。 (在我的情況下,我沒有這個問題所以我不知道如何解決它。)

    檢查這個的一個簡單方法是嘗試在filter-old-name之上重新設置filter-new-name ,然后將兩個提交壓縮在一起:git應該抱怨這會產生一個空提交。 (請注意,您需要在備用分支上執行此操作,然后將其刪除:rebasing從提交中刪除提交者信息,從而丟失您要保留的一些歷史記錄。)

  4. 下一步是將兩個分支移植到一起, 跳過重命名文件夾的兩個提交。 (否則將會有一個奇怪的跳轉,其中所有內容都被刪除並重新創建。)這包括找到兩個提交的完整SHA(全部40個字符!)並將它們放入git的信息中,首先使用名稱分支的提交,然后使用舊的 name branch的提交秒。

     $ echo $NEW_NAME_SECOND_COMMIT_SHA1 $OLD_NAME_PENULTIMATE_COMMIT_SHA1 >> .git/info/grafts 

    如果你做得對, git log --graph現在應該顯示從新歷史的結尾到舊歷史的開頭的一行。

  5. 這種移植物目前是暫時的:它還不是歷史的一部分,也不會跟隨克隆或推動。 使它永久化:

     $ git filter-branch 

    這將重新filter-new-name分支而不嘗試進行任何進一步的更改,使移植永久化(更改filter-new-name分支中的所有提交)。 您現在應該能夠刪除.git/info/grafts文件。

在所有這些結束時,您現在應該在filter-new-name分支上具有該文件夾的兩個名稱的所有歷史記錄。 然后,您可以使用此單獨的存儲庫,或將其合並到另一個存儲庫中,或者您想要對此歷史記錄執行的任何操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM