带有交错线的 git diff

问题描述 投票:0回答:5

我想要一个带有交错线的差异,即“大块头”不超过一行。

例如代替

-t1 = "Christmas 2013"
-t2 = "Easter 2013"
-t3 = "Thanksgiving 2013"
+t1 = "Christmas 2014"
+t2 = "Easter 2014"
+t3 = "Thanksgiving 2014"

我想要这个:

-t1 = "Christmas 2013"
+t1 = "Christmas 2014"
-t2 = "Easter 2013"
+t2 = "Easter 2014"
-t3 = "Thanksgiving 2013"
+t3 = "Thanksgiving 2014"

到目前为止我有

git diff -U0 --ignore-space-at-eol before after holidays.ini

我尝试设置

--break-rewrites=0%/0%
--break-rewrites=100%/0%
等等,但它没有改变任何东西(我什至不知道它是否与我的问题相关)。

git diff git-diff
5个回答
3
投票

我找到了解决我的问题的方法,而不是解决方法,我不改变

diff
的行为。使用 AWK,可以处理其输出以将具有多行的 hunks 切割成一行的切片:

diffungroup

awk -F ',|c' ' # process lines as "3,4c3,4" and following lines
  /[0-9]+,[0-9]+c[0-9]+,[0-9]+/ {
    ss = $1; se = $2; ds = $3; de = $4; 
    for (i = ss; i <= se; i++) {
      getline
      a[i] = $0
    }
    getline # skip "---"    
    i = ss
    for (j = ds; j <= de; j++) {
      print i "c" j
      print a[i++]
      print "---"
      getline
      print $0
    } 
    next 
  }
  { print }
' "$@"

它将

diff
的输出转换为:

1,2c1,2
< Salve<br/>
< Quomodo te habes?<br/>
---
> Salvete<br/>
> Quomodo vos habetis?<br/>

进入:

1c1
< Salve<br/>
---
> Salvete<br/>
2c2
< Quomodo te habes?<br/>
---
> Quomodo vos habetis?<br/>

在上面问题中解释的上下文中,我通过以下方式调用它:

diff short.html.orig short.html > short.diff
./diffungroup short.diff > long.diff
patch -z .orig long.html long.diff

而且,正如我上面所说,它就像一个魅力。


1
投票

内置的 diff 算法都不会以这种方式运行。

我很好奇你想看到什么,例如,改变是添加一行并替换另外两行,这样(拿你的例子)你就会有这样的东西:

-t1 = "Christmas 2013"
+t1 = "Christmas 2014"
+t2 = "Easter 2014"
-t3 = "Thanksgiving 2013"
+t3 = "Thanksgiving 2014"

在这里,对于

t2
,没有什么可以删除的。

无论如何,我相信您最好的选择可能是对

git diff -U0
的输出进行后处理。

如果你在 Unix-ish 系统上,你也可以使用原始的、非统一的 diff,例如:

$ diff --git a/like_min.py b/like_min.py
index 05b9a4d..1c90084 100644
--- a/like_min.py
+++ b/like_min.py
@@ -1 +1 @@
-def like_min(iterable, key=None):
+def like_min(iterable, key=None): # comment
@@ -9 +9 @@ def like_min(iterable, key=None):
-    for candidate in it:
+    for candidate in it: # another comment
$ git show HEAD:like_min.py | diff - like_min.py
1c1
< def like_min(iterable, key=None):
---
> def like_min(iterable, key=None): # comment
9c9
<     for candidate in it:
---
>     for candidate in it: # another comment

这可能更容易进行后处理(取决于许多细节)。特别是每个更改都以行号和字母代码开头(

a
add、
c
hange、
d
elete),因此无需弄清楚某些内容是纯添加还是纯删除,而不是更改你想一次分成一行。如果 new 行数不匹配,您仍然可能需要将“更改”变成“更改后添加或删除”:

$ git show HEAD:like_min.py | diff - like_min.py
1c1,2
< def like_min(iterable, key=None):
---
> def like_min(iterable, key=None): # comment
> def like_min(iterable, key=None): # comment
9c10
<     for candidate in it:
---
>     for candidate in it: # another comment

此外,“旧差异”可能有不同的(而不是所需的)空白忽略选项。


摆弄

--break-rewrites
与您想要的正交:它只是改变了 git 认为文件“完全重写”的点,因此将更改显示为“删除整个以前的文件内容,插入全新内容”。

根据文档,默认断点是

-B50%/60%
,它指定不超过 60% 的文件可以“重写”,或者等效地,“至少 40% 的文件仍然匹配”。您可能想减少它,但可能不想增加它。 (顺便说一下,我似乎无法将其设置为 0%;将其设置为
1%
会使大多数更改变成完全重写,但是小的更改,比如只更改文件的一行,仍然显示为小更改而不是全部-file-rewrites。这可能是因为相似度指数不是纯粹基于一次一行的更改,还包括行内匹配。)

(第一个数字——

-B50%/60%
中的 50%——是用于重命名检测的相似性指数值,假设启用了重命名检测。将这两个数字视为“相似性和相异性指数”值:相似性指数是“如何close 是文件 1 到文件 2”,差异性只是 100% 减去相似性。)


1
投票

我很高兴我不是唯一想这样做的人。

以下通过paste在相邻行上显示新旧,并使用

uniq
作为世界上最差的差异:

git show HEAD:./holidays.ini | paste -d '\n' - holidays.ini | uniq -u

"Christmas 2013"
"Christmas 2014"
"Easter 2013"
"Easter 2014"
"Thanksgiving 2013"
"Thanksgiving 2014"

0
投票

如果差异不需要是文本的,你可以使用 KDiff3:

KDiff3 screenshot

这将提供比单行更大的粒度。


0
投票

解决方法:转换

diff -y

的输出
function difflines() {
  # compare files line-by-line
  # https://stackoverflow.com/a/71665866/10440128
  local W=1000 # depends on input width
  local c=$(((W+1)/2)) # center. +1 to round up
  local ca=$((c-2))
  local cb=$((c+2))
  local color=true
  local red=''
  local green=''
  local reset=''
  if $color; then
    red=$'\e[31m'
    green=$'\e[32m'
    reset=$'\e[0m'
  fi
  diff -y -t -W $W "$1" "$2" | while read -r L
  do
    a="${L:0:$ca}"
    a="$(echo "$a" | sed -E 's/ +$//')"
    b="${L:$cb}"
    echo "$red-$a$reset"
    echo "$green+$b$reset"
    echo
  done
}

例子:

cat >file1 <<EOF
t1 = "Christmas 2013"
t2 = "Easter 2013"
t3 = "Thanksgiving 2013"
EOF

cat >file2 <<EOF
t1 = "Christmas 2014"
t2 = "Easter 2014"
t3 = "Thanksgiving 2014"
EOF

difflines file1 file2

输出

-t1 = "Christmas 2013"</span>
+t1 = "Christmas 2014"

-t2 = "Easter 2013"
+t2 = "Easter 2014"

-t3 = "Thanksgiving 2013"
+t3 = "Thanksgiving 2014"

基于这个答案

© www.soinside.com 2019 - 2024. All rights reserved.