svn diff mit annotierten / schuldähnlichen Informationen darüber, wann Änderungen von wem vorgenommen wurden


7

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

Ein Annotate-Diff, das die Revisionen 8-10 vergleicht, könnte beispielsweise 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 um ihn herum, die sich nicht geändert haben, kann ebenfalls enthalten sein oder nicht, spielt keine Rolle.

Es geht nicht nur darum, "schnell" ein Shell-Skript zu schreiben, das die Ausgabe von svn diff und svn annotate kombiniert. Mit Annotate wird beispielsweise nie angezeigt, 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 (das ist nicht derjenige, der den Unterschied "verursacht" hat), wir möchten wissen, wer sie entfernt hat. Ich vermute, die einzige Möglichkeit, etwas zu implementieren, besteht darin, jedes Commit zwischen den beiden verglichenen Revisionen zu überprüfen (und irgendwie alle Änderungen in den einzelnen Unterschieden den Zeilen im Gesamtdifferenz zuzuordnen) ...

Gibt es ein Tool, das so etwas macht?

Antworten:


1

Ich bin mir nicht ganz sicher, ob ich genau verstanden habe, was Sie wollen, aber ich habe dies mit TortoiseSVN getan:

  1. Erstellen Sie Schuld von Revision 1 bis Revision A - speichern Sie als A.txt
  2. Erstellen Sie Schuld von Revision 1 bis Revision B - speichern Sie als B.txt
  3. Entfernen Sie die erste Spalte (Zeile) aus beiden Textdateien (ich habe den Pspad-Editor verwendet, mit dem eine Spalte einer Textdatei gelöscht werden 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 zusammen mit Datum, Benutzer und Zweig. Ich denke, das ist, was Sie wollten.


Das würde in dieselbe Kategorie fallen wie das von mir erwähnte "a-Shell-Skript, das die Ausgabe von svn diff und svn annotate kombiniert" und hat das gleiche Problem: Bei Zeilen, die entfernt wurden, wird angezeigt, wer die Zeile ursprünglich hinzugefügt hat, nicht wer sie entfernt hat es.
Wouter Coekaerts

1

SVN diff benötigt genau zwei Revisionen und generiert eine Ausgabe im laufenden Betrieb. SVN Annotate benötigt genau eine Revision. Ihr Verdacht, dass das vorgeschlagene Dienstprogramm N Revisionen durchlaufen muss, ist richtig. SVN speichert Revisionszustände als ganze Objekte.

Vielleicht haben Sie mit git und dem git-svn-Gateway mehr Glück ...


0

In Ihrem grundlegenden Vanilla-SVN-Setup gibt es keinen Befehl, mit dem die Ausgaben von Schuld und Unterschied bei einer bestimmten Revision zusammengeführt werden können. Wenn Sie den von Ihnen verwendeten SVN-Client angegeben haben, konnte ich möglicherweise ein Plugin 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 Schuld bekommen können. Auch wenn dies nicht die Antwort ist, auf die Sie gehofft haben, ist es eine Antwort, und diese Frage ist seit 2009 offen.


Ich habe keinen bestimmten SVN-Client angegeben, da dies keine Rolle spielt: Ich würde gerne (nur wenn ich diese Funktion benötige) einen anderen Client verwenden.
Wouter Coekaerts

1
Wie ich bereits in der Beschreibung gesagt habe, geht es nicht nur darum, die Ausgabe eines Diff und eines Annotates abzugleichen. Es sieht so aus, als ob es darum geht, eine Reihe von Patches zu einem zusammenzuführen, während verfolgt wird, welche Änderung von welchem ​​Diff (und dem Committer dieses Diff) stammt. Das ist definitiv keine leichte Aufgabe. Entschuldigung, aber zu behaupten, es sei einfach, ist keine wirkliche Antwort auf die Frage, wie es geht.
Wouter Coekaerts


0

Gibt es ein Tool, das so etwas macht?

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["${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
    }
}

Ich habe Kommentare als Erklärung hinzugefügt, damit ich hier nicht darauf eingehen werde.
Getestet, um mit den Ausgängen von diff(fedora 27), svn info(1.10.2) auf meinem System YMMV zu arbeiten (aber trotz all meiner Bemühungen hoffe ich nicht so viel!).

Grundsätzlich wird die svn diffVerwendung von "Just svn catand Regular" neu implementiert diff, um die Revisions- und Zeilennummern zu berücksichtigen, und es wird genau verfolgt, wo in der Historie eine bestimmte Zeile entfernt wurde.
Berücksichtigt sogar, 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 redigiert 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 -

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, werden rechts im neuen Format einige zusätzliche Informationen angezeigt. Die ersten Spalten zeigen, dass Ashley in r6631 ein paar Zeilen hinzugefügt und in r6639 eine ganze Reihe von Zeilen gelöscht hat, die ursprünglich von zes vor langer Zeit @ r6466 & 6483 festgeschrieben wurden.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.