我有一个包含许多文件的仓库,这些文件已不在工作目录中 - 已在存储库的月/年内添加和删除的文件。
我想创建一个文件,其中包含存储在提交历史中但不再需要的所有这些文件的列表,包括它们的位置..即
/web/scripts/index.php
/sql/tables.sql
...
然后我想要一个运行该文件的命令,并完全从提交历史中删除其中引用的文件,类似于git rm --cached
,但是对于文件列表。
答案 0 :(得分:3)
别名David Underhill's script,然后运行(谨慎):
$ git delete `git log --all --pretty=format: --name-only --diff-filter=D`
David Underhill的命令使用filter-branch
修改存储库的历史记录,删除给定文件路径的所有历史记录。
该脚本完整(source):
#!/bin/bash
set -o errexit
# Author: David Underhill
# Script to permanently delete files/folders from your git repository. To use
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2
if [ $# -eq 0 ]; then
exit 0
fi
# make sure we're at the root of git repo
if [ ! -d .git ]; then
echo "Error: must run this script from the root of a git repository"
exit 1
fi
# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD
# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all && git gc --aggressive --prune
将此脚本保存到硬盘驱动器上的某个位置(例如/path/to/deletion_script.sh
),并确保其可执行文件(chmod +x /path/to/deletion_script.sh
)。
$ git config --global alias.delete '!/path/to/deletion_script.sh'
获得sorted list of all deleted files:
$ git log --all --pretty=format: --name-only --diff-filter=D | sort -u
使用已删除文件的列表,只需挂钩git delete
即可处理列表中的每个文件:
$ git delete `git log --all --pretty=format: --name-only --diff-filter=D`
创建一个包含添加,重命名和删除的虚拟存储库:
mkdir test_repo
cd test_repo/
git init
echo "Dummy content" >> stays.txt
git add stays.txt && git commit -m "First file, will stay"
echo "Rename content" >> will_rename.txt
git add will_rename.txt && git commit -m "Going to rename"
echo "Delete this file" >> will_delete.txt
git add will_delete.txt && git commit -m "Delete this file"
git mv will_rename.txt renamed.txt && git commit -m "File renamed"
git rm will_delete.txt && git commit -m "File deleted"
检查历史:
$ git whatchanged --oneline
d768c58 File deleted
:100644 000000 7a4187c... 0000000... D will_delete.txt
96aadf0 File renamed
:000000 100644 0000000... 94a12c7... A renamed.txt
:100644 000000 94a12c7... 0000000... D will_rename.txt
3ba05fa Delete this file
:000000 100644 0000000... 7a4187c... A will_delete.txt
c88850a Going to rename
:000000 100644 0000000... 94a12c7... A will_rename.txt
6db6015 First file, will stay
:000000 100644 0000000... f3ae800... A stays.txt
删除旧文件:
$ git delete `git log --all --pretty=format: --name-only --diff-filter=D`
Rewrite 8c2009db5ac05b27cd065482da94dec717f5ef4a (8/9)rm 'will_delete.txt'
Rewrite e1348d588597f2f6dd63cade081e0fbdf8692c74 (9/9)
Ref 'refs/heads/master' was rewritten
Counting objects: 27, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (22/22), done.
Writing objects: 100% (27/27), done.
Total 27 (delta 12), reused 10 (delta 0)
立即检查存储库。请注意,删除操作已从历史记录中删除,并且重命名显示为最初以这种方式添加文件。
c800020 File renamed
:000000 100644 0000000... 94a12c7... A renamed.txt
0a729d7 First file, will stay
:000000 100644 0000000... f3ae800... A stays.txt
答案 1 :(得分:0)
添加@David的答案时,如果要格外小心,并确保不删除以后在历史记录中随后添加的任何文件,请使用以下命令块代替git delete $(git log --all --pretty=format: --name-only --diff-filter=D)
(考虑将其作为函数添加到.bashrc
中)
current=($(git ls-files))
tracked=($(git log --all --pretty=format: --name-only --diff-filter=D | xargs))
deleted=()
resurrected=()
for file in "${tracked[@]}"; do
if [[ " ${current[@]} " =~ " $file " ]]; then
resurrected+=("$file")
else
deleted+=("$file");
fi
done
echo "Deleted: ${deleted[@]}"
echo "Resurrected: ${resurrected[@]}"
git delete "${deleted[@]}"