【问题标题】:Change all done replacements to something else将所有已完成的替换更改为其他内容
【发布时间】:2018-10-17 20:17:20
【问题描述】:

在重写遗留应用程序时,我将foo 大量替换为bar 并混合了许多手动更改。一些替换必须手动撤消,并且原始代码中已经有许多其他bars。

现在,我看到每个 foo 替换为 bar 实际上应该是 baz

一个例子:

  • 旧文件:
    a staying "foo" and a replaced "foo" and a kept "bar"
  • 新文件
    a staying "foo" and a replaced "bar" and a kept "bar"
  • 通缉
    a staying "foo" and a replaced "baz" and a kept "bar"

想要的操作很简单:修复每次将foo 替换为barbaz。我想知道是否有使用git 或任何Linux 工具的简单方法。

重新制定

也许这个单句表述更清晰:

给定一个文件的两个版本,将baz 放在旧版本包含foo 而新版本包含bar 的每个位置。

更多详情

实际上有三个整个单词不同长度的单词替换比如

perl -pe 's/\babc\b/pqrs/gi; s/\bdefg\b/uvw/gi; s/\bhi\b/xyz/g'

【问题讨论】:

  • 您只想更改提交消息,而不是实际文件?
  • @ObsidianAge 不,我想更改文件。而且没有单一的提交,我实际上并不关心历史......在我得到一个编译版本之前,这是一个很大的混乱。假设我进行了错误的批量替换,我需要修复它,同时保留所有手动更改。
  • 致反对者:这个问题有什么不清楚的地方吗?
  • @dommmm 这就是我所做的:perl -pi -e 's!foo!bar!g。这就是我应该做的:perl -pi -e 's!foo!baz!g。在这期间,我做了很多手动更改。我现在不能简单地做perl -pi -e 's!bar!baz!g,因为不是每次出现都应该被替换。

标签: git diff


【解决方案1】:

您可以使用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 是修订版,从该修订版开始进行必须修复的错误替换
  • replacement_fix是一个字符串形式

    /orig_pattern/incorrect_replacement_str/correct_replacement_str/

效果

假设文件的工作副本位于 path 时进行比较 对其提交的修订版revision 包含替换结果 orig_patternincorrect_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"

【讨论】:

    【解决方案2】:

    替换 foo : grep -rl 'foo' 。 | xargs sed -i 's/foo/bar/g'

    替换 bar : grep -rl 'bar' 。 | xargs sed -i 's/bar/baz/g'

    【讨论】:

      猜你喜欢
      • 2014-06-21
      • 2014-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-26
      • 2014-07-05
      • 2013-09-01
      相关资源
      最近更新 更多