svn diff, einschließlich annotierter / schuldähnlicher Informationen darüber, wann von wem Änderungen vorgenommen wurden

2453
Wouter Coekaerts

Können Sie zu svn diff mit Anmerkungen versehene / schuldähnliche Informationen hinzufügen, sodass für jede geänderte Zeile angegeben wird, welcher Benutzer und welche Revision diese Zeile geändert hat?

Zum Beispiel könnte eine Annotate-Diff-Vergleichsversion 8-10 Folgendes ausgeben:

9 user1 - some line that user1 deleted in revision 9 10 user2 + some line that user2 added in revision 10 

Der Kontext, Linien, die sich nicht geändert haben, können ebenfalls enthalten sein oder nicht, spielt keine Rolle.

Es ist nicht nur eine Frage des "schnellen" Schreibens eines Shell-Skripts, das die Ausgabe von svn diff und svn annotate kombiniert. Eine Anmerkung zum Beispiel zeigt nie, wer eine Zeile entfernt hat. Es geht auch nicht darum, Anmerkungen zu einer Revision in der Vergangenheit zu machen: Wir sind nicht daran interessiert, wer ursprünglich die entfernte Zeile hinzugefügt hat (dies ist nicht die Person, die den Diff "verursacht" hat), wir möchten wissen, wer sie entfernt hat. Ich vermute, der einzige Weg, etwas zu implementieren, um dies zu tun, besteht darin, jedes Commit zwischen den beiden zu überprüfenden Revisionen zu überprüfen (und irgendwie alle Änderungen in den separaten Unterschieden zu Zeilen im Gesamtunterschied abzubilden) ...

Gibt es ein Werkzeug, das so etwas tut?

7

5 Antworten auf die Frage

1
Odin

Ich bin nicht ganz sicher, dass ich genau verstanden habe, was Sie wollen, aber ich habe dies mit TortoiseSVN gemacht:

  1. Erstellen Sie Blame von Version 1 bis Version A - Speichern Sie als A.txt
  2. Erstellen Sie Blame von Version 1 bis Version B - Speichern Sie als B.txt
  3. Erste Spalte (Zeile) aus beiden Textdateien entfernen (ich habe den Pspad-Editor verwendet, der eine Spalte einer Textdatei löschen kann)
  4. A.txt und B.txt zusammenführen (TortoiseMerge.exe /base:"a.txt "/mine:"b.txt")

Es zeigt geänderte, hinzugefügte und entfernte Zeilen zwischen den Revisionen A und B sowie Datum, Benutzer und Zweig. Ich denke, das war genau das, was Sie wollten.

Das würde in die gleiche Kategorie fallen wie das "a-Shell-Skript, das die Ausgabe von svn diff und svn annotate kombiniert", das ich erwähnt habe, und hat das gleiche Problem: Für Zeilen, die entfernt wurden, wird angezeigt, wer ursprünglich die Zeile hinzugefügt hat, nicht wer entfernt wurde es. Wouter Coekaerts vor 13 Jahren 0
1
qneill

SVN diff nimmt genau zwei Überarbeitungen an und erzeugt im laufenden Betrieb eine Ausgabe. SVN-Annotate benötigt genau eine Revision. Ihr Verdacht, dass das vorgeschlagene Hilfsprogramm N Revisionen durchlaufen muss, ist richtig. SVN speichert Revisionszustände als ganze Objekte.

Mit git und dem git-svn-Gateway haben Sie vielleicht mehr Glück ...

0
Daisetsu

In Ihrem grundlegenden Vanilla-SVN-Setup gibt es keinen Befehl, der die Ausgaben von blame und diff in einer bestimmten Revision zusammenführen kann. Wenn Sie den bestimmten SVN-Client angegeben haben, den Sie verwendet haben, war es mir möglich, ein Plugin zu finden, das dies tut, aber Sie haben es nicht getan, sodass ich nicht nach einem suchen konnte.

Die einzige Alternative besteht darin, ein Skript oder ein kleines Programm zu verwenden, um die beiden Ausgaben abzugleichen. Dies sollte nicht so schwer sein, wenn Sie Zeilennummern auf diff und blame bekommen können. Auch wenn dies nicht die Antwort ist, auf die Sie gehofft haben, ist dies eine Antwort, und diese Frage steht seit 2009 offen.

Ich habe keinen bestimmten SVN-Client angegeben, weil es keine Rolle spielt: Ich würde mich freuen, wenn ich diese Funktion brauche, um einen anderen Client zu verwenden. Wouter Coekaerts vor 13 Jahren 0
Wie ich bereits in der Beschreibung gesagt habe, geht es nicht nur darum, die Ausgabe eines diff und eines mit Anmerkungen zu vergleichen. Es sieht so aus, als ob es eine Sache ist, eine Reihe von Patches zu einem zu verschmelzen und dabei zu verfolgen, welche Veränderung von welchem ​​Diff (und dem Committer dieses Diff) herrührt. Das ist definitiv keine leichte Aufgabe. Tut mir leid, aber die Behauptung, es sei einfach, ist nicht wirklich eine Antwort auf die Frage, wie es geht. Wouter Coekaerts vor 13 Jahren 1
0
Peter Loron

Das ist nicht genau das, wonach Sie gesucht haben, aber Sie können eine kommentierte Ansicht der Änderungen in OpenGrok erhalten .

0
Hashbrown

Gibt es ein Werkzeug, das so etwas tut?

Nun, ich denke, das tut es jetzt.

Verwendungszweck; blameDiff <path> [rev1] [rev2]

Bash-Funktion

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["$"]="$(\ 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 "$" do #read in the two line numbers from the matching change number="$(grep "^$number " <<<"$")" 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=() # continue #and add the context origContext+=("$origLine") newContext+=("$newLine")  if ((printing < 4)) then if $needsContext then echo "@@ -$ +$ @@" needsContext=false fi  #print all lines in the buffer for line in "$" 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=("$") newContext=("$") buffer=("$") #and note that we now need to show the context because of this needsContext=true fi done } } 

Ich habe Kommentare als Erklärung hinzugefügt, deshalb werde ich hier nicht darauf eingehen.
Getestet, um mit den Ausgängen von diff(fedora 27), svn info(1.10.2) auf meinem System YMMV zu arbeiten (aber ich hoffe für all meine Mühe nicht so sehr!).

Im Wesentlichen wird die svn diffVerwendung von just svn catund regular neu implementiert diff, um die Revisions- und Zeilennummern zu berücksichtigen und genau zu verfolgen, wo in der Historie eine bestimmte Linie entfernt wurde.
Sogar berücksichtigt, ob sich die Dateien in verschiedenen Zweigen befinden, und zeigt sie wie svn an.

Hier sind Screenshots der beiden folgenden Befehle, wobei der Code aus Arbeitsgründen geändert wurde.

~/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 - 

enter image description here

Wie Sie sehen, wird im neuen Format rechts eine Reihe zusätzlicher Informationen angezeigt. Die ersten Spalten zeigen, dass Ashley ein paar Zeilen in r6631 hinzugefügt hat und eine ganze Reihe von r6639 gelöscht hat, die ursprünglich von zes long @ r6466 & 6483 begangen wurden.