如何在没有单独相同行的情况下生成差异

如何在没有单独相同行的情况下生成差异

假设我从头开始重写了一个 C 函数。经常会发生某些行前后完全相同的情况,特别是空行和右大括号。当我创建统一的差异(使用git diff或普通 GNU diff -u)时,这些相同的行将大块分开,使审阅者更难阅读补丁。 Diff 想要产生最小差异的野心有时会牺牲可读性,这不是我想要的。有没有办法让 diff 牺牲最小性来让大块头保持在一起?

示例:考虑这个,由 diff 生成:


--- A   2018-10-01 09:37:37.606642955 +0200
+++ B   2018-10-01 09:37:40.405675295 +0200
@@ -1,6 +1,9 @@
 int fib(int n) {
-  if (n <= 1) {
-    return n;
+  int i, t1 = 0, t2 = 1;
+  for (i = 0; i < n; ++i) {
+    int next = t1 + t2;
+    t1 = t2;
+    t2 = next;
   }
-  return fib(n-1) + fib(n-2);
+  return t1;
 }
在我看来,以下等效补丁会更容易阅读,但只需多一行:

--- A   2018-10-01 09:37:37.606642955 +0200
+++ B   2018-10-01 09:37:40.405675295 +0200
@@ -1,6 +1,9 @@
 int fib(int n) {
-  if (n <= 1) {
-    return n;
-  }
-  return fib(n-1) + fib(n-2);
+  int i, t1 = 0, t2 = 1;
+  for (i = 0; i < n; ++i) {
+    int next = t1 + t2;
+    t1 = t2;
+    t2 = next;
+  }
+  return t1;
 }

因此,一种可能的启发是“如果存在相同的行,并且在该行之前和之后都添加和删除了行,则考虑更改相同的行”。我当然可以创建自己的脚本,在现有补丁上应用此规则,但是是否有现有工具可以解决我的问题?

答案1

您可以通过将diff -u输出传送到以下位置来实现您的方法:

perl -0777 -pe '1 while s{^-.*\n\K((?:\+.*\n)+) ((.*\n)(?:-.*\n)+)}
                         {-$2$1+$3}mg'

现在我不相信不显示孤独的共同线总是有助于提高可读性。比较一下例如:

--- A   2018-10-01 09:37:37.606642955 +0200
+++ B   2018-10-01 09:37:40.405675295 +0200
@@ -1,8 +1,11 @@
 int fib(int n) {
-  if (n <= 1) {
-    return n;
+  int i, t1 = 0, t2 = 1;
+  for (i = 0; i < n; ++i) {
+    int next = t1 + t2;
+    t1 = t2;
+    t2 = next;
   }
-  /* assinging foo */
+  /* assigning foo */
   foo = (bar ? bar : complicated_stuff(*a.asd.qwe|(FLAG1|FLAG2)));
-  return fib(n-1) + fib(n-2);
+  return t1;

perl上面有代码的输出:

--- A   2018-10-01 09:37:37.606642955 +0200
+++ B   2018-10-01 09:37:40.405675295 +0200
@@ -1,8 +1,11 @@
 int fib(int n) {
-  if (n <= 1) {
-    return n;
-  }
-  /* assinging foo */
-  foo = (bar ? bar : complicated_stuff(*a.asd.qwe|(FLAG1|FLAG2)));
-  return fib(n-1) + fib(n-2);
+  int i, t1 = 0, t2 = 1;
+  for (i = 0; i < n; ++i) {
+    int next = t1 + t2;
+    t1 = t2;
+    t2 = next;
+  }
+  /* assigning foo */
+  foo = (bar ? bar : complicated_stuff(*a.asd.qwe|(FLAG1|FLAG2)));
+  return t1;

我发现它更有用,它diff告诉我那条复杂的线没有改变。在扩展版本中,您可能会想寻找两者之间的差异。

您可以将 替换为 ,((.*\n)((.{0,20}\n)仅考虑短的孤独的公共行(或(((?:\h*\H){0,10}\h*\n)仅考虑非空白的数量)。

答案2

以下脚本通过检测差异中的“几乎完全不同”的序列并将它们视为完全不同来改善我的情况。寻找更好的解决方案。

#!/usr/bin/python
import sys
(mbefore, pbefore, mid, mafter) = ([], [], [], [])
def flush():
    for x in (mbefore, pbefore, mid, mafter):
        sys.stdout.write(''.join(x))
        del x[:]

for line in sys.stdin:
    if line[0] == '-':
        if mid:
            mafter.append(line)
        else:
            flush()
            mbefore.append(line)
    elif line[0] == '+':
        if mafter:
            mbefore.append('-' + mid[0][1:])
            pbefore.append('+' + mid[0][1:])
            mbefore += mafter
            pbefore.append(line)
            del mafter[:]
            del mid[:]
        elif not mid and mbefore:
            pbefore.append(line)
        else:
            flush()
            sys.stdout.write(line)
    elif line[0] == ' ':
        if pbefore and not mid:
            mid.append(line)
        else:
            flush()
            sys.stdout.write(line)
    else:
        flush()
        sys.stdout.write(line)
flush()

相关内容