7

Можете ли вы добавить аннотированную / похожую на вину информацию в svn diff, чтобы для каждой измененной строки указывалось, какой пользователь и ревизия изменили эту строку?

Например, аннотирование-сравнение, сравнивающее редакции 8-10, может вывести что-то вроде:

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

Контекст, линии вокруг него, которые не изменились, могут быть включены или нет, не имеет значения.

Это не просто вопрос "быстрого" написания сценария оболочки, объединяющего вывод svn diff и svn annotate. Например, аннотирование никогда не покажет вам, кто удалил строку. Это также не вопрос аннотирования ревизии в прошлом: нас не интересует, кто первоначально добавил удаленную строку (это не тот, кто "вызвал" разницу), мы хотим знать, кто ее удалил. Я подозреваю, что единственный способ реализовать что-то для этого - это проверить каждый коммит между двумя сравниваемыми ревизиями (и каким-то образом отобразить все изменения в отдельных разностях в строки в общем разнице)

Существует ли инструмент, который делает что-то подобное?

5 ответов5

1

Я не совсем уверен, что понял, что именно вы хотите, но я сделал это с помощью TortoiseSVN:

  1. Создать вину из ревизии 1 в ревизию A - сохранить как A.txt
  2. Создать вину из ревизии 1 в ревизию B - сохранить как B.txt
  3. Удалить первый столбец (строку) из обоих текстовых файлов (я использовал редактор Pspad, который может удалить столбец текстового файла)
  4. Объединить A.txt и B.txt (TortoiseMerge.exe /base:"a.txt "/mine:"b.txt")

Он показывает измененные, добавленные и удаленные строки между ревизиями A и B вместе с датой, пользователем и веткой, я думаю, это то, что вы хотели.

1

SVN diff берет ровно две ревизии и генерирует вывод на лету. Аннотирование SVN занимает ровно одну ревизию. Ваше подозрение, что предложенной утилите потребуется перебирать N ревизий, верно; SVN хранит ревизионные состояния как целые объекты.

Возможно, вам повезет больше с git и git-svn gateway ...

0

В вашей базовой настройке SVN ванили нет команды, которая могла бы объединить выводы вины и различий в конкретной ревизии. Если бы вы указали конкретный клиент SVN, который вы использовали, я мог бы найти плагин, который делает это, но вы не смогли, поэтому я не смог его найти.

Единственная альтернатива - использовать скрипт или небольшую программу для совмещения двух выходов. Это не должно быть так сложно, если вы можете получить номера строк на diff и вины. Даже если это не тот ответ, на который вы надеялись, это ответ, и этот вопрос остается открытым с 2009 года.

0

Существует ли инструмент, который делает что-то подобное?

Ну, я думаю, что сейчас.

Использование; blameDiff <path> [rev1] [rev2]

функция Баш

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 используя просто svn cat и обычный diff чтобы учесть номер ревизии и строки, отслеживая, где именно в истории была удалена данная строка.
Даже принимает во внимание, находятся ли файлы в разных ветвях и отображает их как 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 -

Как вы видите, куча дополнительной информации дается в новом формате справа; первые столбцы показывают, что Эшли добавила пару строк назад в r6631 и удалила целую связку в r6639, изначально зафиксированную zes @ r6466 & 6483.

0

Это не совсем то, что вы хотели, но вы можете получить аннотированный обзор изменений в OpenGrok.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .