如何从 GIT 存储库历史记录中删除所有文件,路径在文件名中带有冒号:?

How to remove all files from GIT repo history with path having colon : in filename?

提问人:klor 提问时间:1/14/2023 最后编辑:Christopher Mooreklor 更新时间:1/20/2023 访问量:331

问:

我有 ISCSI 节点文件名和冒号存储在 Debian 10 Linux 上的 GIT 存储库中。

例:

'iscsi/nodes/iqn.2000-01.com.synology:NAS01-DS916.nas/ff11::111:11ff:ff1f:1ff1,3260,1/default'
'iscsi/send_targets/1.2.3.4,3260/iqn.2000-01.com.synology:NAS01-DS916.nas,ff11::111:11ff:ff1f:1ff1,3260,1,default'

但是在 Windows 上签出失败,因为冒号是 Windows 文件名中的无效字符。

我在 Windows 结帐时收到以下 GIT 错误:

error: invalid path 'iscsi/nodes/iqn.2000-01.com.synology:NAS01-DS916.nas/ff11::111:11ff:ff1f:1ff1,3260,1/default'
...
error: invalid path 'iscsi/send_targets/1.2.3.4,3260/iqn.2000-01.com.synology:NAS01-DS916.nas,ff11::111:11ff:ff1f:1ff1,3260,1,default'

问题:

1)如何列出所有带有冒号的路径:在完整的GIT存储库历史记录中?

2)如何从GIT存储库历史记录中删除所有文件,其路径至少有一个冒号:在文件名中?

解决方案 1) :

作品1:

git log --all --name-only -m --pretty= -- '*:*' | sort -u

Works2(仅适用于命名的存储库主节点):

git ls-tree -r master --name-only | grep ":"

Works3:最后我用它来列出文件名中带有冒号的文件:

git log --format="reference" --name-status --diff-filter=A "*:*" >/opt/git_repo_files_w_colons.txt

UPDATE1 for 2):

我得到了

Aborting: Refusing to destructively overwrite repo history since
this does not look like a fresh clone.
  (expected freshly packed repo)
Note: when cloning local repositories, you need to pass
      --no-local to git clone to avoid this issue.
Please operate on a fresh clone instead.  If you want to proceed
anyway, use --force.

执行时

git filter-repo --invert-paths --path-match "*:*"

UPDATE2 for 2) :

克隆存储库的副本:

git clone --no-local /source/repo/path/ /target/path/to/repo/clone/
# Cloning into '/target/path/to/repo/clone'...
# remote: Enumerating objects: 9534, done.
# remote: Counting objects: 100% (9534/9534), done.
# remote: Compressing objects: 100% (4776/4776), done.
# remote: Total 9534 (delta 4216), reused 8042 (delta 3136), pack-reused 0
# Receiving objects: 100% (9534/9534), 7.40 MiB | 17.08 MiB/s, done.
# Resolving deltas: 100% (4216/4216), done.

从存储库历史记录中删除带有冒号的文件:

git filter-repo --invert-paths --path-match "*:*"
# Parsed 591 commits
# New history written in 0.47 seconds; now repacking/cleaning...
# Repacking your repo and cleaning out old unneeded objects
# HEAD is now at 501102d daily autocommit
# Enumerating objects: 9534, done.
# Counting objects: 100% (9534/9534), done.
# Delta compression using up to 8 threads
# Compressing objects: 100% (3696/3696), done.
# Writing objects: 100% (9534/9534), done.
# Total 9534 (delta 4216), reused 9534 (delta 4216), pack-reused 0
# Completely finished after 1.33 seconds.

检查仍然显示带冒号的文件名:

git log --format="reference" --name-status --diff-filter=A "*:*"
# A    iscsi/nodes/iqn.2000-01.com.synology:NAS01-DS916.nas/ff11::111:11ff:ff1f:1ff1,3260,1/default
# ...

不幸的是,似乎执行了 filter-repo,但日志仍然列出了带有冒号的文件名:-(

git 无效字符 git-history

评论

0赞 nofinator 1/14/2023
您在 Windows 中运行的 git checkout 命令是什么?也许有一种方法可以改变这一点,因此它适用于冒号。
0赞 klor 1/14/2023
我使用 Git 扩展客户端,因此无法更改 git 命令。
1赞 Nusrat Nuriyev 6/8/2023
只是提醒所有人,Windows 中禁止使用哪些符号和文件名,stackoverflow.com/questions/1976007/......我最终陷入了这种情况,因为我使用 Web 界面在 GitHUB 中添加了一个文件,它允许我添加带有冒号:)的文件但后来很痛苦,无法在 Linux 中修复它,(终端没有启动)感谢上帝我也有 MacOS。

答:

0赞 nofinator 1/14/2023 #1
  1. 如何列出所有带有冒号的路径:在完整的 GIT 存储库历史记录中?

你可能在这里不走运。有关此问题和 Windows 中的解决方法的更多讨论,请点击此处

  1. 如何从 GIT 存储库历史记录中删除路径至少有一个冒号 : 的文件名?

如果您与他人一起开发,请小心使用这种方法。当在源中修改现有分支时,当其他人试图将其拉下时,会引起很多冲突。

但是,如果您可以继续,可以在此处尝试一种方法。

评论

0赞 klor 1/14/2023
感谢您的回答,但是:链接 #1 没有提供列出具有冒号链接 #2 的路径的解决方案,也没有提供删除文件名带冒号的文件的解决方案。
1赞 VonC 1/15/2023 #2

链接 #1 未提供列出具有 colo 的路径的解决方案

检查:

git ls-tree -r master --name-only | grep ":"

但建议的方法是重置所有没有“:”的文件,并删除其余的文件:

git ls-tree -r master --name-only | grep -v ":" | xargs git reset HEAD
git commit -m "deleting all files with a colon in the name"
git restore -- .

OP klor 报告以 git log pretty 格式 “” 列出这些文件(即):reference<abbrev-hash> (<title-line>, <short-author-date>)

git log --format="reference" --name-status --diff-filter=A "*:*" >/opt/git_etc_repo_files_w_colons.txt

OP建议

# Clone repository, to be executed on a safe repo:
git clone --no-local /source/repo/path/ /target/path/to/repo/clone/
# Cloning into '/target/path/to/repo/clone'...
# remote: Enumerating objects: 9534, done.
# remote: Counting objects: 100% (9534/9534), done.
# remote: Compressing objects: 100% (4776/4776), done.
# remote: Total 9534 (delta 4215), reused 8043 (delta 3136), pack-reused 0
# Receiving objects: 100% (9534/9534), 7.41 MiB | 16.78 MiB/s, done.
# Resolving deltas: 100% (4215/4215), done.

cd /target/path/to/repo/clone/

# List the files with colon from repo history into a list file:
git log --all --name-only -m --pretty= -- '*:*' | sort -u >/opt/git_repo_files_w_colons.txt

# Remove the files with colon from repo history:
git filter-repo --invert-paths --paths-from-file /opt/git_repo_files_w_colons.txt
# Parsed 591 commits
# New history written in 0.74 seconds; now repacking/cleaning...
# Repacking your repo and cleaning out old unneeded objects
# HEAD is now at e5fdf93 daily autocommit
# Enumerating objects: 9347, done.
# Counting objects: 100% (9347/9347), done.
# Delta compression using up to 8 threads
# Compressing objects: 100% (3696/3696), done.
# Writing objects: 100% (9347/9347), done.
# Total 9347 (delta 4078), reused 9345 (delta 4076), pack-reused 0
# Completely finished after 1.59 seconds.

# List files with colon to check result:
git log --format="reference" --name-status --diff-filter=A "*:*"
# Empty result, so git filter-repo was successful, filenames with colon were removed!

评论

0赞 klor 1/16/2023
仅列出分支中带有冒号的文件名,而不是整个历史记录。git ls-tree -r master --name-only | grep ":"
0赞 VonC 1/16/2023
@klor 是的,我专注于克隆(使用默认分支)成功所需的最小 maml 修复。
0赞 klor 1/16/2023
我执行了,但我得到了git ls-tree -r live_master --name-only | grep -v ":" | xargs git reset HEAD error: unknown switch '/'
0赞 VonC 1/16/2023
@klor 你是在 Windows 还是 Debian 服务器上执行它?使用哪个版本的 Git?在哪个壳里?
0赞 klor 1/16/2023
在 Debian 服务器上执行。使用 Putty 通过 SSH 到 Debian 服务器、Bash shell、Git v2.28。
3赞 jthill 1/15/2023 #3

更好的方法可能是不在 Windows 上签出这些文件,查看稀疏的签出工具,或者用 Windows 可以处理的字符重命名它们,而是按照要求回答问题:

  1. 如何列出所有带有冒号的路径:在完整的 GIT 存储库历史记录中?
git log --all --name-only -m --pretty= -- '*:*' | sort -u
  1. 如何从 GIT 存储库历史记录中删除路径至少有一个冒号 : 的文件名?
git filter-branch --prune-empty --index-filter '
        git ls-files "*:*" | git update-index --remove --stdin
' -- --all

这将从您必须更改的第一个提交开始重写您的整个历史记录。在临时克隆中执行此操作。

评论

2赞 VonC 1/15/2023
确实是另一个好方法。您还可以列出这些文件并将它们传递给 git filter-repo --invert-path 命令。
0赞 klor 1/16/2023
结果显示:git filter-branch --prune-empty --index-filter ' git ls-files "*:*" | git update-index --remove --stdin ' -- --alluse an alternative filtering tool such as 'git filter-repo' instead
0赞 klor 1/16/2023
否则就行了。列出带有冒号的文件名结果为空,因此 filter-branch 成功。git filter-branch ...
0赞 klor 1/16/2023
@vonc:我更喜欢这个解决方案,但它会导致一个错误。git filter-repo --invert-path commandAborting: Refusing to destructively overwrite repo history since this does not look like a fresh clone. (expected freshly packed repo)
1赞 VonC 1/16/2023
@klor 是的,仅适用于新的克隆:这样,您就不会触及当前工作的本地存储库,这意味着如果“破坏”了任何内容,您可以删除本地克隆,重新克隆并重试该命令。git filter-repofilter-repo