我想要一个带有交错线的差异,即“大块头”不超过一行。
例如代替
-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%
等等,但它没有改变任何东西(我什至不知道它是否与我的问题相关)。
我找到了解决我的问题的方法,而不是解决方法,我不改变
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
而且,正如我上面所说,它就像一个魅力。
内置的 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% 减去相似性。)
我很高兴我不是唯一想这样做的人。
以下通过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"
如果差异不需要是文本的,你可以使用 KDiff3:
这将提供比单行更大的粒度。
解决方法:转换
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"
基于这个答案