0

Suppose I have a revision history with no branching like this:

1
2
3
4

Now I want to create a new branch in my repository with revision 1 and 3, but not revision 2 or 4. There are no conflicting updates in revisions 2/3. Is there a way to do this. My final repository should have two branches like this:

4
3
2  3
| /
|/
1    
alexis
  • 48,685
  • 16
  • 101
  • 161
just.another.programmer
  • 8,579
  • 8
  • 51
  • 90

3 Answers3

3

If you have already published this repo to a public location (or any developer has cloned your repo), you can do this with a combination of graft and backout.

The graft command will copy a commit from one branch to another. The backout command will reverse the changes made by an earlier commit.

The following example should replicate your situation:

hg init test
echo test>>test\test.txt && hg -R test ci -Am "baseline"
echo test>>test\test.txt && hg -R test ci -Am "changeset 1"
echo test>>test\test.txt && hg -R test ci -Am "changeset 2"
echo new>>test\new.txt   && hg -R test ci -Am "changeset 3"
echo test>>test\test.txt && hg -R test ci -Am "changeset 4"
hg -R test backout -r 3
hg -R test ci -m "backed out changeset 3"
hg -R test update -r 1
hg -R test graft -r 3
hg -R test glog --template "{desc}\n"

This creates a new anonymous branch with the changes you wanted and also removes the changes in rev 3 from the original branch without modifying the history of your repository.

This results in the following log:

@  changeset 3
|
| o  backed out changeset 3
| |
| o  changeset 4
| |
| o  changeset 3
| |
| o  changeset 2
|/
o  changeset 1
|
o  baseline
Tim Henigan
  • 60,452
  • 11
  • 85
  • 78
  • @LazyBadger: I've updated my answer...can you explain your objection in more detail? I don't understand what you mean by "backout is just from another story". – Tim Henigan Nov 16 '12 at 16:39
  • I can't show `glog` in comment, but I tested - you'll got another tree, than rewritten by OP request: backout create additional commit – Lazy Badger Nov 16 '12 at 17:49
  • While it is true that backout creates an additional commit, it does not create another tree. It simply creates a new commit that reverses the changes. The result is the same. Also, this is the only method that works without rewriting repo history (important for shared projects). – Tim Henigan Nov 16 '12 at 17:51
  • Not backout, but **your sequence of commands**. Do you want to see full output of your commands-set? – Lazy Badger Nov 16 '12 at 17:53
  • I'll save you the effort. A test script and output are now included in the example. – Tim Henigan Nov 16 '12 at 18:20
2

Because you said nothing about named branch, we work with anonymous branching

Before:

>hg glog --template "{rev}:{desc}\n"
@  3:Added d.txt
|
o  2:Added c.txt
|
o  1:Added b.txt
|
o  0:Initial commit

>hg rebase -s 2 -d 0

>hg glog --template "{rev}:{desc}\n"

@  3:Added d.txt
|
o  2:Added c.txt
|
| o  1:Added b.txt
|/
o  0:Initial commit

>hg rebase -s 3 -d 1

>hg glog --template "{rev}:{desc}\n"
@  3:Added c.txt
|
| o  2:Added d.txt
| |
o |  1:Added b.txt
|/
o  0:Initial commit

In case of named branch you have to hg branch BRANCHNAME and hg ci -m "Creating branch" before first rebase, use -d 4 in rebase instead of 0

Lazy Badger
  • 94,711
  • 9
  • 78
  • 110
  • 2
    Definitely worth throwing in the warning that if you've already pushed this repo somewhere then it's too late to rebase. – Ry4an Brase Nov 16 '12 at 21:44
  • @Ry4an: Phases obsoleted such warning – Lazy Badger Nov 17 '12 at 07:54
  • Most people still aren't running builds with phases. I'll leave the warning. – Ry4an Brase Nov 18 '12 at 12:30
  • It's not that simple! You don't show the descendants of rev 3, but they will move along with it when you rebase. So you also have to rebase rev 4 back onto rev 2. And if the surrounding history is non-linear, you have to tread really carefully. – alexis Nov 27 '12 at 20:55
  • @alexis - I **have not** descendants of rev 3, totally. I copy-paste full output of real repo, without editiing. In case of more long history - yes, it will be more long dances and more chances for MQ – Lazy Badger Nov 27 '12 at 21:27
  • I see that you don't, but the OP wanted to cherry-pick 3 and leave 2 and 4 behind. So the fate of descendants is relevant, but missing from your nice explanation. – alexis Nov 27 '12 at 21:32
0

From your comments, it sounds like you're trying to accomplish what's called "cherrypicking": Selectively copy some changesets to another branch, without treating them as a merge. If that's correct, you can do it by first creating an ordinary branch off revision one, then grafting onto it the changesets you want to copy. The command hg graft is designed for this purpose.

Here's how it would work with a named branch, selective. If you want unnamed branches, just omit the branch creation.

hg update -r 1
hg branch selective
hg graft -r 3

The result will look like this (which, I hope, is what you wanted):

4
|
3
|  5 = 3
2 /
|/
1
|
0

By default, graft will copy user, date, and description from the source changeset(s). The new revision will have identical effects to revision 3, but will have a new numeric and hash id. Mercurial will not be aware of the relationship between revisions 3 and 5.

There's no way to selectively import some changesets and treat the operation as a merge: Merging always unifies the complete (linear) history up to the point being merged.

alexis
  • 48,685
  • 16
  • 101
  • 161