views:

1064

answers:

3

Hey guys,

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 this: http://www.selenic.com/pipermail/mercurial/2007-June/013393.html

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.

Thanks!!

Jamie

+6  A: 

What is wrong with the 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

VonC
I have looked at the Rebase Extension, but it still isn't clear to me. Could you please explain the steps to do what I have described above?
orange80
@jpswain09: those steps, I believe, are illustrated in http://mercurial.selenic.com/wiki/RebaseProject: `hg pull` followed by `hg rebase`, or `hg pull --rebase` for short.
VonC
+3  A: 

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.

sblom
+12  A: 

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. :)

Ry4an
+1 for the indelible changeset.
VonC
Note: off course, Git does not *exactly* allow you to rewrite history, only to create new one easily (http://utcc.utoronto.ca/~cks/space/blog/tech/GitNewHistory). By adding the RebaseExtension, Mercurial provides the same exact convenient way to replace an old history by a new one. Why? Because a merge is not always the right answer, especially when your changeset should be viewed as *evolutions* on top of F, and not the reverse (P merged on top of O)
VonC
VonC, I agree, a merge isn't always the right choice, but I think the difference in is what one wants one's VCS history to be able to tell them. I think the history should _always_ be able to answer questions like "What was that way I tried to integrate it at first that didn't work out and I thought was useless at the time". Scientists keep logbooks in pen with numbered pages, and AFAIC software engineers should save every byte they've ever typed. Rewriting history, even cset parentage, but certainly CollapseExtension, HistEdit, etc. violate that. It's totally a matter of personal choice.
Ry4an