您可以使用git diff 的--word-diff=porcelain 模式(以及传递给-U 选项的足够大的值,以保留更改之间的所有上下文)并使用足够简单的方法处理其输出将纠正错误替换的脚本。
--word-diff[=<mode>] 显示单词差异,使用<mode> 分隔更改的单词。默认情况下,单词由空格分隔;
请参阅下面的--word-diff-regex。 <mode> 默认为 plain,并且
必须是以下之一:
- ...
-
porcelain:使用一种特殊的基于行的格式供脚本使用。添加/删除/未更改的运行以通常的方式打印
统一差异格式,以 +/-/` ` 字符开头
行的开头并延伸到行的末尾。换行符
在输入中由波浪线 ~ 单独表示。
您将在下面找到基于sed 的上述方法的原型实现。
用法:
fix_wrong_replacements path revision replacement_fix
在哪里
效果:
假设文件的工作副本位于 path 时进行比较
对其提交的修订版revision 包含替换结果
orig_pattern 和 incorrect_replacement_str 的某些实例,
识别这些替换并将它们更改为 correct_replacement_str。
示例:
# In last two commits (and, maybe, in the working copy) some "int"s
# were incorrectly changed to "unsigned", now change those to "long"
$myname main.c HEAD~2 /int/unsigned/long/
# In the working copy of somefile.txt all "abc" case-insensitive words
# were changed to "pqrs", now change them to "xyz"
$myname somefile.txt HEAD '/[aA][bB][cC]/pqrs/xyz/'
已知限制/问题:
它适用于单个文件。要修复提交、提交范围或本地更改中的所有错误替换,必须识别已更改文件的列表并在循环中为所有这些文件调用此脚本。
如果在原始(错误)替换期间使用了不区分大小写的模式,则 replacement_fix 参数的 orig_pattern 部分必须使用 [aA]、@987654350 @等,每个字母的正则表达式原子。
不处理紧邻其他更改的替换。
有时可能会添加多余的空行(因为git diff --word-diff 的输出略有不一致)
fix_wrong_replacements:
#!/usr/bin/env bash
myname="$(basename "$0")"
if [ $# -ne 3 ]
then
cat<<END
Usage:
$myname <path> <revision> <replacement_fix>
where
- <path> is the (relative) path of the file in the working tree
- <revision> is the revision since which the wrong replacements that
must be fixed were made
- <replacement_fix> is a string of the form
/orig_pattern/incorrect_replacement_str/correct_replacement_str/
Effects:
Assuming that the working copy of the file at <path> when compared
to its committed revision <revision> contains results of replacing
certain instances of <orig_pattern> with <incorrect_replacement_str>,
identifies those replacements and changes them to <correct_replacement_str>.
Examples:
# In last two commits (and, maybe, in the working copy) some "int"s
# were incorrectly changed to "unsigned", now change those to "long"
$myname main.c HEAD~2 /int/unsigned/long/
# In the working copy of somefile.txt all "abc" case-insensitive words
# were changed to "pqrs", now change them to "xyz"
$myname somefile.txt HEAD '/[aA][bB][cC]/pqrs/xyz/'
END
exit 1
fi
file="$1"
revision="$2"
s=(${3//// })
orig_pattern="${s[0]}"
incorrect_replacement="${s[1]}"
correct_replacement="${s[2]}"
pat="-$orig_pattern\n+$incorrect_replacement"
git_word_diff()
{
git diff -U100000 \
--word-diff=porcelain \
--word-diff-regex='[[:alpha:]][[:alnum:]]*' \
"$@"
}
word_diff_file="$(mktemp)"
trap "rm $word_diff_file" EXIT
git_word_diff "$revision" -- "$file" > "$word_diff_file"
sed -n -e '
1,5 d;
/^-/ N;
/\n~$/ d;
/\n[- ]/ D;
/^'"$pat"'$/ {x;G;s/\n'"$pat"'$/'"$correct_replacement"'/;x;d;};
/^-.*\n+/ {s/^-.*\n+//;H;x;s/\n//;x;d;};
/^~$/ {s/.*//;x;p;d;};
{s/^.//;H;x;s/\n//;x;};
' "$word_diff_file" > "$file"