Mercurial move changes to a new branch - mercurial

I have a number of changes that I committed to my local repository, but have not yet been pushed. Since on a feature is taking longer than expected, I want to swap these changes onto a named branch before I push. How can I do this?

As suggested by Mark, the MqExtension is one solution for you problem. IMHO a simpler workflow is to use the rebase extension. Suppose you have a history like this:
# changeset: 2:81b92083cb1d
| tag: tip
| summary: my new feature: edit file a
|
o changeset: 1:8bdc4508ac7b
| summary: my new feature: add file b
|
o changeset: 0:d554afd54164
summary: initial
This means, revision 0 is the base on which you started to work on your feature. Now you want to have revisions 1-2 on a named branch, let's say my-feature. Update to revision 0 and create that branch:
$ hg up 0
$ hg branch my-feature
$ hg ci -m "start new branch my-feature"
The history now looks like this:
# changeset: 3:b5939750b911
| branch: my-feature
| tag: tip
| parent: 0:d554afd54164
| summary: start new branch my-feature
|
| o changeset: 2:81b92083cb1d
| | summary: my new feature: edit file a
| |
| o changeset: 1:8bdc4508ac7b
|/ summary: my new feature: add file b
|
o changeset: 0:d554afd54164
summary: initial
Use the rebase command to move revisions 1-2 onto revision 3:
$ hg rebase -s 1 -d 3
This results in the following graph:
# changeset: 3:88a90f9bbde7
| branch: my-feature
| tag: tip
| summary: my new feature: edit file a
|
o changeset: 2:38f5adf2cf4b
| branch: my-feature
| summary: my new feature: add file b
|
o changeset: 1:b5939750b911
| branch: my-feature
| summary: start new branch my-feature
|
o changeset: 0:d554afd54164
summary: initial
That's it .. as mentioned in the comments to Mark's answer, moving around already pushed changesets generally is a bad idea, unless you work in a small team where you are able to communicate and enforce your history manipulation.

You can use the MqExtension. Let's say the changesets to move are revisions 1-3:
hg qimport -r 1:3 # convert revisions to patches
hg qpop -a # remove all them from history
hg branch new # start a new branch
hg qpush -a # push them all back into history
hg qfin -a # finalize the patches

I prefer the patch solution describe here by Mark Tolonen
What I have:
hg log -G
#default branch
# changeset: 3:cb292fcdbde1
|
o changeset: 2:e746dceba503
|
o changeset: 1:2d50c7ab6b8f
|
o changeset: 0:c22be856358b
What I want:
# changeset: 3:0e85ae268e35
| branch: feature/my_feature
|
o changeset: 2:1450cb9ec349
| branch: feature/my_feature
|
o changeset: 1:7b9836f25f28
| branch: feature/my_feature
|
/
|
o changeset: 0:c22be856358b
mercurials commands:
hg export -o feature.diff 1 2 3
hg update 0
hg branch feature/my_feature
hg import feature.diff
Here is the state of my local repository
# changeset: 6:0e85ae268e35
| branch: feature/my_feature
|
o changeset: 5:1450cb9ec349
| branch: feature/my_feature
|
o changeset: 4:7b9836f25f28
| branch: feature/my_feature
|
| o changeset: 3:cb292fcdbde1
| |
| o changeset: 2:e746dceba503
| |
| o changeset: 1:2d50c7ab6b8f
|/
|
o changeset: 0:c22be856358b
Now I need to delete the revisions 1 2 and 3 from my default branch.
You can do this with strip command from mq's extension.
hg strip removes the changeset and all its descendants from the repository.
Enable the extension by adding following lines to your configuration file (.hgrc or Mercurial.ini):
vim ~/.hgrc and add :
[extensions]
mq =
And now strip this repository on revision 1.
hg strip 1
and here we are
# changeset: 3:0e85ae268e35
| branch: feature/my_feature
|
o changeset: 2:1450cb9ec349
| branch: feature/my_feature
|
o changeset: 1:7b9836f25f28
| branch: feature/my_feature
|
o changeset: 0:c22be856358b
note: changesets are different but revisions are the same

For those inclined to use GUI
Go to Tortoise Hg -> File -> Settings then tick rebase .
Restart tortoise UI
Create new branch where you will be moving changes. Click on current branch name -> choose Open a new named branch -> choose branch name.
If changes you want to move have not been made public (e.g draft) go to 5. (If changes have already been published and you are not a senior dev you should talk to someone senior (get a scapegoat) as you might screw things up big time, I don't take any responsibility :) ).
Go to View -> Show Console (or Ctrl + L)
then write in console hg phase -f -d 2 - where 2 is lowest revision you will be moving to new branch.
Go to branch and revision (should be topmost revision if you are moving changes to new branch created in step 3.) Right Mouse -> Update
Go to branch and revsion you will be moving changes from Right Mouse -> Modify History -> Rebase
Click Rebase and pray there are no conflicts, merge if you must.
Push changes, at this point all revisions should still be draft.
Go to topmost revision in branch you were moving changes to Right Mouse -> Change Phase to -> Public.
Hope this saves you some time.

Related

How do I update to the last public revision in my repository?

o 911e74cd 44 minutes ago master
|
| # f085ae95 3 minutes ago
| | Testing
| |
| o 4431b579 Today at 11:24
|/ Feature
|
o 4ab195c4 Today at 04:59
I am currently on revision f085ae95 and I would like to use one hg update command to get to 4ab195c4, which is the last ancestor that is on the public branch in the repository.
You can literally do:
hg update 4431b579
and that should work.
This will update the files in your working folder to whatever state they had in the referenced changeset.
You could also use:
hg up -r -2
to go back 2 revisions from the working folder, which I think would do the same thing.
hg log -r "last(public() and ancestors(.))" --template "{node}" will print out the hash of the last commit on the public branch that is also an ancestor of the current commit. As such you can now chain command calss via:
hg update `hg log -r "last(public() and ancestors(.))" --template "{node}"`
or
hg rebase -s `<commit-you-want-to-rebase>` -d `hg log -r "last(public() and ancestors(.))" --template "{node}"`

How to hg bundle only changes in a branch?

I have tried this:
$ hg bundle -b my-branch ../my-branch-bundle.hg
searching for changes
no changes found
Then this:
$ hg bundle --all --branch my-branch ../my-branch-bundle.hg
7191 changesets found
... but my branch has only 3 commits? Then also this:
$ hg bundle --base null --branch my-branch ../my-branch-bundle.hg
7191 changesets found
How to hg bundle only the changes for a given branch?!
hg bundle bundles each specified revision (-r) and assumes the destination repository has all the revisions (and their ancestors) specified by the --base option.
So one way to get only a small branch of 3 changesets is to specify with --base the first changeset branched from, and specify of the first changeset of the branch and its descendants.
For example, given:
o changeset: 5:f429f686e698
| branch: test
|
o changeset: 4:e02923c7302b
| branch: test
|
o changeset: 3:076f442d4d3b
| branch: test
|
| # changeset: 2:dab4279642cb
|/
o changeset: 1:233d09b80d63
|
o changeset: 0:6818527e85ac
Use:
hg bundle --base 1 --rev heads(descendants(3))

Hg command to get the file content without switching branch

In HG, is there any command such that i can get the file content of the file from another branch without switching/checkout to the particular branch?
Similar to the other answer, you can use the cat command but in a slightly different way:
hg cat --rev=11204 path/to/file
This will pick the file from revision #11204 which can be any branch.
You may want to add the --output switch lets you use whatever filename and/or location you want:
hg cat --output=C:/new/path/to/file/filename#11204.ext --rev=11204 path/to/file
If you are using TortoiseHG, you can use the "save at revision" command to do this.
Steps:
Run Tortoise Workbench
Find the changeset in history which has the file revision you want (could be in any branch)
Say its changeset #abcd1234
Right click on the specific file in the file list for that changeset
Select "Save at revision..." and tell it where to put the file.
The file would typically be named filename#abcd1234.ext so that you don't mix it up with the current version.
Use the cat subcommand with the revision number of the commit you're looking for.
Here's an example. I create two branches with the contents of the file file indicating which branch it's on. Then I use cat to examine the contents on both branches
% hg init foo
% cd foo
% echo "default branch" > file
% hg add file
% hg ci -m 'default' file
% echo "default 2nd rev" > file
% hg ci -m 'default 2nd rev' file
% hg glog
# changeset: 1:305b2b5ccbd9
| tag: tip
| user: dj
| date: Mon Sep 17 14:11:20 2018 -0400
| summary: default 2nd rev
|
o changeset: 0:6d22c68d8abc
user: dj
date: Mon Sep 17 14:10:56 2018 -0400
summary: default
% hg co -r 0
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
% echo "new branch" > file
% hg branch 'new branch'
marked working directory as branch new branch
(branches are permanent and global, did you want a bookmark?)
% hg ci -m 'new branch'
% hg glog
# changeset: 2:4c8d2181526c
| branch: new branch
| tag: tip
| parent: 0:6d22c68d8abc
| user: dj
| date: Mon Sep 17 14:12:30 2018 -0400
| summary: new branch
|
| o changeset: 1:305b2b5ccbd9
|/ user: dj
| date: Mon Sep 17 14:11:20 2018 -0400
| summary: default 2nd rev
|
o changeset: 0:6d22c68d8abc
user: dj
date: Mon Sep 17 14:10:56 2018 -0400
summary: default
% hg branches
new branch 2:4c8d2181526c
default 1:305b2b5ccbd9
% hg cat -r 2 file
new branch
% hg cat -r 1 file
default 2nd rev

Is there another way of removing multiple heads?

Let's say I have this:
hg init
touch a
hg add a
hg commit -m a
touch b
hg add b
hg commit -m b
hg up -r 0
touch c
hg add c
hg commit -m c
Now I will have multiple heads, because of the last commit. If, for example I want to keep the last head, the one created by commit c ( effectively discarding b, and all other commits made after the first ) , how could I do it? I played a little with mq's strip command, and I'm able to achieve what I want, but I'd like to know if there's another way.
Yes, there is another way. From your example above, the output of hg glog looks a bit like this:
# changeset: 2:925573c7103c
| tag: tip
| parent: 0:4fe26dfe856d
| user: Joel B Fant
| date: Thu Jul 28 23:20:45 2011 -0400
| summary: c
|
| o changeset: 1:9dc928176506
|/ user: Joel B Fant
| date: Thu Jul 28 23:20:24 2011 -0400
| summary: b
|
o changeset: 0:4fe26dfe856d
user: Joel B Fant
date: Thu Jul 28 23:20:12 2011 -0400
summary: a
If you clone test but specify a revision, it will only clone that revision and its ancestors. So if your repo's directory is TwoHeadsMightNotBeBetter, you can go to its parent directory and issue:
hg clone TwoHeadsMightNotBeBetter OneHeadIsFine -r 925573c7103c
I specified changeset id in that, but you could also use -r 2 instead, or even -r tip since it is currently the tip of that repo. Now when you go into the new clone and do hg glog, you have only one head:
# changeset: 1:925573c7103c
| tag: tip
| user: Joel B Fant
| date: Thu Jul 28 23:20:45 2011 -0400
| summary: c
|
o changeset: 0:4fe26dfe856d
user: Joel B Fant
date: Thu Jul 28 23:20:12 2011 -0400
summary: a
If you had 3 heads and wanted to keep 2, it would be a little different. You'd have to clone one of them with -r and the also specify -r on hg pull to pull specific branches.
You can also perform a dummy merge of the changeset containing b (changeset 1 in this case):
$ hg --config ui.merge=internal:fail merge 1
resolving manifests
getting b
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg revert --all --no-backup --rev .
removing b
$ hg status
R b
$ hg commit -m "Dummy merge -- eliminate b"
committed changeset 3:c163151f19df
$ ls
a c
Note that in this case you haven't rewritten any history or created any new repos -- particularly important if b had already been pushed to a centralized repo and pulled by others.

Splicing over discontinuities in Mercurial repository timeline

I converted a Subversion repository to Mercurial a few months back and I wound up leaving two meaningless gaps in my revision history. I'm trying to figure out if I can just splice over the gaps, but I haven't been able to get the tools to do precisely what I want.
I had reorganized the Subversion repo twice in the early days of the project: first to convert a single project root to trunk/branches/tags layout, and then to add a second related project in a second root folder with it's own trunk/branches/tags.
By the time I decided to switch to Mercurial there had been no significant development activity outside of the trunk of the first, original project. I was able to use the Mercurial conversion utilities and path mapping to reassemble a single sensible trunk in the new Mercurial repository, or so I thought.
Now I realize that I have two extra heads, each corresponding to where the change history essentially starts over:
r0 ... r16 | (r17) r18 ... r61 | (r62) r63 ... tip
The results of the two revisions after the breaks, r17 and r62, are identical in content to the corresponding revision before the breaks -- they consist entirely of file add operations with exactly the same contents as the previous revisions. Meaningful changes only start at the next revisions (r18 and r63 respectively).
I've messed with the Mercurial Transplant extension in an attempt to splice over r17 and r62, but it winds up concatenating the spliced changesets all the way at the tip of the default branch (r405 at this point).
These extra heads are not really hurting my development activities, so I've let it go for a while. What's pushing me to resolve this is that MercurialEclipse complains about these extra heads every time I pull from my remote repository.
Can anyone offer any advice on how to approach this? Am I just getting the command flags wrong, or am I using the wrong tool? Should I be using the Rebase extension instead? What about some sort of dump-edit dumpfile-reload process that we all used to do with Subversion?
While I've published the project to my development server, there are only a couple of clones out there, so destroying those copies and recloning shouldn't be a big deal.
The extension commands rebase and collapse should do the trick. Consider the following small repository as an example:
$ hg glog -p
o changeset: 3:bc701d12d956
| tag: tip
| summary: hack
|
| diff --git a/file b/file
| --- a/file
| +++ b/file
| ## -1,1 +1,1 ##
| -hello world
| +hello big world
|
o changeset: 2:2bb8c95d978e
parent: -1:000000000000
summary: history breaking svn reorganization
diff --git a/file b/file
new file mode 100644
--- /dev/null
+++ b/file
## -0,0 +1,1 ##
+hello world
# changeset: 1:b578b2ec776b
| summary: hack
|
| diff --git a/file b/file
| --- a/file
| +++ b/file
| ## -1,1 +1,1 ##
| -hello
| +hello world
|
o changeset: 0:c3d20f0b7072
summary: initial
diff --git a/file b/file
new file mode 100644
--- /dev/null
+++ b/file
## -0,0 +1,1 ##
+hello
It basically resembles your situation, i.e. there are two unrelated lines of history, where the first revision of the second line (r2) is a plain add of everything present at the last revision of the first line (r1).
You can put the second line onto the first one with rebase:
$ hg rebase -s 2 -d 1
$ hg glog
# changeset: 3:020d1b20caa8
| summary: hack
|
o changeset: 2:2a44eb4b74c3
| summary: history breaking svn reorganization (empty changeset now)
|
o changeset: 1:b578b2ec776b
| summary: hack
|
o changeset: 0:c3d20f0b7072
summary: initial
As you see, the two lines have been joined. Revision 2 now is an obsolete empty changeset. You can get rid of it by using the collapse command to combine revisions 1 and 2:
$ hg collapse -r 1:2
<edit commit message>
$ hg glog -p
# changeset: 2:d283fe96a5e6
| tag: tip
| summary: hack
|
| diff --git a/file b/file
| --- a/file
| +++ b/file
| ## -1,1 +1,1 ##
| -hello world
| +hello big world
|
o changeset: 1:c486d8191bf0
| summary: hack
|
| diff --git a/file b/file
| --- a/file
| +++ b/file
| ## -1,1 +1,1 ##
| -hello
| +hello world
|
o changeset: 0:c3d20f0b7072
summary: initial
diff --git a/file b/file
new file mode 100644
--- /dev/null
+++ b/file
## -0,0 +1,1 ##
+hello
Now the unrelated lines of history are joined in a meaningful way.