2011-09-07 140 views
11

我正在拆分最初駐留在單個Subversion存儲庫中的一組舊應用程序。如何刪除Git倉庫中不在工作目錄中的所有文件?

我已經將它轉換爲Git存儲庫並刪除了我不想要的內容,但是我希望通過刪除與刪除的文件關聯的歷史數據來減少存儲庫的數量(原始存儲庫將維護以供參考,因此在新版本中不需要)。

理想情況下,我想要做的是遍歷整個存儲庫並刪除工作目錄中不存在的任何文件或文件夾以及與其關聯的任何歷史記錄。這會讓我得到HEAD的內容以及影響這些文件的提交歷史。然而,我還沒有遇到過這樣的做法(孤立HEAD沒有幫助,因爲它不保存歷史)。

這可能嗎?我知道如何通過git-filter-branch從整個歷史記錄中刪除單個文件或文件夾,但是有太多的文件和文件夾,這是一個實用的方法......除非有一種方法可以對所有不在HEAD的文件進行過濾?

+0

那麼,那些得到了過去重命名的文件?刪除重命名時的歷史記錄或保留重命名(並跟蹤重命名之前的不同文件名) – knittl

+0

好點。我更願意在重命名之前保留歷史記錄,所以需要在其中添加一些額外的文件,這很好。 –

回答

3

我這樣做了幾次 - 提取單個文件的提交併從中創建新的存儲庫。它有點像這樣:

$ c=10; for commit in $(git log --format=%h -- path/to/file|tac); do 
     c=$((c+1)) 
     git format-patch -1 --stdout $commit > $c.patch 
    done 

這將創建補丁文件11.patch,12.patch等。然後我編輯這些補丁(使用vim或perl,看起來最適合這項工作),刪除我不感興趣的文件的全部區塊,也可以修正名稱以及diff區塊標題中的重命名。

我會在新的git存儲庫上使用git am補丁。如果某些東西沒有出現,那麼我會重新啓動新的git存儲庫並重新編輯修補程序,然後重複git am。

我開始從10計數的原因是因爲我懶的前導0,預先準備的補丁程序並提交超過99我剛開始在99

+0

您可以使用'$(printf「%02d」$ c).patch'來預先設置前導零。 – jfs

+0

謝謝你提到這一點。從現在開始,我必須更頻繁地使用printf。 – holygeek

+0

謝謝......但這不是在逐個文件的基礎上工作嗎?正如我在我的問題中所說的,我知道如何在每個文件的基礎上做到這一點,但有太多的文件要實用。或者,也許我誤解了這裏發生的事情? –

6

這裏是你如何使用git過濾器 - 分支擺脫所有文件的,你不要想:

  1. 兩個舊名稱,新名稱重命名中的情況下,獲取您不希望出現在歷史上的文件名列表。例如把它們放在一個名爲toberemoved.txt

  2. 運行git過濾分支這樣的文件:

    $ git filter-branch --tree-filter "rm -f `cat toberemoved.txt`" branch1 branch2 ... 
    

下面是從git的過濾器分行的相關手冊頁:

--tree-filter <command> 
     This is the filter for rewriting the tree and its contents. The 
     argument is evaluated in shell with the working directory set to 
     the root of the checked out tree. The new tree is then used as-is 
     (new files are auto-added, disappeared files are auto-removed - 
     neither .gitignore files nor any other ignore rules HAVE ANY 
     EFFECT!). 

所以,只要確保你想刪除的文件列表都是相對於檢出樹的根。

更新:

若要獲取存在於過去,但不是在當前工作目錄,你可以運行下面的文件列表。請注意,你必須做進一步的努力,使「歷史重命名之前」的重命名的文件:

$ git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo Deleted: $f;fi;done 

即$ 6是受影響在--raw顯示提交的文件的名稱日誌模式。

如果你想知道發生了什麼([D]選擇,[R]註冊,[M]修飾等等)每個提交的每個文件,請參閱--diff-filter選項以git log。

也許其他人可以在如何查找被重新命名的情況下跟蹤文件的舊名稱。

+0

感謝您的新答案。越來越近我想,我沒有想過在過濾分支中使用'cat'。然而,我仍然沒有得到的是如何生成文件列表,因爲我只是想刪除工作目錄中的文件*而不是*(因此不容易列出)。還有什麼想法? –

+0

我已經更新了答案,以包含命令以獲取已刪除文件的列表。 – holygeek

+0

很好的答案。我從oneliner中刪除了'Deleted:'來獲取列表。但是當使用該列表時,出於某種原因,git filter-branch命令中的bash語法不起作用。因此,我使用'git filter-branch --tree-filter'cat $ HOME/toberemoved.txt | xargs -I {} rm -f {}「'(注意'toberemoved.txt'需要在目錄之外在版本控制下,這可能會導致''cat'toberemoved.txt'''語法的問題,但我沒有檢查。) – jaimedash

1

幫助到第二個答案:「也許其他人可以在如何找到重命名情況下跟蹤的文件的以前的名稱。

這將返回項目中的文件以及它們重命名的文件。

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done

您可以用它們來從列表中排除。

的整體解決方案是:

for file in `git ls-files`; do git log --follow --name-only --pretty=format: $file | sort -n -b | uniq | sed '/^\s*$/d'; done > current.txt

git log --raw |awk '/^:/ { if (! printed[$6]) { print $6; printed[$6] = 1 }}'|while read f;do if [ ! -f $f ]; then echo $f;fi;done | sort > hist.txt

diff --new-line-format="" --unchanged-line-format="" hist.txt current.txt > for_remove.txt

相關問題