如何颠覆变基?

发布于 2024-09-08 19:46:35 字数 297 浏览 9 评论 0原文

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

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

我曾经将主干的任何更改合并到功能分支。但是后来当我将feature分支合并回trunk时,trunk中的一些东西又会被再次合并回trunk,这就造成了很多冲突。可以选择重新集成合并,但它似乎对我不起作用。

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

I find this way easier to merge branches and less conflicts:

Copy trunk to a new branch, merge it with feature branch/s. When things done, merge the new branch back to the trunk. This technique is quite like the mercurial and git rebasing.

I used to merge whatever changes from trunk to feature branches. But later when I merged the feature branch back to trunk, some of the stuff from trunk would be merged back again to the trunk, which caused a lot of conflicts. There is a choice of reintegrate merge, but it didn't seem to work for me.

Does anyone do similar subversion rebasing? I just started doing this recently, and haven't seen any side effects. Would this cause any unforeseen problems?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

叹沉浮 2024-09-15 19:46:35

一般来说,变基是将上游更改合并到功能分支中,然后将功能分支合并回上游分支的行为。

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

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

  1. svn cp trunk feature
  2. commits to feature & trunk
  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

然后最终打开trunk 的工作副本,svn merge --reintegrate feature

您看到与简单地将 trunk 合并到功能分支的区别了吗?您从上游的最新版本(本例中的 trunk)开始,然后将功能的更改合并到该版本上。

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

Generally speaking, rebasing is the act of incorporating upstream changes into a feature branch, before merging the feature branch back into the upstream branch.

In git, the process is even more sophisticated, because the changes that have been made since the branch was created are first taken off and buffered, the upstream changes are applied, then the buffered changes are applied. The takeaway here is merging trunk into a feature branch is not a rebase in git terms, there's more to it. The git approach has a number of advantages, but can't be implemented very cleanly in svn since all commits must be stored on the server (svn is not distributed), however it can be done in svn.

An 'svn rebase' (the git way) might look something like this

  1. svn cp trunk feature
  2. commits to feature & trunk
  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. (back on feature-rebase WC) svn switch feature

Then eventually on a working copy of trunk, svn merge --reintegrate feature

You see the difference from simply merging trunk to the feature branch? You start with the latest from upstream, trunk in this example, then merge the changes from feature onto that.

Imagine some of the commits on trunk could come from a merge of another feature branch into trunk, so I am not at all advocating committing directly to trunk.

故笙诉离歌 2024-09-15 19:46:35

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

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

我更喜欢的是,通过将主干更改合并回分支来刷新分支,不会导致随后从该分支进行重新集成合并,以在此过程中提取这些重新调整的修订。应该可以根据 merge-info 属性来做到这一点,但根据 jdehaan 的说法,我担心的是,这样做仍然需要挑选。

请注意,正确的变基实现还应该能够考虑从另一个分支创建分支的楼梯外壳示例。

更新:根据 Subversion 文档,当使用 --重新集成选项,Subversion 应该能够以介意任何可能的刷新合并的方式正确地重新集成在分支中完成的工作这样做可能是为了将基础更改带入分支。当然,这在技术上与变基有点不同,但我认为它在用法上足够相似,可以称为变基。

I wish I had a clever trick to tell you on how to achieve rebasing in SVN but I've always avoided manual refreshing of a branch with trunk changes in SVN mainly because of the complications requiring manual cherry picking that jdehaan mentions.

What I generally do instead is follow the practice of merging changes from a branch to the trunk, deleting the branch, and then recreating the branch from the trunk. This allows me to refresh/rebase my feature branch but with the sometimes unfortunate side effect that any prior changes from that branch are now part of the trunk. For this reason I only follow this practice when a feature branch is at a stable and usable point yet I still wish to continue work on that feature in order to further complete some bigger objective.

What I would prefer is that refreshing a branch by merging trunk changes back into a branch not cause subsequent reintegration merges from that branch to pull those rebased revisions during the process. It should be possible to do this based on the merge-info properties but according to what jdehaan states and what I have feared is that doing this still requires cherry picking.

Note that proper rebasing implementation should also be able to take into consideration stair casing examples where a branch is made from another branch.

Update: According to the Subversion documentation it appears that when using the --reintegrate option that Subversion should be able to properly reintegrate work done in a branch in a way that minds any possible refresh merges that may have been done to bring base changes into the branch. Of course this is is technically a little different than rebasing but i think it is similar enough in usage that it could be referred to as rebasing.

烂人 2024-09-15 19:46:35

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

  1. 对于问题跟踪器中的每个任务 NK-$X,我们都有一个单独的分支 Branches/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 合并到 UPDNK-$Y 中。即 cd UPDNK-$Y; svn merge -r start:HEAD Branches/NK-$X
  5. UPDNK-$Y 准备好后,我们将其合并到 trunk。即 cd trunk;svn merge -r start:HEAD Branches/UPDNK-$Y

如果任务 NK-$X 持续时间超过一个迭代周期,因此需要刷新,我们永远、永远、永远不会将 trunk 合并到 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'

这样,每当您查看 Branches/NK-$X 的变更日志时,您只会看到开发人员实际执行的更改。

更新:
由于上述工作流程可以自动化,因此我在 github 上启动了一个项目:svn rebase

In my company we use following approach:

  1. for each task NK-$X in the issue tracker we have a separate branch branches/NK-$X
  2. we start work on a task by svn cp trunk branches/NK-$X
  3. we never commit changes directly to the trunk. For each schedulled update UPDNK-$X we have a separate branches/UPDNK-$X. We create it with svn cp trunk branches/UPDNK-$X just before the update.
  4. when the task NK-$X is schedulled for an update UPDNK-$Y we merge branches/NK-$X inot UPDNK-$Y. That is cd UPDNK-$Y; svn merge -r start:HEAD branches/NK-$X
  5. after UPDNK-$Y is ready, we merge it to trunk. That is cd trunk;svn merge -r start:HEAD branches/UPDNK-$Y

If it happens that task NK-$X lasts longer than one iteration cycle, and therefore needs refreshing, we never, ever, NEVER merge trunk to NK-$X. We have a rule that you commit to your branch only things that you wrote yourself, which makes everything easier. Instead we do:

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'

This way, whenever you look at the changelog of branches/NK-$X you see only changes actually performed by the developer.

Update:
Since the above workflow can be automated, I've started a project on github: svn rebase.

手心的温暖 2024-09-15 19:46:35

使用 git svn :

git svn clone -s

然后随意使用 git rebase 命令

use git svn:

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

then feel free to use git rebase command

快乐很简单 2024-09-15 19:46:35

我正在使用这种方法:

通过变基,您必须注意在再次合并时不要采用变基修订。在合并时,请进行精挑细选:仅选择功能分支上实现新内容的修订,而不是变基变更集。那么它应该可以正常工作。评论:我不记得曾使用过 reintegrate 分支来做什么。我认为它仅适用于非常简单的用例。

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

I am using this approach:

With rebasing you have to take care not to take the rebased revisions over when you merge again. When it comes to merging, do a cherry picking: select only the revisions on the feature branch that implement something new, not the rebasing changesets. Then it should work fine. COMMENT: I cannot ever remember having used the reintegrate branch for something. I think it is intended for very simple use-cases only.

In your new approach, it is not clear from the description how you handle the rebase from trunk to your feature branches if you need to. Do you want to completely disallow rebasing? As branching in svn is a cheap operation this could be an option too.

笑饮青盏花 2024-09-15 19:46:35

我使用一个脚本,它对 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

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

I use a script that does a git like rebase for 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

It merges revisions from other branch one by one.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文