Subversion rebase?

时间:2010-07-05 04:12:38

标签: svn rebase svn-reintegrate

我发现这种方式更容易合并分支和更少的冲突:

  

将trunk复制到新分支,将其与功能分支合并。完成任务后,将新分支合并回主干。这种技术非常像mercurial和git rebasing。

我曾经合并过一些来自trunk的chang到feature branche / s。但后来当我将功能分支合并回主干时,来自主干的一些内容将再次合并回主干,这引起了很多冲突。有一个重新整合合并的选择,但它似乎并不适合我。

有没有人做类似的颠覆变基?我刚刚开始这样做,并没有看到任何副作用。这会导致任何不可预见的问题吗?

6 个答案:

答案 0 :(得分:29)

一般来说,在将功能分支合并回上游分支之前,重新定位是将上游更改合并到功能分支中的行为。

在git中,该过程更加复杂,因为自创建分支以来所做的更改首先被取消并缓冲,应用上游更改,然后应用缓冲的更改。这里的内容是将主干合并到一个功能分支不是git术语中的rebase,还有更多内容。 git方法有许多优点,但是在svn中无法非常干净地实现,因为所有提交都必须存储在服务器上(svn不是分布式的),但可以在svn中完成。

'svn rebase'(git方式)可能看起来像这样

  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. (返回feature-rebase WC)svn switch feature
  11. 然后最终在trunk的工作副本上svn merge --reintegrate feature

    您看到简单地将主干合并到功能分支的区别?在此示例中,您将从上游的最新版本trunk开始,然后将功能中的更改合并到该。

    想象一下,trunk上的一些提交可能来自另一个功能分支合并到trunk,所以我一点也不主张直接提交trunk。

答案 1 :(得分:7)

我希望我有一个聪明的伎俩可以告诉你如何在SVN中实现变基,但我总是避免手动刷新SVN中的主干变化的分支主要是因为jdehaan提到的需要手动樱桃采摘的复杂性。

我通常做的是遵循将更改从分支合并到主干,删除分支,然后从主干重新创建分支的做法。这允许我刷新/重新定义我的功能分支,但有时不幸的副作用是,该分支的任何先前更改现在都是主干的一部分。出于这个原因,我只是在功能分支处于稳定且可用的点时才遵循这种做法,但我仍然希望继续使用该功能以进一步完成更大的目标。

我更喜欢通过将主干更改合并回分支来刷新分支,而不会导致后续重新集成从该分支合并以在该过程中提取这些重新定义的修订。应该可以根据merge-info属性执行此操作,但根据jdehaan的说法和我担心的是,这样做仍然需要采摘樱桃。

请注意,正确的变基实现也应该能够考虑到分支是从另一个分支制作的阶梯套管示例。

更新:根据Subversion文档,当使用--reintegrate option时,Subversion应该能够以一种可以考虑任何可能的刷新合并的方式正确地重新集成在分支中完成的工作可能已经完成将基础更改带入分支。当然,这在技术上与变基有点不同,但我认为它在使用上足够相似,可以称之为变基。

答案 2 :(得分:4)

在我的公司,我们使用以下方法:

  1. 对于每个任务NK-$ X在问题跟踪器中我们有一个单独的分支机构/ NK- $ X
  2. 我们通过svn cp trunk branches / NK- $ X
  3. 开始处理任务
  4. 我们从不直接将更改提交到主干。对于每个schedulled更新UPDNK- $ X,我们有一个单独的分支/ UPDNK- $ X.我们在更新之前使用svn cp trunk branches / UPDNK- $ X创建它。
  5. 当任务NK- $ X被调整为更新UPDNK- $ Y时,我们合并分支/ NK- $ X inot UPDNK- $ Y.那就是cd UPDNK- $ Y; svn merge -r start:HEAD branches / NK- $ X
  6. 在UPDNK- $ Y准备好之后,我们将它合并到trunk。那就是cd trunk; svn merge -r start:HEAD branches / UPDNK- $ Y
  7. 如果发生任务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

答案 3 :(得分:0)

我正在使用这种方法:

通过重新定位,您必须注意不要在再次合并时重新考虑重新定义的修订。在合并方面,做一个挑选:只选择功能分支上实现新内容的修订,而不是重定位变更集。那它应该工作正常。评论:我不记得曾经使用过reintegrate分支。我认为它只适用于非常简单的用例。

在您的新方法中,从描述中不清楚如何在需要时如何处理从主干到功能分支的rebase。你想完全不允许变基吗?由于svn中的分支是一种廉价操作,因此这也是一种选择。

答案 4 :(得分:0)

我使用的脚本为svn:

执行类似rebase的git
#!/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

它逐个合并其他分支的修订。

答案 5 :(得分:0)

使用git svn

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

然后随时使用git rebase命令