如何使用 git filter-branch 通过 blob SHA1 删除文件?
How to use git filter-branch to remove a file by blob SHA1?
我见过的大多数删除文件的 git 过滤器分支示例都是根据 文件名 删除文件。我不一定要那样做。相反,我已经确定了我要删除的文件的一些 blob(未提交)SHA1,无论它们在存储库中的什么位置。 (由于我们的回购历史,文件往往会在一堆文件中移动而不会改变。)
告诉 git filter-branch 根据文件的 blob SHA1 删除文件的最佳方法是什么?
您的任务是通过散列标识符从 Git 历史记录中删除 blob。您可能会发现使用 BFG 比使用 git-filter-branch
更快更容易,特别是使用 --strip-blobs-with-ids
标志:
-bi, --strip-blobs-with-ids <blob-ids-file>
...strip blobs with the specified Git object ids
仔细看usage instructions,核心部分就是这个:
$ java -jar bfg.jar --strip-blobs-with-ids <blob-ids-file> my-repo.git
请注意,<blob-ids-file>
文件应包含 Git object id,而不是 blob 内容的普通 SHA-1 哈希值。
对于给定的文件,您可以使用 git hash-object
:
计算 Git object id
$ git hash-object README.md
a63b49c2e93788cd71c81015818307c7b70963bf
您可以看到这个值与简单的 SHA-1 哈希不同:
$ sha1sum README.md
7b833f7b37550e2df719b57e8c4994c93a865aa9 README.md
...那是因为 Git object id 散列了一个 Git header,连同文件的内容,即使它确实使用相同的SHA-1 算法。
BFG 通常比 运行 git-filter-branch
至少快 10-50 倍,而且通常更易于使用。
完全披露:我是 BFG Repo-Cleaner 的作者。
filter-branch 版本在 index-filter 内部可能看起来像这样:
git ls-files -s |
sed -r '/ 02c97746d64fbfe13007a1ab4e9b9e4bbd99f42f /s/^100(644|755)/0/' |
git update-index --index-info
也就是说,读取 index-info 格式,找到感兴趣的 blob 并将模式设置为 0(将其标记为删除),然后将其写回索引。
正如@RobertTyley 在他的回答中指出的那样,您最好使用 BFG。但是,要按要求回答问题(如何使用 filter-branch
执行此操作):
不幸的是,没有很好的方法。您可以编写一个脚本来获取与索引中的 SHA 值关联的所有文件名。作为起点,如果您要删除哈希为 DEADC0DE
的文件
git rev-list -n 1 --objects HEAD |grep ^DEADC0DE |cut -c 42-
然后您将输入每一行(也许 xargs
?)作为
中的 <filename>
git rm --cached <filename>
并且您将使用该脚本作为您的 index-filter
值(因为将其用作树过滤器只会使本已缓慢的方法变得更慢)。
git filter branch --index-filter
将每次提交迭代地放入索引中,因此可以使用 git ls-files -s
.
从哈希中恢复文件名
我这样做是为了删除散列为 2d341f0223ff、6a4558fa76d1 和 4d0a90cba061 的 blob:
git filter-branch --force --index-filter "git ls-files -cdmo -s | grep ' 2d341f0223ff\| 6a4558fa76d1\| 4d0a90cba061' | awk '{print }' | xargs git rm --cached --ignore-unmatch 656565randomstring546464" --prune-empty --tag-name-filter cat -- --all
随机字符串是为了避免git rm
在grep
returns不匹配时报错。
我见过的大多数删除文件的 git 过滤器分支示例都是根据 文件名 删除文件。我不一定要那样做。相反,我已经确定了我要删除的文件的一些 blob(未提交)SHA1,无论它们在存储库中的什么位置。 (由于我们的回购历史,文件往往会在一堆文件中移动而不会改变。)
告诉 git filter-branch 根据文件的 blob SHA1 删除文件的最佳方法是什么?
您的任务是通过散列标识符从 Git 历史记录中删除 blob。您可能会发现使用 BFG 比使用 git-filter-branch
更快更容易,特别是使用 --strip-blobs-with-ids
标志:
-bi, --strip-blobs-with-ids
<blob-ids-file>
...strip blobs with the specified Git object ids
仔细看usage instructions,核心部分就是这个:
$ java -jar bfg.jar --strip-blobs-with-ids <blob-ids-file> my-repo.git
请注意,<blob-ids-file>
文件应包含 Git object id,而不是 blob 内容的普通 SHA-1 哈希值。
对于给定的文件,您可以使用 git hash-object
:
$ git hash-object README.md
a63b49c2e93788cd71c81015818307c7b70963bf
您可以看到这个值与简单的 SHA-1 哈希不同:
$ sha1sum README.md
7b833f7b37550e2df719b57e8c4994c93a865aa9 README.md
...那是因为 Git object id 散列了一个 Git header,连同文件的内容,即使它确实使用相同的SHA-1 算法。
BFG 通常比 运行 git-filter-branch
至少快 10-50 倍,而且通常更易于使用。
完全披露:我是 BFG Repo-Cleaner 的作者。
filter-branch 版本在 index-filter 内部可能看起来像这样:
git ls-files -s |
sed -r '/ 02c97746d64fbfe13007a1ab4e9b9e4bbd99f42f /s/^100(644|755)/0/' |
git update-index --index-info
也就是说,读取 index-info 格式,找到感兴趣的 blob 并将模式设置为 0(将其标记为删除),然后将其写回索引。
正如@RobertTyley 在他的回答中指出的那样,您最好使用 BFG。但是,要按要求回答问题(如何使用 filter-branch
执行此操作):
不幸的是,没有很好的方法。您可以编写一个脚本来获取与索引中的 SHA 值关联的所有文件名。作为起点,如果您要删除哈希为 DEADC0DE
的文件git rev-list -n 1 --objects HEAD |grep ^DEADC0DE |cut -c 42-
然后您将输入每一行(也许 xargs
?)作为
<filename>
git rm --cached <filename>
并且您将使用该脚本作为您的 index-filter
值(因为将其用作树过滤器只会使本已缓慢的方法变得更慢)。
git filter branch --index-filter
将每次提交迭代地放入索引中,因此可以使用 git ls-files -s
.
我这样做是为了删除散列为 2d341f0223ff、6a4558fa76d1 和 4d0a90cba061 的 blob:
git filter-branch --force --index-filter "git ls-files -cdmo -s | grep ' 2d341f0223ff\| 6a4558fa76d1\| 4d0a90cba061' | awk '{print }' | xargs git rm --cached --ignore-unmatch 656565randomstring546464" --prune-empty --tag-name-filter cat -- --all
随机字符串是为了避免git rm
在grep
returns不匹配时报错。