您能否向 svn diff 添加注释/类似指责信息,以便每个更改的行都包括哪个用户和修订版本更改了该行?
例如,比较修订版本 8-10 的 annotate-diff 可能会输出类似以下内容:
9 user1 - some line that user1 deleted in revision 9
10 user2 + some line that user2 added in revision 10
上下文以及周围的未发生改变的线条可能会被包括在内,也可能会不包括,这并不重要。
这不仅仅是“快速”编写一个结合 svn diff 和 svn annotate 输出的 shell 脚本的问题。例如,annotate 永远不会显示谁删除了一行。这也不是对过去的修订进行注释的问题:我们不关心最初是谁添加了被删除的行(这不是“导致”差异的人),我们想知道是谁删除了它。我怀疑实现这一点的唯一方法是检查被比较的两个修订之间的每个提交(并以某种方式将单独差异中的所有更改映射到总差异中的行)...
是否存在可以做类似事情的工具?
答案1
我不完全确定我理解了你想要什么,但我用 TortoiseSVN 做到了这一点:
- 创建从修订版本 1 到修订版本 A 的追溯 - 保存为 A.txt
- 创建从修订版本 1 到修订版本 B 的追溯 - 保存为 B.txt
- 从两个文本文件中删除第一列(行)(我使用 Pspad 编辑器,它可以删除文本文件的一列)
- 合并 A.txt 和 B.txt (TortoiseMerge.exe /base:"a.txt" /mine:"b.txt" )
它显示了修订 A 和 B 之间的更改、添加和删除的行以及日期、用户和分支,我认为这就是您想要的。
答案2
SVN diff 只接受两个修订版本并即时生成输出。SVN annotate 只接受一个修订版本。您怀疑提议的实用程序需要迭代 N 个修订版本,这是正确的;SVN 将修订状态存储为整个对象。
您可能更愿意使用 git 和 git-svn 网关......
答案3
是否存在可以做类似事情的工具?
嗯,我想现在有的。
用法;blameDiff <path> [rev1] [rev2]
bash 函数
function blameDiff() {
file="$1"
rev1="$2"
rev2="$3"
#default to HEAD if omitted
if [ -n "$rev1" ]
then
title1="(revision $rev1)"
else
title1="(working copy)"
rev1='HEAD'
fi
if [ -n "$rev2" ]
then
title2="(revision $rev2)"
else
title2="(working copy)"
rev2='HEAD'
fi
#check that the svn urls are the same
tmp1="$(svn info -r $rev1 "$file" |\
grep '^Relative URL' |\
sed 's/Relative URL: //' \
)"
tmp2="$(svn info -r $rev2 "$file" |\
grep '^Relative URL' |\
sed 's/Relative URL: //' \
)"
if [ "$tmp1" != "$tmp2" ]
then
#if not, then one of these revisions is in another branch
#lets have this in the output
title1="($tmp1) $title1"
title2="($tmp2) $title2"
fi
#can just print this but you wont get deleted revision/blame
# diff -u \
# <(svn blame -r "$rev1" "$file") \
# <(svn blame -r "$rev2" "$file") \
# | sed "s|^--- .*$|--- $file $title1|" \
# | sed "s|^+++ .*$|+++ $file $title2|"
# return 0
#an array of commitNumber|committer pairs for the file
history=()
#a map between elements in `history` and a list of line numbers changed.
#each item in the list is a lineNumber|newLineNumber pair
declare -A revisions
#the sed match and replace expressions to pull data from the
#diff-line-number&cat-line-number combo and give it to the cache
grabData='^ *\([0-9]\+\)\t\([0-9]\+\)$'
formatData='\2 \1'
#for each revision between the ones given
last=''
while read -r line
do
#read in the revision number and submitter
IFS=' |' read next by tmp <<<"$line"
if [ -n "$last" ]
then
#save them
history+=("$next $by")
#associate and format the list
revisions["${history[-1]}"]="$(\
diff \
--unchanged-line-format="%dn%c'\012'" \
--new-line-format="?%c'\012'" \
--old-line-format='' \
<(svn cat -r "$last" "$file") \
<(svn cat -r "$next" "$file") \
| cat -n \
| grep -v '?$' \
| sed "s/$grabData/$formatData/" \
)"
fi
#remember the last revision looked at
last="$next"
done <<<"$(
svn log -r "$rev1:$rev2" "$file" \
| grep '^r[0-9]\+ | ' \
| sed 's/^r//' \
)"
#pull the full diff
diff \
--new-line-format='+%L' \
--old-line-format='-%L' \
--unchanged-line-format='=%L' \
<(svn blame -r "$rev1" "$file") \
<(svn blame -r "$rev2" "$file") \
| {
#header stuff
echo "Index: $file"
echo '==================================================================='
echo "--- $file $title1"
echo "+++ $file $title2"
#count the line number we're up to for the original file
origLine=0
#count the line number we're up to for the new file
newLine=0
#keep a few of the output lines, and their line number contexts
buffer=()
origContext=()
newContext=()
#tells the script to print the buffer if <3;
#the context lines around real differences
printing=4
#whether or not the next print needs to show line numbers
needsContext=true
#the sed match and replace expressions to pull data from diff
#and give it to read
grabData='^\([+=-]\)\( *[0-9]\+\)\( *[^ ]\+\)\(.*\)$'
formatData='\1\v\2\v\3\v\4'
#for each line in the full diff
while read -r data
do
IFS=$'\v' read flag committed who line <<<"$(\
sed $'s/\t/ /g' \
<<<"$data" \
| sed "s/$grabData/$formatData/" \
)"
#the last surviving revision of the line
edited="$rev2"
#who killed this line
by=''
case "$flag" in
+)
#a new line was introduced
((++newLine))
printing=0
;;
-)
#an old line was removed
((++origLine))
printing=0
#the line number that changes throughout history
number="$origLine"
#for each commit
for revision in "${history[@]}"
do
#read in the two line numbers from the matching change
number="$(grep "^$number " <<<"${revisions["$revision"]}")"
IFS=' ' read edited by <<<"$revision"
#not present; this was the revision where it was destroyed
if [ -z "$number" ]
then
break
fi
#pull the new line number for the next revision
IFS=' ' read tmp number <<<"$number"
done
;;
=)
#an old line continues to exist in the new file
((++newLine))
((++origLine))
flag=' '
((++printing))
;;
esac
#format the line to print
buffer+=("$(printf "%s %s:%-${#committed}s%s:%-${#who}s%s" \
"$flag" \
"$committed" \
"$edited" \
"$who" \
"$by" \
"$line" \
)")
#can just end it here, but it will print the whole file/s
# echo "${buffer[-1]}"
# buffer=()
# continue
#and add the context
origContext+=("$origLine")
newContext+=("$newLine")
if ((printing < 4))
then
if $needsContext
then
echo "@@ -${origContext[0]} +${newContext[0]} @@"
needsContext=false
fi
#print all lines in the buffer
for line in "${buffer[@]}"
do
echo "$line"
done
#and reset it
origContext=()
newContext=()
buffer=()
fi
#if there are too many lines in the buffer
if ((${#buffer[@]} > 3))
then
#remove the overflow
origContext=("${origContext[@]:1}")
newContext=("${newContext[@]:1}")
buffer=("${buffer[@]:1}")
#and note that we now need to show the context because of this
needsContext=true
fi
done
}
}
我添加了注释作为解释,因此这里就不深入讨论了。在我的系统上
测试了diff
(fedora 27)、svn info
(1.10.2) 的输出,YMMV(但尽管我付出了这么多努力,但我希望结果不会那么好!)。
它基本上重新实现了svn diff
使用 justsvn cat
和 regulardiff
来考虑修订和行号,准确跟踪历史记录中某一行被删除的位置。
甚至考虑文件是否位于不同的分支中,并将其显示为 svn 所为。
以下是两个命令的屏幕截图,其中的代码因工作原因已被删除。
~/data/<redacted>/svn-2.4.2/$ svn diff -r 6600 services/<redacted>.w3p | gvim -
~/data/<redacted>/svn-2.4.2/$ blameDiff services/<redacted>.w3p 6600 | gvim -
如您所见,右侧的新格式提供了大量额外信息;第一列显示 ashley 在 r6631 中添加了几行,并在 r6639 中删除了一大堆很久以前由 zes 提交的 @r6466&6483。
答案4
这并不是你想要的,但你可以得到一个注释视图来查看更改OpenGrok。