Converting a Mercurial branch into the same repository, but different branch - mercurial

We are faced with a situation where we are maintaining two code bases in the same repository. The folder structure looks like this:
/WebRoot/
In our default branch the /WebRoot/ is very different from the /WebRoot/ in the Stable branch. The goal is to move /WebRoot/ from the Stable branch to /WebRoot/ in default branch. And the current default /WebRoot/ will become /WebRootX/. So in the end, all code will be in default and we won't have to switch back and forth between default and Stable branches when making changes in the two different code bases.
| | |
| | |
| --------
| | QA
| |
-------|
| Stable
|
default
I'm thinking that we have to use hg convert to move the Stable code out to a different (temp) repository. Then rename the default WebRoot to WebRootX. Then import the Stable /WebRoot/ folder back in.
I have done several tests and I'm not getting the desired results. I have tried using hg convert with the branchmap ("Stable default") to get the Stable branch out to a temp repository, but that's not working. I'm seeing code from default in there.
What is the best way to accomplish this?

Before trying anything below first back up your repo.
Now you can try this: in the default branch, rename WebRoot to WebRootX. Commit this change.
Still in the default branch, merge in the stable branch using the internal:fail merge tool (what git calls a merge strategy):
hg merge --tool internal:fail stable
At this point, your working copy is in a state that, if committed, Mercurial will accept as a successful merge. But before you commit, you want to tell Mercurial to revert the entire WebRoot directory structure to its state in the stable branch, while at the same time not reverting anything that in the WebRootX directory structure:
hg revert --all -r stable -IWebRoot* -XWebRootX*
At this point you should have the WebRootX directory structure as it was in the default branch, while at the same time having the WebRoot directory structure as it was in the stable branch, and also preserving both their histories.
I have to warn you though I just roughly tested this out in a dummy repo and I'm not sure what results you'll get in a 'real' repo.
Some ideas from here.

Related

how do I push most recent commit in HG

I have done some local commits.
But I want to push the most recent ones like 4977 and 4978 excluding the previous ones.
4948 local commit 1 is the ancestor of all commits
Can some one tell how do we do that in HG
4978 local commit 4
|
|
|
4977 local commit 3
|
|
|
4976 local commit 2
|
|
|
4948 local commit 1
Mercurial repositories are intended to have immutable histories, so out of the box this is not possible. However, there are workarounds for this.
Possibly the easiest way to achieve this would be with the histedit extension. You would need to enable it by modifying your .hgrc (or mercurial.ini) with the following
[extensions]
histedit =
Then you can run the histedit subcommand from the command line and tell it to look back as far as the changeset you're concerned about...
hg histedit 4948
This will pop up a text editor with the word pick next to each changeset. Change pick to drop for the changeset you don't want any more, save, and exit, and the problem changeset will be gone.
Note that this will remove the changeset from your local repo, in addition to prevent it being pushed to the remote!
You cannot push a commit with out pushing all the ancestor commits as well. However, you can "fold"/"collapse"/"squash" commits together to get rid of the ancestor commits you don't like. You use the standard histedit extension for this.
Simply run
$ histedit 4948
and you will see an editor open up. That edit contains a file that will serve as the instructions for histedit. By default all changesets are left unchanged, but you can change the keyword at the beginning of the lines to change this. Also, you can reorder the lines to reorder the corresponding commits.
Changing the keyword in the beginning of a line to fold will tell histedit to combine the commit with the previous commit. That way you can change your history to
4978 local commit 4
|
|
|
4977 local commit 3
|
|
|
4948 local commit 1
and thus "fold" the changes you made in your local commit 2 into local commit 3.

How to revert to the future?

I started a named branch several months ago which I then abandoned. Now I want to "restart" it. Specifically, I want to bring it up to the latest version of default and start working on it again.
I tried updating to the branch, and then reverting it to default,
hg revert -a -r default
But when I swap back and forth between this branch and the actual default I see 112 files have changed, so clearly they are not the same.
I ended up closing the branch, updating to default, force-switching back to my named branch again, and then force pushed (because it creates a new head).
Now my named branch is the same as default, but I have this short dead branch in my history now.
My questions are:
What was hg reverting to default doing? Was it reverting to the closest default ancestor rather than the tip of default? Even when I tried reverting to the tip via an explicit changeset, the two branches ended up different.
What is the "proper" way to do this?
What was hg reverting to default doing?
For your (really bad )syntax:
Using the -r/--rev or -d/--date options, revert the given files or directories to their states as of a specific revision
i.e to the state of latest ancestor in default branch for all files in repo
I see 112 files have changed, so clearly they are not the same
Wrong assumption
Because revert does not change the working directory parents, this will cause these files to appear modified.
I.e you must commit this modified Working Directory and diff (for testing) heads of branches after it only
What is the "proper" way to do this?
Proper ways is
If you want to save branch-specific changes and only update with latest changes
Update to the head of abandoned branch
Merge default branch to your branch
Resolve all (if any) conflicts
Commit mergeset
If you want to have empty branch only and remove all changes from it
Backout all changesets from branch
Commit backout-changeset
Merge default to branch

Hg Branching/Merging for Bugfixes

So, I have an Hg repo that looks like this:
O [default] [tip] Current repo
|
O Merging changes from named branch
|\
|O Something from a named branch
||
O| [prod-v1.2] Okay, version 1.2 is done
Now I've come across a problem in version 1.2. I can update to the tag prod-v1.2 and commit it, but when pushing, it warns me about multiple heads. Is there a way I can make my new "bugfix" branch the default temporarily? How can I manage this?
The best way to do this, is to create a new branch for your bugfix and then commit in it. The next time you will have to do changes on the version actually in production, you can just update to your branch and commit your change there.
If needed, you can easily merge the content of the branch to your development branch.
An example of this kind of workflow is described here : http://stevelosh.com/blog/2010/05/mercurial-workflows-stable-default/ but you can also find many more way to do this.
In your specific case, you can do something like this if you made only one commit :
hg rollback # rollbacking last commit to allow for branch creation
hg branch bugfix-v1.2
hg commit
hg push
You can now switch back to your default branch and continue to work on the next version... Next time you have a bugfix to do, just switch to your branch with hg update bugfix-v1.2 and commit here.

Why can't I rebase on to an ancestor of source changesets if on a different branch?

I would like to know why the following pattern is not possible.
Having created a local feature branch (minor_feature - not intended to be shared with the world) I would like to rebase the work on it on to the tip of a well known branch (stable). However I have discovered that rebase finds nothing to be rebased in the case where stable has not progressed since branching away from it.
I appreciate that this breaks the rule that the destination of rebase can not be an ancestor of the source but can't work out why this should be prohibited in the simple case shown. I also understand that, branches aside, the topology would not actually change during the rebase. But given that the branch names are indeed significant to the topology, it only seems to be a special case in that stable has no further revisions commited to it. With a single extra revision on the tip of stable (say pulled in from elsewhere) I can of course perform the rebase
o branch:minor_feature
| rev:4
| changeset:746d8191aa5d
|
o branch:minor_feature
| rev:3
| changeset:520f565ba7f2
|
# branch:stable
| rev:2
| changeset:64e7c753c090
|
o branch:stable
| rev:1
| changeset:3dc55a5c9971
|
o branch:stable
rev:0
changeset:fbf1f426945c
$hg rebase -b minor_feature
nothing to rebase
--
Thanks
Chris Gorman
Rebase is strictly for changing ancestry of changesets. As you've observed, you're not changing ancestry here. Branches aren't included in the ancestry computation.
I'm not 100% sure what you're trying to accomplish. If it's to effectively remove the branch, then as long as you haven't pushed, you can likely use the MQ extension. Import the changesets, pop all. Ensure you're updated to the stable branch (which it should be by default), and push them all back on.
They should now all be on the stable branch.
You can do this with the convert extension. You would use a branchmap to rebase minor_feature to default. That file (we'll call it alldefault) would look something like this:
minor_branch default
Then the command would just be:
$ hg convert --branchmap alldefault oldrepo newrepo
When it finishes, newrepo will have the named branch "rebased" on top of the default branch.

Can I clone part of a Mercurial repository?

Is it possible to clone part of a Mercurial repository? Let's say the repository is quite large, or contains multiple projects, or multiple branches. Can I clone only part of the repository?
E.g. in Subversion, you might have trunk and branches. If I only want to get trunk (or one of the branches) I can just request [project]/trunk. If I clone the hg repo I'll get trunk and all of the branches. This might be a lot of information I don't want. Can I avoid getting this?
Alternatively, if I want to have multiple projects in one hg repo, how should I do this? I.e. so that I might just get one of the projects and ignore the others.
Yes you can. I'm sure you've moved on, but for the sake of those who will wander here later, I followed the docs at ConvertExtension, and wrote a simple batch script:
#echo off
echo Converting %1
REM Create the file map
echo include %1 > ~myfilemap
echo rename %1 . >> ~myfilemap
REM Run the convert process
hg convert --filemap ~myfilemap .\ ..\%1
REM Delete the file map
del ~myfilemap
cd ..\%1
REM update the new repo--to create the files
hg update
Name it something like split.cmd, and put it in the directory for the repo you want to split. Say for example you have C:\repos\ReallyBigProject, and a subfolder is C:\repos\ReallyBigProject\small-project. At the command prompt, run:
cd\repos\ReallyBigProject
split.cmd small-project
This will create C:\repos\small-project with a slice of the relevant history of revisions from the larger project.
The convert is not enabled by default. You'll need to make sure the following lines exist in your .hg\hgrc file (c:\repos\ReallyBigProject\.hg\hgrc in my example):
[extensions]
hgext.convert=
#Nick
"E.g. in Subversion, you might have trunk and branches. If I only want to get trunk (or one of the branches) I can just request [project]/trunk. If I clone the hg repo I'll get trunk and all of the branches. This might be a lot of information I don't want. Can I avoid getting this?"
Absolutely. Just use hg clone -r <branch> and get only the branch you want. If you have lots of branches, you need a -r <branch> for each one. <branch> doesn't have to be a named branch: you can simply have multiple unnamed heads (or named heads using bookmark, though those still aren't perfect, because currently they don't show up with push/pull/clone).
Keep in mind that in DVCSes, Mercurial among them, branches are often short-lived and merged back into each other frequently. If you pull a branch you will still get the common history it has with any other branches.
To my knowledge, that's not possible. But compared to Subversrion, cloning the whole repos may not be slower than just a branch from SVN.
Quoting from UnderstandingMercurial:
Many SVN/CVS users expect to host
related projects together in one
repository. This is really not what hg
was made for, so you should try a
different way of working. This
especially means, that you cannot
check out only one directory of a
repository.
If you absolutely need to host
multiple projects in a kind of
meta-repository though, you could try
the Subrepositories feature that was
introduced with Mercurial 1.3 or the
older ForestExtension.
#Nick said:
"This is a pretty big omission since a lot hosting sites only offer one repo. With svn I can effectively have as many repos as I want by only taking one branch from the main one. The subrepos sound like a hack."
Subrepos (aka submodules) are not as ideal as "narrow clones" its true. But at least for having many distinct projects in one hosting site's repository, you can have multiple code-bases in one repository. This won't allow you to slice up different sections of one repository / sub-directories of a project , but it will let you manage multiple projects. What you do is have lots of named branches each rooted at the empty (or null) changeset (i.e. they have no common root revision). It can get a little messy to track the branches but it does work.
For example:
hg init
hg branch project-1
# Changes, commits, repeated as needed
hg update null
hg branch project-2
# Changes, commits, repeated as needed
You now can see all your projects:
> hg branches
project-2 5:42c2beffe780
project-1 2:43fd60024328
The projects are unrelated (though you can merge them):
> hg debugancestors
-1:000000000000
Most usefully: you can clone only the project you want, and the others won't mix in:
> hg clone <repository> -r project-1
The graph for this would look something like this (hg log -qG):
# 5 | project-2 | {tip}
|
o 4 | project-2
|
o 3 | project-2
o 2 | project-1
|
o 1 | project-1
|
o 0 | project-1
You can do this for as many projects as you need, listing each with hg branches, and jumping between them with hg update. This takes some care, because named branch support isn't perfect. It isn't always intuitive for one thing (read about hg clone -u in Mercurial 1.4 -- the pre-1.4 behavior is surprising when cloning). But it does work.
Mercurial and Git only permit cloning on the entire repository. Thus it is recommended that each project gets its own repository.
Mercurial has a forest extension to ease having a "forest" for project repositories. The extension keeps each project in a separate repository, but provides options to update/push/pull all the forest repositories together.
It's possible to ask Mercurial to clone just a branch using hg clone -r branchname (see Mercurial clone from a branch).
With Google's NarrowHG extension extension it's possible to perform a narrow clone (see How do I clone a sub-folder of a repository in Mercurial? for a similar question).
I know that it is nearly 10 years after this question was asked, I I stumbled across
this question by accident.
There is a new mercurial extension call sparse that allows you to do this.
Here's a possible improvement to Vadim Kotov's solution that supports spaces in the small-project name/subfolder:
#echo off
echo Converting "%~1"
REM Create the file map
echo include "%~1" > ~myfilemap
echo rename "%~1" . >> ~myfilemap
REM Run the convert process
hg convert --filemap ~myfilemap .\ "..\%~1"
REM Delete the file map
del ~myfilemap
cd ".\%~1"
REM update the new repo--to create the files
hg update