Hg:如何像 git 的 rebase 一样进行 rebase

发布于 2024-08-30 04:57:15 字数 1684 浏览 4 评论 0原文

在 Git 中我可以这样做:

1. Start working on new feature:
$ git co -b newfeature-123  # (a local feature development branch)
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream master:
$ git pull
(master updated with ff-commits)

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. Rebase off master so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ git rebase master

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O


我想知道如何在 Mercurial 中做同样的事情,并且我在网上搜索了答案,但我能找到的最好的答案是:git rebase - hg 可以做到这一点

该链接提供了 2 个示例:
1. 我承认这一点:(将示例中的修订替换为我自己示例中的修订)

hg up -C F  
hg branch -f newfeature-123  
hg transplant -a -b newfeature-123 

并不算太糟糕,只是它留下了预变基 MNO 作为未合并的头并创建了 3 个新提交 M', N',O' 代表他们从更新的主线分支出来。

基本上问题是我最终会得到这样的结果:

master A---B---C---D---E---F
                \           \
newfeature-123   \           M'---N'---O'
                  \
newfeature-123     M---N---O

这不好,因为它留下了应该删除的本地不需要的提交。

  1. 同一链接中的另一个选项是
hg qimport -r M:O
hg qpop -a
hg up F
hg branch newfeature-123
hg qpush -a
hg qdel -r qbase:qtip

,这确实会产生所需的图表:

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O

复杂得多

$ git rebase master

但是这些命令(全部 6 个!)看起来比我想知道这是否是 Hg 中唯一等效的命令或者是否有一些命令 其他可用的方法也很简单,例如 Git。

In Git I can do this:

1. Start working on new feature:
$ git co -b newfeature-123  # (a local feature development branch)
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream master:
$ git pull
(master updated with ff-commits)

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. Rebase off master so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ git rebase master

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O

I want to know how to do the same thing in Mercurial, and I've scoured the web for an answer, but the best I could find was: git rebase - can hg do that

That link provides 2 examples:
1. I'll admit that this: (replacing the revisions from the example with those from my own example)

hg up -C F  
hg branch -f newfeature-123  
hg transplant -a -b newfeature-123 

is not too bad, except that it leaves behind the pre-rebase M-N-O as an unmerged head and creates 3 new commits M',N',O' that represent them branching off the updated mainline.

Basically the problem is that I end up with this:

master A---B---C---D---E---F
                \           \
newfeature-123   \           M'---N'---O'
                  \
newfeature-123     M---N---O

this is not good because it leaves behind local, unwanted commits that should be dropped.

  1. The other option from the same link is
hg qimport -r M:O
hg qpop -a
hg up F
hg branch newfeature-123
hg qpush -a
hg qdel -r qbase:qtip

and this does result in the desired graph:

master A---B---C---D---E---F
                            \
newfeature-123               M---N---O

but these commands (all 6 of them!) seem so much more complicated than

$ git rebase master

I want to know if this is the only equivalent in Hg or if there is some other way available that is simple like Git.

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

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

发布评论

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

评论(5

岁月苍老的讽刺 2024-09-06 04:57:15

VonC 有您正在寻找的答案< /a>,变基扩展。然而,值得花一两秒钟思考一下为什么在 Mercurial 中默认情况下既不启用 mq 也不启用 rebase:因为 Mercurial 都是关于不可消除的变更集的。当我按照你所描述的方式工作时(几乎每天都是如此),这就是我采取的模式:

1. Start working on a new feature:
$ hg clone mainline-repo newfeature-123
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream mainline:
$ hg pull

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. merge master into my clone so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ hg merge F

master A---B---C---D---E---F
                \           \
newfeature-123   M---N---O---P

这确实是所需要的。我最终得到了一个 newfeature-123 克隆,当我对它感到满意时,我可以轻松地推回主线。然而,最重要的是,我从未改变过历史。有人可以查看我的 cset,看看它们最初是针对什么进行编码的,以及我在整个工作中对主线变化的反应。并不是每个人都认为这有价值,但我坚信,源代码控制的工作不是向我们展示我们希望发生的事情,而是实际发生的事情 - 每个死胡同和每个重构都应该留下不可磨灭的痕迹,并且重新定位和其他历史编辑技术隐藏了这一点。

现在我收起我的演讲台,去挑选 VonC 的答案。 :)

VonC has the answer you're looking for, the Rebase Extension. It is, however, worth spending a second or two thinking about why neither mq nor rebase are enabled by default in mercurial: because mercurial is all about indelible changesets. When I work in the manner you're describing, which is nearly daily, here's the pattern I take:

1. Start working on a new feature:
$ hg clone mainline-repo newfeature-123
do a few commits (M, N, O)

master A---B---C
                \
newfeature-123   M---N---O

2. Pull new changes from upstream mainline:
$ hg pull

master A---B---C---D---E---F
                \
newfeature-123   M---N---O

3. merge master into my clone so that my new feature 
can be developed against the latest upstream changes:
(from newfeature-123)
$ hg merge F

master A---B---C---D---E---F
                \           \
newfeature-123   M---N---O---P

and that's really all that's necessary. I end up with a newfeature-123 clone I can easily push back to the mainline when I'm happy with it. Most importantly, however, I never changed history. Someone can look at my csets and see what they were originally coded against and how I reacted to changes in the mainline throughout my work. Not everyone thinks that has value, but I'm a firm believer that it's the job of source control to show us not what we wished had happened, but what actually happened -- every deadend and every refactor should leave an indelible trace, and rebasing and other history editing techniques hide that.

Now go pick VonC's answer while I put my soapbox away. :)

多情出卖 2024-09-06 04:57:15

您可能正在寻找Rebase 扩展。 (作为 SummerOfCode 2008 的一部分实施)

在这些情况下,“分离”本地更改、将存储库与主流同步,然后将私有更改附加到新的远程更改之上可能会很有用。这个操作称为变基。

来源

alt text

到:

alt text


作为 评论如下steprobe

如果您没有拉取更改,并且您的存储库中有两个分支,您可以执行以下操作(使用 keepbranches):

hg up newfeature-123 
hg rebase -d master --keepbranches

(--keepbranches:继承原来的分支名称。)

Mojca 提到:

我喜欢使用 hg rebase --source {L1's-sha} --dest {R2's-sha},但我不知道我可以添加 --keepbranches > 在最后。

正如如下所示,作者:乔纳森·布莱克本

 hg rebase -d default --keepbranches

You might be looking for Rebase Extension. (implemented as part of the SummerOfCode 2008)

In those cases it can be useful to "detach" the local changes, synchronize the repository with the mainstream and then append the private changes on top of the new remote changes. This operation is called rebase.

Getting from:

alt text

to:

alt text


As commented below by steprobe:

In the case where you aren't pulling the changes in, and you have the two branches in your repo, you can do (using keepbranches):

hg up newfeature-123 
hg rebase -d master --keepbranches

(--keepbranches: Inherit the original branch name.)

Mojca mentions:

I like using hg rebase --source {L1's-sha} --dest {R2's-sha}, but I didn't know I could add --keepbranches at the end.

As illustrated below by Jonathan Blackburn:

 hg rebase -d default --keepbranches
合久必婚 2024-09-06 04:57:15

假设您安装了现代 Hg,您只需将:

[extensions]
rebase = 

添加到 ~/.hgrc 即可。

然后您可以使用命令 hg rebasehg pull --rebasehg help rebase

Assuming you have a modern Hg installation, you can simply add:

[extensions]
rebase = 

to ~/.hgrc.

Then you can use the commands hg rebase, hg pull --rebase, or hg help rebase.

太傻旳人生 2024-09-06 04:57:15

我认为上面的答案没有实现OP的目标,即维护他的任务分支,只是根据父分支上的稍后点进行重新调整。

假设我从这张图开始(使用 graphlog 扩展生成。极客非常喜欢 graphlog)。

@  9a4c0eb66429 Feature 3 commit 2 tip feature3
|
| o  af630ccb4a80 default againagainagain  
| |
o |  98bdde5d2185 Feature 3 branch commit 1  feature3
|/
o  e9f850ac41da foo   

如果我位于 feature3 分支上并且想要将其重新设置为再次提交,我知道我将运行 hg rebase -d default。这会产生以下结果:

@  89dada24591e Feature 3 commit 2 tip 
|
o  77dcce88786d Feature 3 branch commit 1  
|
o  af630ccb4a80 default againagainagain  
|
o  e9f850ac41da foo  

任务完成了吗?我不这么认为。问题是,当 feature3 分支上的提交再次重新基于时,feature3 分支被删除。我的提交已移至默认分支,这是我首先试图避免的。

在 Git 中,结果如下所示:

@  9a4c0eb66429 Feature 3 commit 2 tip
|
o  98bdde5d2185 Feature 3 branch commit 1 **feature3**
|
o  af630ccb4a80 default againagainagain
|
o  e9f850ac41da foo

请注意,feature3 分支仍然存在,两个提交仍然位于 feature3 分支上,并且默认情况下不可见。如果不保留任务分支,我看不出这在功能上与合并有何不同。

更新:我发现了 hg rebase 支持的 --keepbranches 标志,我很高兴地报告一切都很好。使用 hg rebase -d default --keepbranches,我完全复制了我渴望的 Git 行为。几个别名之后,我就像没人管事一样重新定位。

I don't think the answers above achieve the OP's goal, which was to maintain his task branch, just rebased against a later point on the parent branch.

Let's say I start with this graph (generated using the graphlog extension. Serious geek love for graphlog).

@  9a4c0eb66429 Feature 3 commit 2 tip feature3
|
| o  af630ccb4a80 default againagainagain  
| |
o |  98bdde5d2185 Feature 3 branch commit 1  feature3
|/
o  e9f850ac41da foo   

If I'm on the feature3 branch and want to rebase it off of the againagainagain commit, I understand that I would run hg rebase -d default. This has the following result:

@  89dada24591e Feature 3 commit 2 tip 
|
o  77dcce88786d Feature 3 branch commit 1  
|
o  af630ccb4a80 default againagainagain  
|
o  e9f850ac41da foo  

Mission accomplished? I don't think so. The problem is that when the commits on the feature3 branch were rebased on againagainagain, the feature3 branch was deleted. My commits have been moved to the default branch, which was what I was trying to avoid in the first place.

In Git, the result would look like this:

@  9a4c0eb66429 Feature 3 commit 2 tip
|
o  98bdde5d2185 Feature 3 branch commit 1 **feature3**
|
o  af630ccb4a80 default againagainagain
|
o  e9f850ac41da foo

Notice that the feature3 branch still exists, the two commits are still on the feature3 branch, and not visible on default. Without preserving the task branch, I don't see how this is functionally different from a merge.

UPDATE: I discovered the --keepbranches flag supported by hg rebase, and I'm happy to report everything is okey-dokey. Using hg rebase -d default --keepbranches, I exactly replicate the Git behavior I craved. A couple of aliases later and I'm rebasing like nobody's business.

巷雨优美回忆 2024-09-06 04:57:15

由于有些人插话说他们认为保留所有内容的每次迭代是件好事,因此我将指出,对于较大的开源项目,接受充满合并和开发迭代的更改将导致混乱的主线修订历史记录,并使得修订历史记录对于了解当前版本如何到达那里不太有用。

当提交的更改在被接受之前由未编写更改的人进行审查时,这种方法效果很好,因此进入主线的更改通常会被调试并工作。然后,当您回溯到一条线的原点时,您会看到与之相关的所有变化,而不是它所属的变化发展过程中的某个点。

x265 贡献者页面解释了如何重新提交您所做的一组更改我们正在努力让它们做好提交到 x265 项目的准备。 (包括使用 TortoiseHG 提交单个文件中的一些但不是全部更改,例如用于提交的 git gui 的 stage/unstage diff hunk)。

该过程是将 hg 更新到上游提示,然后在工作目录中获取所有未提交的更改。搁置不属于您要提交的内容的任何内容,然后将其余内容分解为适当的多个单独提交,并带有良好的提交消息。

我想您会复制/粘贴,然后编辑您正在修订的补丁集的先前迭代中的提交消息。或者你可以嫁接旧的提交(git 语言中的cherry-pick),然后一一修改它们,以获取旧的提交消息作为编辑的起点。

Since some people have chimed in saying they think it's good to keep every iteration of everything, I'll point out that for larger open-source projects, accepting changes full of merges and development iteration would make for a messy mainline revision history, and make the revision history less useful for seeing how the current version got there.

This works well when submitted changes are reviewed by people that didn't write them, before they're accepted, so changes that do go into the mainline are generally debugged and working. Then when you backtrack to the origin of a line, you see all the changes that go with it, not some point in the middle of development of the change it's part of.

The x265 contributors page explains how to re-commit a set of changes you're working on, to get them ready for submission to the x265 project. (Including use of TortoiseHG to commit some but not all changes in an individual file, like git gui's stage/unstage diff hunk for commit).

The process is to get hg updated to the upstream tip, and then get all your changes uncommitted in the working directory. Shelve any that aren't part of what you want to submit, then break the rest into as many separate commits are appropriate, with nice commit messages.

I guess you'd copy/paste and then edit commit messages from previous iterations of a patchset that you're revising. Or maybe you could graft your old commits (cherry-pick in git language), and then amend them one by one, to get your old commit messages as a start point for editting.

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