我看过几篇关于如何从所有git历史中删除单个文件的文章和问题。示例:如何从Git存储库的提交历史中删除一个大文件?
我想做的是删除所有文件,这些文件当前不在主分支的头部。
我的用例是将一个较小的存储库(称为small
(与一个单片存储库(也称为monolith
(分开。我想在创建small
时保留git历史记录,但只保留相关的git历史。
首先,我在GitHub上创建了一个新的存储库small
。然后,在我的笔记本电脑上,我将它作为一个名为origin-small
的远程添加到我的本地monolith
存储库中,并将monolith
的主分支的当前状态推送到origin-small
。
然后,我从monolith
中删除了远程origin-small
,更改了目录,并从GitHub中克隆了small
。瞧,我有一份我的原始存储库monolith
的副本,里面有它的完整历史。
但是,small
的历史记录中有大量文件不再相关,它们正在膨胀回购。
我想做的是:
- 从
small
中删除所有不必要的文件 - 运行一个命令来清除我刚刚删除的文件的整个git历史记录
有没有一种方法可以用一个命令来实现这一点?还是需要为要删除的每个文件/目录运行git filter-branch
一次?
我最终使用了git-filter-repo
警告:此方法无法更新远程设备上的标记(如果有的话(
-
安装
git-filter-repo
。brew install git-filter-repo
-
以镜像形式克隆您想要的回购。
git clone --mirror <my-repo-url>
-
输入repo目录。
cd <my-repo-name>
-
分析repo以识别历史记录中但已不存在的所有文件。
git filter-repo --analyze
-
在
analysis
输出目录中,将有一个名为path-deleted-sizes.txt
的文件,该文件包含一个列表,列出了在某个时刻提交的、后来被删除的、但仍存在于git历史中的所有文件。创建一个没有标题和其他列的新文件。
tail +3 ./filter-repo/analysis/path-deleted-sizes.txt | tr -s ' ' | cut -d ' ' -f 5- > ./filter-repo/analysis/path-deleted.txt
-
清除所有不再存在的文件的git历史记录。这还将清理脏提交,删除空提交,并为您重新压缩所有内容。
git filter-repo --invert-paths --paths-from-file ./filter-repo/analysis/path-deleted.txt
-
清理
./filter-repo
目录,否则您将无法推送您的更改。rm -rf ./filter-repo
-
强制将所有引用推到原点。它会强制推送,即使命令没有指示它。此外,它会更新远程上的所有分支,这很方便。如果你在GitHub/Bitbucket等中的一些分支上启用了分支保护。,那么你需要允许用力推。如果您发现某些refs无法被强制推送,您可以随时重新运行此命令。
git push
列出旧提交中存在的所有文件。
git rev-list HEAD | sed 1d | xargs -i git ls-tree -r {} --name-only | sort -u
列出头中存在的所有文件。
git ls-tree -r HEAD --name-only | sort -u
获取头中不存在的文件(引用(。
files=$(comm -23 <(git rev-list HEAD | sed 1d | xargs -i git ls-tree -r {} --name-only | sort -u) <(git ls-tree -r HEAD --name-only | sort -u))
将不可见的字符(我猜是新行(替换为空格,否则会导致git filter-branch
中出现错误。
lostfiles=$(echo $files | sed -e 's/s/ /g')
从历史记录中删除lostfiles
:
git filter-branch -f --tree-filter "rm -rf ${lostfiles}" --prune-emtpy
可以将它们组合为一个命令,但我不知道是否会有任何性能问题,所以我更喜欢单独的命令。