Subversion ребаз?
Я считаю, что таким образом легче объединить ветви и меньше конфликтов:
Скопируйте ствол в новую ветвь, объедините его с функцией branch /s. Когда все готово, слить новую ветку обратно в ствол. Эта техника очень похожа на меркуриоз и мерзавец.
Я использовал для слияния все изменения от ствола к функции Branche / S. Но позже, когда я объединил ветвь функции обратно в транк, некоторые вещи из транка снова были объединены в транк, что вызвало много конфликтов. Существует возможность реинтеграции слияния, но, похоже, это не сработало для меня.
Кто-нибудь делает подобный переброс Subversion? Я только начал делать это недавно, и не видел никаких побочных эффектов. Это вызвало бы непредвиденные проблемы?
5 ответов
Вообще говоря, перебазирование - это акт включения восходящих изменений в ветвь функции перед тем, как объединить ветвь функции обратно с веткой вверх.
В git процесс еще более сложный, потому что изменения, которые были сделаны после создания ветки, сначала снимаются и буферизуются, применяются восходящие изменения, затем применяются буферизованные изменения. Выводом здесь является объединение соединительной линии в ветвь функций - это не перебазирование в терминах git, это еще не все. Подход git имеет ряд преимуществ, но не может быть реализован очень четко в SVN, поскольку все коммиты должны храниться на сервере (SVN не распространяется), однако это может быть сделано в SVN.
'Svn rebase' (git way) может выглядеть примерно так
svn cp trunk feature
- берет на себя функцию и багажник
svn cp trunk feature-rebase
svn co feature-rebase
cd feature-rebase
svn merge feature
svn commit
svn rm feature
svn mv feature-rebase feature
- (вернуться на фейсбук WC)
svn switch feature
Затем в конечном итоге на рабочей копии ствола, svn merge --reintegrate feature
Вы видите разницу от простого объединения ствола с веткой функций? В этом примере вы начинаете с последней версии от основной линии связи, транка, а затем объединяете изменения из функции.
Представьте, что некоторые коммиты на транке могут быть получены в результате слияния другой ветки функций в транк, поэтому я вовсе не рекомендую совершать коммиты напрямую на транк.
Хотелось бы, чтобы у меня был хитрый трюк, чтобы рассказать вам о том, как добиться перебазирования в SVN, но я всегда избегал ручного обновления ветки с изменениями магистрали в SVN, главным образом из-за сложностей, требующих ручного выбора вишни, о котором упоминает jdehaan.
Вместо этого я обычно следую практике объединения изменений из ветви в ствол, удаления ветви и последующего воссоздания ветви из ствола. Это позволяет мне обновить / перебазировать мою функциональную ветку, но с иногда неприятным побочным эффектом, что любые предыдущие изменения из этой ветви теперь являются частью магистрали. По этой причине я придерживаюсь этой практики только тогда, когда ветвь функции находится в стабильной и пригодной для использования точке, но все же я хочу продолжить работу над этой функцией, чтобы в дальнейшем выполнить более масштабную задачу.
Я бы предпочел, чтобы обновление ветки путем объединения изменений в магистрали обратно в ветку не приводило к тому, чтобы последующие объединения реинтеграции из этой ветки вытягивали эти пересмотренные ревизии в процессе. Должно быть возможно сделать это на основе свойств merge-info, но в соответствии с тем, что заявляет jdehaan, и чего я боялся, так это того, что для этого все еще требуется сбор вишни.
Обратите внимание, что правильная реализация перебазирования также должна быть в состоянии принять во внимание примеры корпусов лестниц, где ветвь сделана из другой ветки.
Обновление. Согласно документации Subversion, кажется, что при использовании опции--reintegrate Subversion должна иметь возможность правильно реинтегрировать работу, выполненную в ветке, таким образом, чтобы предотвратить возможные слияния обновлений, которые могли быть сделаны для внесения базовых изменений в ветка. Конечно, технически это немного отличается от перебазирования, но я думаю, что оно достаточно схоже в использовании, что его можно назвать перебазированием.
В моей компании мы используем следующий подход:
- для каждой задачи NK- $ X в трекере проблем у нас есть отдельная ветка веток /NK-$X
- мы начинаем работу над задачей по веткам svn cp trunk /NK-$X
- мы никогда не вносим изменения непосредственно в ствол. Для каждого запланированного обновления UPDNK-$X у нас есть отдельные ветки /UPDNK-$X. Мы создаем его с помощью svn cp магистральных веток / UPDNK-$X непосредственно перед обновлением.
- когда задача NK- $ X запланирована для обновления UPDNK-$Y, мы объединяем ветви /NK-$X в UPDNK-$Y. Это CD UPDNK-$Y; svn merge -r start: ветки HEAD /NK-$X
- после того, как 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
Он объединяет ревизии из другой ветки одна за другой.