Subversion ребаз?

Я считаю, что таким образом легче объединить ветви и меньше конфликтов:

Скопируйте ствол в новую ветвь, объедините его с функцией branch /s. Когда все готово, слить новую ветку обратно в ствол. Эта техника очень похожа на меркуриоз и мерзавец.

Я использовал для слияния все изменения от ствола к функции Branche / S. Но позже, когда я объединил ветвь функции обратно в транк, некоторые вещи из транка снова были объединены в транк, что вызвало много конфликтов. Существует возможность реинтеграции слияния, но, похоже, это не сработало для меня.

Кто-нибудь делает подобный переброс Subversion? Я только начал делать это недавно, и не видел никаких побочных эффектов. Это вызвало бы непредвиденные проблемы?

5 ответов

Вообще говоря, перебазирование - это акт включения восходящих изменений в ветвь функции перед тем, как объединить ветвь функции обратно с веткой вверх.

В git процесс еще более сложный, потому что изменения, которые были сделаны после создания ветки, сначала снимаются и буферизуются, применяются восходящие изменения, затем применяются буферизованные изменения. Выводом здесь является объединение соединительной линии в ветвь функций - это не перебазирование в терминах git, это еще не все. Подход git имеет ряд преимуществ, но не может быть реализован очень четко в SVN, поскольку все коммиты должны храниться на сервере (SVN не распространяется), однако это может быть сделано в SVN.

'Svn rebase' (git way) может выглядеть примерно так

  1. svn cp trunk feature
  2. берет на себя функцию и багажник
  3. svn cp trunk feature-rebase
  4. svn co feature-rebase
  5. cd feature-rebase
  6. svn merge feature
  7. svn commit
  8. svn rm feature
  9. svn mv feature-rebase feature
  10. (вернуться на фейсбук WC) svn switch feature

Затем в конечном итоге на рабочей копии ствола, svn merge --reintegrate feature

Вы видите разницу от простого объединения ствола с веткой функций? В этом примере вы начинаете с последней версии от основной линии связи, транка, а затем объединяете изменения из функции.

Представьте, что некоторые коммиты на транке могут быть получены в результате слияния другой ветки функций в транк, поэтому я вовсе не рекомендую совершать коммиты напрямую на транк.

Хотелось бы, чтобы у меня был хитрый трюк, чтобы рассказать вам о том, как добиться перебазирования в SVN, но я всегда избегал ручного обновления ветки с изменениями магистрали в SVN, главным образом из-за сложностей, требующих ручного выбора вишни, о котором упоминает jdehaan.

Вместо этого я обычно следую практике объединения изменений из ветви в ствол, удаления ветви и последующего воссоздания ветви из ствола. Это позволяет мне обновить / перебазировать мою функциональную ветку, но с иногда неприятным побочным эффектом, что любые предыдущие изменения из этой ветви теперь являются частью магистрали. По этой причине я придерживаюсь этой практики только тогда, когда ветвь функции находится в стабильной и пригодной для использования точке, но все же я хочу продолжить работу над этой функцией, чтобы в дальнейшем выполнить более масштабную задачу.

Я бы предпочел, чтобы обновление ветки путем объединения изменений в магистрали обратно в ветку не приводило к тому, чтобы последующие объединения реинтеграции из этой ветки вытягивали эти пересмотренные ревизии в процессе. Должно быть возможно сделать это на основе свойств merge-info, но в соответствии с тем, что заявляет jdehaan, и чего я боялся, так это того, что для этого все еще требуется сбор вишни.

Обратите внимание, что правильная реализация перебазирования также должна быть в состоянии принять во внимание примеры корпусов лестниц, где ветвь сделана из другой ветки.

Обновление. Согласно документации Subversion, кажется, что при использовании опции--reintegrate Subversion должна иметь возможность правильно реинтегрировать работу, выполненную в ветке, таким образом, чтобы предотвратить возможные слияния обновлений, которые могли быть сделаны для внесения базовых изменений в ветка. Конечно, технически это немного отличается от перебазирования, но я думаю, что оно достаточно схоже в использовании, что его можно назвать перебазированием.

В моей компании мы используем следующий подход:

  1. для каждой задачи NK- $ X в трекере проблем у нас есть отдельная ветка веток /NK-$X
  2. мы начинаем работу над задачей по веткам svn cp trunk /NK-$X
  3. мы никогда не вносим изменения непосредственно в ствол. Для каждого запланированного обновления UPDNK-$X у нас есть отдельные ветки /UPDNK-$X. Мы создаем его с помощью svn cp магистральных веток / UPDNK-$X непосредственно перед обновлением.
  4. когда задача NK- $ X запланирована для обновления UPDNK-$Y, мы объединяем ветви /NK-$X в UPDNK-$Y. Это CD UPDNK-$Y; svn merge -r start: ветки HEAD /NK-$X
  5. после того, как UPDNK-$Y готов, мы объединяем его в транк. Это транк CD; svn merge -r start:HEAD ветки /UPDNK-$Y

Если случается, что задача NK- $ X длится дольше, чем один итерационный цикл, и, следовательно, нуждается в обновлении, мы никогда, НИКОГДА не объединяем магистраль с NK- $ X. У нас есть правило, что вы передаете в свою ветку только то, что написали сами, что делает все проще. Вместо этого мы делаем:

cd NK-$X
svn log
//let L = the number of the last changeset to this branch changeset
//let F = the number of the first changeset to this branch
svn rm branches/NK-$X 
svn cp trunk branches/NK-$X 
svn up
svn merge -r F:L branches/NK-$X@L 
svn ci -m 'refereshed'

Таким образом, всякий раз, когда вы смотрите на список изменений ветвей /NK-$X, вы видите только изменения, фактически выполненные разработчиком.

Обновление: так как вышеуказанный рабочий процесс может быть автоматизирован, я запустил проект на github: svn rebase.

Использование git svn:

git svn clone -s <link to svn trunk/branches/tags parent>

тогда не стесняйтесь использовать команду git rebase

Я использую этот подход:

При перебазировании вы должны позаботиться о том, чтобы не перенести пересмотренные ревизии при повторном слиянии. Когда дело доходит до слияния, сделайте выбор вишни: выберите только те ревизии в ветви функций, которые реализуют что-то новое, а не перебазирующие наборы изменений. Тогда все должно работать нормально. КОММЕНТАРИЙ: Я никогда не помню, чтобы когда-то использовал ветвь реинтеграции. Я думаю, что он предназначен только для очень простых случаев использования.

В вашем новом подходе из описания неясно, как вы обрабатываете перебазирование из транка в ваши ветви функций, если вам это нужно. Вы хотите полностью запретить перебазирование? Поскольку ветвление в svn - дешевая операция, это тоже может быть вариантом.

Я использую скрипт, который делает git like rebase для svn:

#!/bin/bash

set_safe()
{
    set -eo pipefail
}

validate_number()
(
    if (! [ "$1" -eq "$1" ] 2>/dev/null ) then
    {
        echo "$1 is not a number"
        return 1
    }
    fi
)

get_line()
(
    set_safe
    #head -n "$1" | tail -n 1
    sed -n "${1}p;$(($1+1))q"
)

split_trim()
(
    set_safe
    tr "$1" '\n' | sed -e 's/^\s*//;' -e 's/\s*$//'
)

run_svn()
(
    set +x
    #echo "svn $*" 1>&2
    svn --non-interactive --password "$svn_password" "$@"
)

rebase()
(
    set_safe

    url="$1"
    cur="$2"
    end="$3"

    validate_number "$cur"
    if ([ -z "$end" ] || [ "$end" = "HEAD" ]) then
    {
        end="$(run_svn info "$url" | grep "Last Changed Rev" | cut -d' ' -f4)"
        echo "end: $end"
    }
    else
    {
        validate_number "$end";
    }
    fi

    while (true) do
    {
        log="$(run_svn log "$url" -l1 -r "$cur:HEAD")"
        meta="$(echo -n "$log" | get_line 2 | split_trim '|')"
        next="$(echo -n "$meta" | get_line 1 | tail -c +2)"
        author="$(echo -n "$meta" | get_line 2)"
        date="$(echo -n "$meta" | get_line 3 | awk '{print $1, $2, $3}')"
        msg="$(echo -n "$log" | tail -n +4 | head -n -1)"
        cur=$next

        if ([ -z $cur ] || [ $cur -gt $end ]) then { break; } fi

        echo "$msg" > .msg

        echo "Merging revision $cur:"
        echo "========"
        cat .msg
        echo "========"

        run_svn merge "$url" -c $cur
        run_svn commit -F .msg
        rm -f .msg
        run_svn update

        echo "Success"
        echo

        cur=$(($cur + 1))
    }
    done
)

if ([ -z "$1" ]) then
{
    echo "Usage:"
    echo "    svn-rebase.sh <url> <begin revision> [end revision]"
    exit
}
fi

echo -n "svn password: "
read -s svn_password
echo

rebase "$1" "$2" "$3"
err=$?
if ([ $err -ne 0 ]) then { echo "rebase failed: $err"; } fi
exit $err

Он объединяет ревизии из другой ветки одна за другой.

Другие вопросы по тегам