What is the issue with absolute paths in .hgsub? - mercurial

The mercurial documentation recommends to use trivial relative paths in .hgsub and use [subpaths] to map to the absolute paths. I don't fully understand the reasoning behind this. The argument on the documentation page is that absolute paths are more likely to change. Wouldn't the solution with [subpaths] require a change, too, whenever the absolute path changes?
One reason I can understand (but it doesn't apply in my case) is that clones of clones are only possible using [subpaths] to remap full original paths to the absolute path. If absolute paths would be used directly, the clone of the clone would push/pull from the original and not the first clone. Is this the only reason against using absolute paths without a [subpaths] section?

The primary reason is because sometimes paths change and your .hgsub is part of history. If your subrepo moves from http://tinyco.com/hg/repo1 to http://bigco.com/tinydivision/hg/repo1 you can update your .hgsub file of course, but the old version in place for past revisions. Thus when you do hg update reallly_old_revision it'll try to talk to http:/tinyco.com, which got nerfed as part of the acquisition. If you keep a trivial path as the subrepo path then you can use [subpaths] in your .hg/hgrc to point it to where it currently lives.
It's also, often handy, to point subrepos toward your own local clones of the real subrepo, so that you can push to it even if you're unable to push to the subrepo (no permission).
In general adding a layer of indirection adds flexibility.

Related

Is there any side effect if I clone a repo and rename it?

I have central mercurial repository server. I cloned repoA on my local system
initiated new repoB on central server. cloned repob to local. copied everything from repoA to repoB, commit and pushed to repoB (central server)
now i have all the changeset history from repoA on this new repoB
there was a need to do so as there were two application code on same repoA, to separate it i did the above experiment. and it is working.
my question is by doing so is there any side effects , or is there a better way to do it (recommended way ) please suggest, thank you !
When you clone a repository to your local PC, the repository lives in a folder. That name of that folder is typically how people refer to the "name of the clone" or the "name of the repository".
Other than that, the folder name itself has very little significance and is not even properly part of the Mercurial repository.
It sounds like you did several other steps, but basically if you renamed repository A to B it won't make much difference (but see notes below).
You do not need to use hg clone to clone a repository. You can literally just copy the entire repository folder and the copy will work just fine. The one difference that I am aware of when you use clone vs. operating system file copy is that the clone will point back to the repo you cloned from (for use in push/pull operations). The copy would point back to the original source. (See notes below about some related effects).
One situation where you might cause some problems by renaming the repository folder is if you have have cloned FROM it. Example: you have local repo A. You clone A to B. Now internal to the configuration data in B is a reference to the folder path including A. If you rename A to A1 then that path is obviously broken.
In such a situation you can easily edit the B/.hg/hgrc file and modify the line starting with default= to correct the path.
Based on your question it sounded like you copied a bunch of stuff from one repo to another. Presumably this also included the .hg folder. Generally speaking I recommend avoiding the contents of that folder, and always approach it with caution.
Although technically some of it is human-readable it is simpler & safer to treat it as a black box, or you risk corrupting your repository. There are occasional exceptions (like hgrc) but they are few & far between.
Of course if you are just trying to learn how it works then by all means try things & see what happens! One of the great Mercurial features is the ability to copy a repo, mess around with it, and throw it away when done.

Mercurial: how do I create a new repository containing a subrange of revisions from an existing repo?

I have a repo with subrepos, with a long history. At some point the main subrepo became fully self-contained (doesn't depend on other sister subrepos).
I don't care anymore about the history of the whole thing before the main subrepo became self-contained. So I want to start a new repo that contains just what the subrepo has in it from that moment on. If possible, please describe in terms of TortoiseHg commands.
You probably want to make use of mercurial's convert extension. You can specify revisions to be converted, paths, branches and files to include or exclude in the newly-created repository.
hg convert from-path new-repo
Convert is a default extension which just needs activation.
You might be able to weed out any other changesets you don't need by using the hg strip command.
It will entirely remove changesets (and their ancestors) from a repository. Most likely you would want to make a fresh clone and then work on stripping it down.
One potential pitfall is that the final stripped repo would still have shared parentage with the original; therefore the potential exists for someone to accidentally pull down again changesets which were stripped.
The hg convert command (noted in another answer) does not have this downside.

recommended method to add a *single file* as a subrepo to a mercurial repository

I have a mercurial repository myProject:
myProject
|- file1.js
|- file2.css
|- useful.js
Now useful.js is a file with a few useful classes in it. I use it in multiple projects and as such it has its own repository:
useful
|- useful.js
|- example.js
|- README
The idea is that other people can check out useful, have alook at the file and the example and readme, and if they like it, they copy useful.js into their own project and make use of it.
Since useful.js is used in a few of my projects, what is the recommended way to keep it in sync? There is a restriction that useful.js must live in the top-level folder myProject, i.e. can't be nested. This makes it tricky to use subrepositories (and in any case, then I'd get the other files like example.js and README).
The other thing to note is that the useful repo has a few branches: default, version1, and version2. My projects that use useful.js also have branches default, version1 and version2. I'd like to make sure that whenever I switch between branches in myProject, my useful.js switches branches too. If not for that I could probably live with a symbolic link.
This situation doesn't seem particularly uncommon; how do others handle it? Just write a hook on update to check if I'm switching branches and switch accordingly? Plus hooks on commit, push, pull ? (basically replicate subrepo behaviour for the single file)?
cheers.
Given your use case, it would seem that you might want to consider using Yeoman and more specifically the Twitter Bower Package Manager. This way, rather than keeping a copy of the external dependency in your repository, just identify it in the Bower config.
It is impossible to add only a part of a repository as a subrepository with Mercurial. Thus you can't add only a single file from a repository.
Even if your other repository contained only one file, you could'nt add it at the root level either.
You will have to find another way to include your useful.js file. You're mentionning hooks to do that, but I can't see a way to do it honestly without some kind of manual work. Personnally, I'll go with "simplicity" and do everything "by hand".
Concerning the branch switch, there's no builtin mechanism in Mercurial, but as you said you should be able to do that with a hook on update.
Follow-up #krtek
Yes, in any case you can't have linked (with subrepo) useful.js at the root of superrepo, it must be inside subbir.
But - no, with some tricks your can get some iteration to requested result (branch-dependent useful.js and adding single file instead of all).
In order to achieve this, you have to re-read subrepository documentation ("any supported by Mercurial URL can be used for defining external subrepo...") and hg help urls, namely
An optional identifier after # indicates a particular branch, tag, or changeset to use from the remote repository
and note mentioning of branch. I.e - if you'll have special branch(es) with known name(es) in repository of useful and have in this branches only single useful.js, you can define subrepo with these added data - branch with single file for branch in superrepo
This way you'll have different subrepo specification in each branch of superrepo, have to merge branches with accuracy (always save "my") or define special mergetool for .hgsub files

subrepo, hg clone and symlinks

I'm quite new to mercurial, I've read a lot on this topic but I've been unable to find a clear answer.
The mercurial guide says: "For efficiency, hardlinks are used for cloning whenever the source and destination are on the same filesystem (note this applies only to the repository data, not to the working directory)."
The Repository wiki page says: "All of the files and directories that coexist with the .hg directory in the repository root are said to live in the working directory".
Now, to "link" a subrepo in a main repo I do:
hg init main
cd main
echo subrepo = ../subrepo > .hgsub
hg clone ../subrepo subrepo # (1)
hg add
hg ci -m "initial rev of the main repo"
Does the definition above mean that I'm actually creating a copy of subrepo when I perform (1)?? Or am I creating just a symlink to ../subrepo? According to the output of ls, it is an actual copy. But it sounds so strange to me... If someone could put a bit of light on this subject, I'd appreciate.
First of all, that part of Mercurial, I'm not an expert, but here's what I've understood.
No, you didn't create a link to the whole directory. Instead, files were hardlinked inside it.
This means that space on disk is reserved to keep your directory structure separate, but the files are all identical, because they were just cloned, so they are constructed as links back to the original.
When you start manipulating the repository, through your add or commit (ci) commands, then the hardlinks are broken by Mercurial and separate files are constructed for each, on demand.
Now, this is purely a technical thing, you don't need to know or care about this. If it makes it easier, just think of a clone as a complete copy of the original repository, separate files and all that. The hardlink part is just to save diskspace for the things that are the same.
Since a typical project has many files, and a typical changeset only changes a few files, and a typical reason to clone is that you're going to do a fixed set of changes, hardlinks makes sense since many of the files in the repository directories will be 100% identical to their original for the lifetime of the repository.
For those that aren't, all of that is silently handled by Mercurial for you.
Let us start by looking at what happens when you clone without talking about subrepositories. When you do
$ hg clone A B
then Mercurial will make hard links for the files inside A/.hg/store/data. So if a file called x is tracked, then after the clone you will see that
A/.hg/store/data/x.i
and
B/.hg/store/data/x.i
are hard linked -- this means that the two filenames really refer to the same file. As Lasse points out, this is smart since you might never commit a change to x clone, and so there is no reason to make two different x.i files for the A and B clones. Another advantage is that it is much faster to make a hard link than to copy a file, especially if x.i is very large: the hard link is a constant time operation.
In your example above you are adding a subrepository subrepo to the main repository. A subrepository consist of two things:
the subrepository itself. This what you creates when you do
$ hg clone ../subrepo
the subrepository meta data. This is what you store in the .hgsub file. You must tell Mercurial where you want the subrepository and where Mercurial can clone it from.
You ask if you copy or symlink the repository, and you certainly copied (cloned) it, as you have also confirmed with ls. Afterwards you added some meta data to Mercurial that tells it where it can expect to find the subrepository. This has nothing to do with a symbolic link in the normal filesystem sense, it is just some meta data for Mercurial.

Mercurial repo inside a repo

Is it possible to create a mercurial repository inside an existing mercurial repository?
The idea is to handle subdirectories of a repository as different repositories, how do you do that?
I'm not talking about subrepos (at least, if I understood the purpose of subrepos...), but if this is how subrepos do exist for, I got it wrong and I'll try to get it right :)
Thanks
~Aki
EDIT: To be more clear, I'd like to know what happens, the practices and the implications of having a repository inside another one, without specifying modules/subrepos.
In other words: what happens if I just do:
hg init globalRepo
hg init globalRepo/subRepo
and use these two repositories as-are?
It works well. Long before the subrepo support was added in Mercurial 1.3, lots of folks kept their entire home directories in a mercurial repo for tracking their .bashrc files and the like. Then within their home dir they'd have many clones of other repos.
Whenever you invoke mercurial (without the -R option) it looks in the current directory for a .hg directory and then just keeps going up directories until it finds one. So if you're in a repo that is in a repo, your commands will always act on the innermost repo you're in.
The caveat is that you want to make sure not to have files added to the outer repo that end up inside the inner repo. Then you'll have two repos updating the same files.
As you can see in this SO question, you can make that kind of nested hg init, even though it is usually reserved for defining subRepo (which is not what you are after).
Normally it should work as two independant repos, but I would advise adding an hgignore rule in the globalRepo in order to ignore the subRepo content altogether.
Here are some docs on nested repositories.