47

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

将主干复制到新分支,将其与功能分支合并。完成后,将新分支合并回主干。这种技术很像 mercurial 和 git rebase。

我曾经合并从主干到功能分支的任何变化。但是后来当我把feature分支合并回trunk时,trunk中的一些东西又会重新合并回trunk,造成了很多冲突。有一个重新整合合并的选择,但它似乎对我不起作用。

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

4

6 回答 6

39

一般来说,变基是在将特性分支合并回上游分支之前将上游更改合并到特性分支中的行为。

在 git 中,这个过程更加复杂,因为自创建分支以来所做的更改首先被取出并缓冲,应用上游更改,然后应用缓冲的更改。这里的要点是将主干合并到一个特性分支中,这不是 git 术语中的变基,还有更多。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. (回到功能变基 WC)svn switch feature

然后最终在主干的工作副本上,svn merge --reintegrate feature

您看到简单地将主干合并到功能分支的区别了吗?你从上游的最新版本开始,在这个例子中是主干,然后将特性的变化合并到那个上。

想象一下,主干上的一些提交可能来自另一个功能分支到主干的合并,所以我根本不提倡直接提交到主干。

于 2013-09-30T02:09:22.790 回答
7

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

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

我更希望通过将主干更改合并回分支来刷新分支,这不会导致该分支的后续重新集成合并以在此过程中提取那些重新设置的修订。应该可以根据合并信息属性执行此操作,但根据 jdehaan 的状态,我担心的是这样做仍然需要樱桃采摘。

请注意,适当的变基实施还应该能够考虑楼梯套管示例,其中一个分支是由另一个分支制成的。

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

于 2011-02-09T18:28:18.257 回答
4

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

  1. 对于问题跟踪器中的每个任务NK-$X,我们有一个单独的分支branchs/NK-$X
  2. 我们通过 svn cp trunk branches/NK-$X 开始一项任务
  3. 我们从不直接将更改提交到主干。对于每个计划的更新 UPDNK-$X,我们都有一个单独的分支/UPDNK-$X。我们在更新前使用 svn cp trunk branches/UPDNK-$X 创建它。
  4. 当任务 NK-$X 计划更新 UPDNK-$Y 时,我们合并分支/NK-$X int UPDNK-$Y。即 cd UPDNK-$Y; svn merge -r start:HEAD 分支/NK-$X
  5. UPDNK-$Y 准备好后,我们将其合并到主干。那就是 cd trunk;svn merge -r start:HEAD branches/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

于 2012-11-22T07:17:54.787 回答
0

我正在使用这种方法:

使用变基时,您必须注意不要在再次合并时将变基的修订重新考虑在内。当谈到合并时,做一个樱桃采摘:只选择特性分支上实现新东西的修订,而不是变基变更集。然后它应该可以正常工作。评论:我不记得曾经使用 reintegrate 分支做某事。我认为它仅适用于非常简单的用例。

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

于 2010-07-05T05:13:32.387 回答
0

我使用了一个脚本,它为 svn 执行 git 之类的 rebase:

#!/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

它一一合并来自其他分支的修订。

于 2018-05-08T11:22:53.050 回答
0

使用git svn

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

然后随意使用 git rebase 命令

于 2019-06-21T09:49:41.897 回答