mercurial: any command or python api to get repository name - mercurial

Is there any Mercurial command or Python API that could yield the repo name? This will help developing cross-repo scripts.
The only related solution that I found is to parse the .hg/hgrc [paths] section 'default' config option.
[paths]
default = ssh://server//path/tools
There must be a more elegant solution, I think.

There is no real concept of a "repository name" in Mercurial (a repository doesn't "know" or care about its own name). I think you mean "last past component of the default pull path"?
If so, then parsing the output of hg path default would be the most direct way to get that information.
However, you should note that the default path can (and often is) changed: think of cloning a local clone time for testing:
$ hg clone http://server/lib-foo
$ hg clone lib-foo lib-foo-test
$ hg clone lib-foo-test lib-foo-more-testing
The lib-foo-more-testing clone has a default push path back to lib-foo-test.
This means that parsing hg paths default wont be much more reliable than using basename $(hg root) — both can be completely different from the (base)name of the repository that was originally cloned.
If what you really want is to get an "identity" for a repository, then you should instead use
$ hg log -r 0 --template "{node}"
The first changeset hash in a repository will normally uniquely identify the repository and it will be stable even when clones change names. (If a repository has two or more roots, then the zeroth changeset can in principle differ between clones. People will have to actively try to make it differ, though.)

If you want to get last segment of path for remote default alias, processing output of hg path default will be better choice
If you want to get local directory name of you mercurial repository, I haven't good solution, except checking code of Notify extension (in which, after some tricks, you can get project-name)

Related

Hg clone only public commits

We have a big Hg repo, hosted in a remote location. Performing an hg clone from this master repo takes about an hour. What we generally do to speed things up is to hg serve a local repo of a colleague, hg clone http://colleague-machine, and then change de default path in .hg/hgrc to the address of the master repo.
This is all well and good, but this workaround has one drawback: because we are cloning the repo of a developer, some draft commits can be cloned along with the public ones. Moreover, these commits become public in the cloned repo, making them indistinguishable from the others.
One possibility I found is to make the developer's repo non publishing, in order to preserve the phases of the commits and to remove them later on. Another possibility is to create a bundle containing only the public commits, instead of cloning directly.
These methods are more complex to explain and to document. Is there an option for hg clone to clone only the public commits? I tried with hg clone -r "public()", but clone does not take a revset, just a regular commit identifer. Alternatively, is there an option for hg serve to serve only the public commits?
Throw disk space at the problem: just keep a local mirror clone that you update regularly.
Cloning the "true master" is slow because it's far away over a slow link. But updating the mirror is fast because, while the true master is far away over a slow link, little data needs to traverse it; and cloning the mirror is fast, and gets you the state of the true master as of the last time the mirror was updated.
As you mention, you can then just replace the default path (and maybe run a subsequent hg pull to pick up anything not-yet-mirrored, if needed). Your new clone is then the same as it would have been, had you cloned from the far-away slow true master, except that it went fast.
Git has this kind of cloning built in, as what's called a reference clone. You point your git clone process at two repositories: the true source, and the "close and fast" reference. It gets hash IDs from the true source but then uses the close-and-fast reference's storage for its data. You can then choose to continue to rely on the reference (default) or "dissociate" from the reference so that your clone is independent. It needs this dissociate operation because it can do a somewhat dangerous path-name-based "link" (not really a link in the sense of hard links; more an in-Git analogue to symbolic links) to the original, and does so by default here.
I don't think Mercurial has anything equivalent "out of the box". I imagine it should be relatively easy to write as an extension, though, if you are up for that sort of thing. You wouldn't need --dissociate at all, it would be the default wherever hard links are not feasible.
One way to do this is to use hg clone -r <rev> where <rev> is public. That will ensure that you won't get any draft commits, although you will miss any branches that aren't ancestors of <rev>.
I don't think there's a generic way to clone only public changes. It might be possible via a server-side extension or in-process hook though.
I ended up using a combination of hg serve option and hg strip.
On the existing repository:
hg serve --config phases.publish=False --port 0 --prefix repo-name
On the target machine:
hg clone <address printed by `hg serve`>
cd repo-name
hg strip -r "draft()"
The phases.publish=False config makes the repo non-publishing, and thus preserves the phase of the commits that are cloned. Now that the phases are kept on the target machine, it is easy to strip them off after the clone.

Can I mark a branch as 'not going to push'?

I use named branches in Mercurial.
In doing so I have created one branch called playground where I can try out various wacky experiments. I never intend to merge this branch into any others and I never want to push it to our main repository.
Since creating it, every time I do a push I am told I have added a new branch and I have to use the --new-branch flag. At this point hg push -b default (or whatever branch I'm pushing) works fine but it's annoying. Is there any way to suppress that message by letting Hg know that I am not interested in pushing that branch ever?
Starting with Mercurial 2.1 (released in February 2012), you can mark your changesets secret to keep them from being pushed to another repository. You use the new hg phase command to do this:
$ hg phase --force --secret .
This mark the current working directory parent revision (.) as being in the secret phase. Secret changesets are local to your repository: they wont be pushed or pulled. Pushing now looks like this:
$ hg push
pushing to /home/mg/tmp/repo
searching for changes
no changes to push but 2 secret changesets
There is no equivalent mechanism in older versions of Mercurial. There your best bet is to create a local clone for the changesets you don't want to push.
Update:
Mercurial 2.1 introduced the hg phase command which allows users to control what change sets are exchanged with remote repositories. #MartinGeisler answer to this question details this method.
Original Answer:
If you want to create a local branch of your code you have a couple options. You can hg clone the repository which will locally create a branch of the entire repository in your filesystem. The other alternative is you can try to use a Mercurial extension like LocalbranchExtension.
There are many ways to branch in Mercurial without using a named branch. Just find a method that suits your needs.
Further reading: http://stevelosh.com/blog/2009/08/a-guide-to-branching-in-mercurial/
In addition to the excellent answer above concerning phases, you can also specify 'default-path' (in the [paths] section of your .hgrc) to refer to the local repository:
[paths]
default = ...
default-push = .
This will cause all outgoing changesets to be compared to the specified repository. In this case, comparing outgoing changesets in your local repository TO your local repository results in nothing to push.
You can still pull/update/merge from the main repository, but no push will ever send anything back to that main repository.
If you work on multiple machines/repositories, you can set one up as described above, and configure the others to specify the 'default' path to point to the server that pushes to itself. In this way, the other machines can push/pull to your local central repository, and these changesets will never escape your carefully configured collection of repositories.

Cloning a mercurial repository, .hgsub refers to a dead external subrepo

We're trying to clone a Mercurial repository A where it references a subrepository B that's moved hosts. We'd like to update .hgsub in A to point to the new location of B, but it's a chicken and egg problem if we can't hg clone A in the first place.
Does anyone know how to work around this?
$ hg help subrepos
...
Remapping Subrepositories Sources
---------------------------------
A subrepository source location may change during a project life,
invalidating references stored in the parent repository history. To fix
this, rewriting rules can be defined in parent repository "hgrc" file or
in Mercurial configuration. See the "[subpaths]" section in hgrc(5) for
more details.
$ man hgrc
...
subpaths
Defines subrepositories source locations rewriting rules of the form:
<pattern> = <replacement>
Where pattern is a regular expression matching the source and replacement is the replacement string used to
rewrite it. Groups can be matched in pattern and referenced in replacements. For instance:
http://server/(.*)-hg/ = http://hg.server/\1/
rewrites http://server/foo-hg/ into http://hg.server/foo/.
All patterns are applied in definition order.
...
So, you can do it in .hgrc in a [subpaths] section.
First note that clone is init + pull + update and that subrepo cloning is part of the update step, not the pull step. This means that you can avoid clone failing simply by skipping the update step:
$ hg clone -U <url>
Now the problem is reduced to "how do I update to a revision with a problematic .hgsub/.hgsubstate file?" There are two possibilities here:
remap subrepos using the [subpaths] feature (see hg help subrepo and hg help config)
manual update and repair
A "manual update" can be done like this:
$ hg revert -a -r default -X problematic-file
[adding a bunch of files]
$ hg debugrebuildstate -r default
Now you can manually fix-up your subrepos and .hgsub and commit. Be sure to test your fix with a clone before pushing it.
Also, see this mailing list thread on the topic: http://markmail.org/thread/ktxd2rsm7avkexzr
It could be easier to tamper with DNS as a quick workaround (e.g. hosts file on Windows) and then fix .hgsub.

Mercurial error: repository is unrelated

I've just started with Mercurial, I have a 'central' repository on Bitbucket which I cloned onto one machine and made changes and committed and pushed. I then cloned from Bitbucket to another machine committed and pushed which was fine. I then came back to the first machine, made changes committed and attempted to push, but got the error message. What am I doing wrong? Should I have pulled first? How can I resolve the error and push? Any help is appreciated!
Darren.
A Mercurial repository gets its identity when you make the first commit in it. When you create a new repository on Bitbucket, you create an empty repository with no identity.
When you clone this repository to machine A and make a commit and push it back, then you brand the repository. If you have cloned the repository on the second machine before pushing from the first, then you can end up in the situation you describe.
Please run hg paths on the machine where you cannot push. Then make a separate clone of the repository it says it will push to. Now examine the first changeset in each repository with
hg log -r 0
If the initial changesets are different, then you have two unrelated repositories, as we call it in Mercurial. You can then export the changes you cannot push as patches and import them in the other.
If you're pretty sure the push path is correct, it may be worth it to just export your changes to patches from the problem repo, clone again from Bitbucket and then import the patches into the new repo. This will either just work or reveal a bad/corrupted commit.
I would like to share knowledge about Mercurial internals.
Repositories unrelated when they have no any same revisions.
Corresponding piece you can find in mercurial/treediscovery.py:
base = list(base)
if base == [nullid]:
if force:
repo.ui.warn(_("warning: repository is unrelated\n"))
else:
raise util.Abort(_("repository is unrelated"))
base is a list of roots of common parts in both local/remote repositories.
You always may know how repositories are different by:
$ hg in $REMOTE
$ hg out $REMOTE
You always may checks roots of both (after cloning both locally):
$ hg -R $ONE log -r "roots(all())"
$ hg -R $TWO log -r "roots(all())"
if output from above commands doesn't share IDs - those repositories are unrelated. Due to hash properties it is very impossible that roots be equal accidentally. You may not trick roots checking by carefully crafting repositories because building two repositories looks like these (with common parts but different roots):
0 <--- SHA-256-XXX <--- SHA-256-YYY <--- SHA-256-ZZZ
0 <--- SHA-256-YYY <--- SHA-256-ZZZ
impossible because that mean you reverse SHA-256 as each subsequent hash depends on previous values.
Having this info I believe any Devs be able to troubleshoot error: repository is unrelated.
See also Mercurial repository identification
Thanks for attention, good hacking!
You get this message when you try to push to a repository other than the one that you cloned. Double-check the address of the push, or the default path, if you're just using hg push by itself.
To check the default path, you can use hg showconfig | grep ^paths\.default (or just hg showconfig and look for the line that starts paths.default=).

How do I move a private Mercurial repository to a central server?

I’m just getting started with Mercurial, and I’ve read Joel Spolsky’s Hg Init tutorial, which I liked.
I’m wondering: let’s say I have a private repository and I work on it for about a month. Then I decide I want to centralize it or make it public, like on bitbucket.org. I want to retain all the history.
The intuitive thing would be to use hg clone, but according to the docs:
The location of the source is added to
the new repository's .hg/hgrc file, as
the default to be used for future
pulls.
I don’t think this is what I’d want, since the source is my local, private repository, and the destination is the public server. I don’t want the public server trying to pull from my private repository in the future thinking it’s the central one. I hope this makes sense.
Do I have to tweak the .hg/hgrc file on the server manually? Am I approaching this correctly?
BitBucket's help says it's as easy as making an empty repo on BitBucket, then pushing to it:
... create a new empty repository via the "Create repository" page. We will assume that this repository is named blonk and is to be found on http://bitbucket.org/jespern/blonk.
Now, just push to it:
$ cd ~/Work/blonk # our existing hg repository
$ hg push http://bitbucket.org/jespern/blonk
...
Done!
You can edit .hg/hgrc in your repository to include the default path to Bitbucket:
$ cat .hg/hgrc
[paths]
default = http://bitbucket.org/jespern/blonk
Now you can simply enter hg push and hg pull without having to specify the full URL.
Doing this operation using 'hg push', as described, is probably the best way to do this, overall.
However in other circumstances it might be convenient, or reassuring, to note that all of the Hg state is contained within the .hg directory, and so simply moving this directory is enough to move the repository.
For example, if you have ssh access to a machine at example.com, you can tar (or zip) up your .hg directory in the 'private' repository, unpack it in, say, ~/repo/foo on the remote machine (thus creating a directory ~/repo/foo/.hg there), and then simply clone this:
$ hg clone ssh://example.com/repo/foo
This does have a slight back-door feel to it, I agree. However, there's nothing really under-the-hood happening here, and no editing of configuration files is necessary. When I do this, I find it less confusing than the 'proper' way.