汞:如何做像git的rebase的rebase


207

在Git中,我可以这样做:

1.开始使用新功能:
$ git co -b newfeature-123#(本地功能开发分支)
进行几次提交(M,N,O)

大师A --- B --- C
                \
newfeature-123 M --- N --- O

2.从上游主服务器获取新更改:
$ git pull
(master更新为ff-commits)

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

3.调整主站的基础,以便使用新功能 
可以针对最新的上游变化进行开发:
(摘自newfeature-123)
$ git rebase master

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


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

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

hg up -CF  
汞分支-f newfeature-123  
汞移植-a -b newfeature-123 

效果还不错,只是它以未合并的头的形式保留了预基准MNO,并创建了3个新提交M',N',O',代表它们从更新的主线分支。

基本上问题是我最终遇到了这个问题:

大师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分支newfeature-123
hg qpush -a
汞qdel -r qbase:qtip

这确实产生了所需的图形:

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

但是这些命令(共6个!)似乎比它们复杂得多。

$ git rebase master

我想知道这是否是等效的汞含量,或者是否有其他类似Git的简单方法。


7
“这不好,因为它留下了应该丢弃的本地,不必要的提交。” -实际上,git做同样的事情。它不会更改或删除原始分支中的提交,它只是使新的提交在master上应用相同的更改集。您仍然可以使用来访问旧的文件git reflog,直到它们被垃圾回收,它们才被完全清除。如果您想将它们保留在命名分支中,从而不必使用reflog,则只需git branch feature-123_original在重新基准化之前这样做。
MatrixFrog 2010年

5
随机问题:您是自己自己绘制变更集/分支的,还是有这样做的工具?
Amir Rachum

2
他们自己只是将TextWrangler设置为“覆盖”。
jpswain 2012年

Answers:


235

VonC可以为您提供答案,即Rebase Extension。但是,值得花一两秒钟的时间来思考为什么默认情况下不启用mq和rebase的原因是Mercurial:因为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的答案。:)


18
注意:当然,Git不能完全允许您重写历史记录,而只是为了轻松创建新历史记录(utcc.utoronto.ca/~cks/space/blog/tech/GitNewHistory)。通过添加RebaseExtension,Mercurial提供了完全相同的便捷方法,用新历史记录替换了旧历史记录。为什么?因为合并并不总是正确的答案,特别是当您的变更集应被视为F之上的演变,而不是反向变化(P合并为O之上)时
VonC

19
VonC,我同意,合并并非总是正确的选择,但是我认为区别在于,人们希望自己的VCS历史能够告诉他们。我认为历史应该总是能够回答诸如“我最初试图将其整合并以失败的方式以为当时我没用的那种方式”这样的问题。科学家们用数字页来记录日志,AFAIC软件工程师应该保存他们曾经键入的每个字节。重写历史记录,甚至是cset的亲戚关系,但肯定是CollapseExtension,HistEdit等违反了这一点。这完全是个人选择的问题。
Ry4an Brase

14
+1供个人选择。因此,对于Git,我将rebase用于琐碎的分歧,将merge用于非琐碎的事。这使我可以保留我认为很重要的合并历史记录,但在大多数情况下都保持日志整洁和线性。
科斯2012年

16
另外,我还会进行大量的交互式rebase,因为我倾向于先做很多小的提交,然后加入,标记和清理它们,然后将它们合并回主分支(或在主分支之上重新设置基础)。我喜欢编码和管理更改是单独的步骤。
科斯2012年

6
“在开发过程中保存每个字节”的理念实际上不适用于大型开源项目,在该项目中,贡献者会提出一组补丁,然后根据维护者的反馈进行修改。然后,最终主项目存储库仅具有所有更改的正确版本,所有相关更改都在一次提交中。git Interactive rebase非常适合将工作更改整理成一系列不会使树折断的提交,并带有反映您在完成全部工作后决定说的内容的提交消息。
彼得·科德斯

104

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

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

替代文字

至:

替代文字


正如下面的评论通过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

1
我已经看过Rebase Extension,但是对我来说仍然不清楚。您能否解释执行上述步骤的步骤?
jpswain 2010年

6
如果您没有拉进更改,并且您的回购中有两个分支,则可以执行以下操作:hg up newfeature-123接下来hg rebase -d master --keepbranches
steprobe,2011年

2
我相信改基没有错,这只是选择问题。问题在于,rebase被滥用了,我使用@ Ry4an来处理此事件,因此不会重写历史记录,因此您可以知道会发生什么情况以及何时发生。
豪尔赫·巴尔加斯

@steprobe:感谢您使用--keepbranches的提示。我喜欢使用hg rebase --source {L1's-sha} --dest {R2's-sha},但是我不知道可以--keepbranches在末尾添加。在其他排名较低的答案中也提到了这一点,但是最好也明确地将其写入此答案。
Mojca,

@Mojca没问题。我已经相应地编辑了答案。
VonC

44

假设您拥有现代化的汞装置,则只需添加:

[extensions]
rebase = 

到〜/ .hgrc。

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


2
只需添加此命令项,然后需要执行的操作将是: hg rebase -s o -d f
Simple-Solution

21

我认为上述答案并没有达到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分支上,并且默认情况下不可见。在不保留任务分支的情况下,我看不到这与合并在功能上有何不同。

更新:我发现了--keepbrancheshg rebase支持的标志,我很高兴地报告一切都是okey-dokey。使用hg rebase -d default --keepbranches,我完全复制了我渴望的Git行为。几个别名以后,我像其他人一样不停地打基础。


7
刚刚在rebase上发现了--keepbranches标志。问题解决了。如果这是我的代码,我会将其设为默认值,但这就是我自己。
乔纳森·布莱克本

1
我认为,如果您在上述答复中添加了一些信息,这将很有用-我花了一段时间才找到它。
HansMari 2013年

3

由于有些人吹嘘说他们认为保留所有内容的每个迭代都是很好的,所以我要指出,对于大型开源项目,接受充满合并和开发迭代的更改将使主线修订历史变得混乱,并使修订历史记录对于查看当前版本的实现方式不太有用。

当提交的更改被未写的人进行审核,然后才被接受时,此方法效果很好,因此,进入主线的更改通常可以调试并正常工作。然后,当您回溯到线的起点时,您会看到与之相关的所有更改,而不是该更改的一部分正在开发的中间。

X265贡献者页解释了如何重新提交了一组正在努力改变的,让他们准备提交到X265的项目。(包括使用TortoiseHG在单个文件中提交部分但不是全部更改,例如git gui的stage / unstage diff hunk进行提交)。

该过程是将hg更新到上游技巧,然后将所有更改未提交到工作目录中。搁置所有不属于您要提交的内容的内容,然后将其余内容分成许多适当的单独提交,并附上漂亮的提交消息。

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.