借鉴@larsks的想法,我使用以下命令实现了目标。我在这里留下它作为参考。
- 创建一个空分支[1]:
git switch --orphan new_history
2. 将主分支重新基于此,对每个提交执行 pre-commit 钩子:
git rebase --root main --exec .git/hooks/pre-commit -X theirs
请注意,我使用了
theirs
合并策略,以便在冲突的情况下,使用主分支的版本([
2],[
3])。
3.之后,所有提交的提交日期都设置为今天。为了解决这个问题,我运行了([
4]):
git filter-branch --env-filter 'export GIT_COMMITTER_DATE="$GIT_AUTHOR_DATE"'
这是我的pre-commit
脚本:
#!/bin/sh
set -x
IFS=$'\n'
files=$(git diff-tree --no-commit-id --name-status -r HEAD | grep -v ^D | cut -c3-)
if [ "$files" != "" ]
then
for f in $files
do
if [[ "$f" =~ [.]md$ ]]
then
if [ "$(tail -c1 $f)" != '\n' ]
then
echo >> $f
fi
if grep -q "[[:blank:]]$" $f
then
sed -i "" -e $'s/[ \t]*$//g' $f
fi
python3 ~/bin/remove_empty_lines_md.py $f $f
fi
done
fi
unset IFS
git add -A
git commit --amend --no-edit --no-verify
请注意,末尾的
--no-verify
很重要(它跳过了钩子),否则会出现无限循环。
为了完整起见,这里是
remove_empty_lines_md.py
脚本:
def remove_empty_lines(text):
r"""
>>> text = "\n\n- test\n - test2\n\n- test3\n\n\n cointinue\n\n- test 4\n\n- test 5\n - test 6\n continue\n continue\n\n\n\n test7\n\n\n tset8\n\n\n- test 9\n\n\n- final\n\n\n"
>>> remove_empty_lines(text)
'- test\n - test2\n- test3\n\n\n cointinue\n- test 4\n- test 5\n - test 6\n continue\n continue\n\n\n\n test7\n\n\n tset8\n- test 9\n- final\n'
"""
new_lines = []
buffer = []
for i, line in enumerate(text.split('\n')):
if not line.strip():
buffer.append(line)
else:
if buffer:
if line.lstrip() and line.lstrip()[0] != '-':
new_lines.extend(buffer)
buffer = []
new_lines.append(line)
return '\n'.join(new_lines) + '\n'
if __name__ == '__main__':
import doctest
import sys
doctest.testmod()
filename_in, filename_out = sys.argv[1], sys.argv[2]
with open(filename_in) as fin:
text = fin.read()
with open(filename_out, 'w') as fout:
fout.write(remove_empty_lines(text))
.git-blame-ignore-revs
文件中,以从git blame
输出中排除这些修改。(更改将看起来像钩子应用后,但没有对其的引用;日期显示自旧提交,因此与您的期望相匹配) - SUTerliakov