Push to two repositories that can't reach each other - mercurial

The setup:
a laptop L
an office server hosting various repositories SOffice
a customer's database server SCustomer
I'm writing code on L for a customer, and regularly want to push it both to SOffice as well as SCustomer.
I know I could use a changegroup hook to push to a third repository from the second (as described in this answer), but this requires that the second can reach the third network-wise.
In my case, each is behind a firewall, and only my laptop typically accesses both through a VPN (or by being physically there). I could set up the VPN on SOffice to get to SCustomer, but I'd rather not.
Is there a way I can, say, set default to two repositories?

You can't default to two repositories, but you can define more than one repository in your hgrc file :
[paths]
default= /path/to/first/repo
scustomer = /path/to/second/repo
You can then push to the scustomer repository explicitly :
hg push scustomer
If you want to automate the process of pushing to both repository at once, I'm not aware of a Mercurial method to do it, but it is really easy to create a shell script, alias or something else to run both commands one after the other.
You can even use a hook on the repository to automatically push to the other one, but you will have to discriminate between a "manual" push and the automatic push in the hook, and I'm supposing this will be really messy.

Could you create a second clone of the repository with a hook that automatically pushes to both of the external repositories? Then push from your working clone to the second clone.

There's a MultirepoExtension that adds commands for doing any operation on multiple repositories.
Or you could create an alias to push to both like:
[aliases]
pushboth = !$HG push http://first ; $HG push http://second
or you could create a pre-push hook that pushes to the other one. Something like:
[hooks]
pre-push = hg push http://second
But I like (and upvoted) krtek's answer the most. Just give each a path alias and run push twice with the short names instead of the URLs.

Related

How to refer to external SubRepo in the .hgsub file? [duplicate]

Is it possible to create a subrepository using a sibling path?
Subversion is our "chosen" VCS here, but I've already had quite a few issues with out of date commits. It's much more convenient for me to dual version my files under Hg and SVN, and I have had great success with it. However, I've got a few other co-workers using Hg, and we've had no problems there except for one they probably haven't noticed.
Our SVN layout looks like this
Area/
trunk/
Program1/
Program2/
...
Services/
Program1ServiceA/
Program1ServiceB/
branches/
Program/
Program/
...
Services/
Program1ServiceA/
Program1ServiceB/
tags/
Program1/
Program2/
...
Services/
Program1ServiceA/
Program1ServiceB/
Which makes it kind of stupid when you're working on a project, because if your main project is comprised of Program1 and Program2, and a few more services... I can't get all of the changesets in one go, because we've got a repository that matches the directories. So I have to make sure 4 or 5 repos are in sync, especially with some service references.
I've had some good luck using subrepos beneath a single directory:
MainRepo/
Subrepo1/
Subrepo2/
But what I would like to do is specify a relative path so I can use sibling directories to the subrepository, so I could have something like this:
Area/
Project1/
Program1/ (points to ../trunk/Program1)
Program2/ (points to ../trunk/Program2)
Service1/ (... You get the idea)
Service2/
trunk/
Program1/
Program2/
Services/
Service1/
Service2/
But so far it hasn't worked like I expected it to. trunk/Program1 is an Hg repo, and my Project1/.hgsub file contains
Program1 = ../trunk/Program1
I've also tried ../../trunk/Program1
But the result of either of those is that a new directory is created: Area/Program1/Project1 that is empty.
So far, the only search results I've been able to find use http based repositories for subrepos, so I'm not sure where to go from here. Our dev env is Windows 7, so the "easy" answer is to create junctions, but my primary concern is to make things like this easy to do, so the barrier to entry is as low as possible, and even something as easy as mklink /J Program1 ..\trunk\Program1 from an administrator cmd window is one more thing that would prevent people from migrating to a better workflow.
Is it possible to add a subrepository like I want, or is there a better way to do what we're doing?
Subrepositories are always inside another repository. In other words, subrepositories lets you version a collection of repositories where some repositories are nested inside other repositories. Subrepositories can thus not be siblings without creating an outer repository.
The relative paths you're talking about are used when Mercurial needs to figure out where to get a new subrepository from. That is, when you run hg update (or when it's run for you as part of hg clone) and Mercurial notices a .hgsub file, then it needs to create the subrepositories mentioned there. To create the subrepo, Mercurial uses the path on right-hand side:
sub-A = relative/path
sub-B = C:/absolute/path
Here sub-A will be checked out in the root of your working copy using the command
hg clone <default path for main repo>/relative/path sub-A
and sub-B is checked out using the command
hg clone C:/absolute/path sub-B
That's all — it's a very simple mechanism. I've tried to describe this in my subrepository guide and it's also explained in the wiki.
For your case, you can make a thin shell repository for the parts that belong together. This repo will be like Project1 above and have Program1, Program2, Service1, etc as subrepos. The .hgsub will look like this:
Program1 = Program1
Program2 = Program2
Service1 = Service1
Service2 = Service2
By using "trivial subrepo paths" you make things easy: a clone looks just like the clone source and everything is kept together.
A final note: unless you use Program1 or Service1 in other projects, then you should just put everything into a single repository.

Mirgrating from mercurial Bfiles to largefiles

I have used mercurial's bfiles extension for some time and it works fine. The only problems are installation and the special "hg bfadd" command.
Now that Mercurial 2.0 include the largefile extension I would like to switch.
Can't find any tools or guides on how to do it? Anyone tried it yet.
I have several repositories that all use the same store and have the following mercurial.ini.
[bfiles]
store=\\Someserver\Mercurial\bFilesStore
autostatus = true
autoupdate = true
autorefresh = true
autoput = *
You can find the documentation here : https://www.mercurial-scm.org/wiki/LargefilesExtension
To enable the extension add the following to your hgrc :
[extensions]
largefiles =
You can add a new large file with :
hg add --large thisfileislarge
About the migration, the readme.txt of the bfiles extension says something about a migrate.txt file ( https://bitbucket.org/gward/hg-bfiles/overview section "The future"). But I can't find the file anywhere on the repository, maybe he forgot to upload it.
There's also a mail on mercurial-devel about this : https://www.mercurial-scm.org/pipermail/mercurial-devel/2011-October/035161.html but nothing since then.
Maybe the better solution is to contact the author of bfiles about his status on the migration process and keep using the old extension until you have an answer ?
Either way, there's a lot of bug report about largefiles since the release of 2.0, so it's maybe a good idea to wait anyway :)
In the latest hg-bfiles version (from 2011-12-05), if you update to the migrate branch, you get this help file:
bfiles: migrating to largefiles
If you want to migrate from bfiles to the new largefiles extension in
Mercurial 2.0, you first have to decide: convert your repo or keep it?
Converting your repo
This is appropriate if:
you have a small repository
you know exactly where every clone of it is
you can replace every clone
It involves creating an new repo with .hgbfiles/ replaced by .hglf/.
This means that your changeset IDs will differ, so you cannot
pull/push between the old and new repos. You must replace every
existing clone with a clone of the converted repo.
The advantage of converting your repo is that you can say goodbye
forever to bfiles, and move into the future using largefiles alone.
The process is mostly automated by two shell scripts: convert-repo and
convert-store.
Use the convert-repo shell script to convert the repository itself. This is just a wrapper around "hg convert" that takes care
of all the fussy details needed to turn .hgbfiles/ into .hglf/.
It's easy to run:
./convert-repo SRC-REPO DST-REPO
The resulting DST-REPO is not yet ready to use: you still have
to convert the bfiles store to a largefiles store.
Use convert-store to turn the bfiles store into a largefiles store. You must have a local copy of the bfiles store -- so you
probably want to run this on the server where your bfiles store
lives. Again, it's easy:
./convert-store SRC-STORE DST-REPO/.hg/largefiles
Putting the store inside your DST-REPO is the easiest way to
make largefiles just work.
Keeping your repo
(Yes, that's the end of the file, there's no help on how to keep your repository)

How do I set up a hook in HG / Mercurial that gets dictated by the repository?

I have a need for a hook to run after update (this will build the solution they have updated) and I don't want to have to add that hook manually for each person that clones my central repository.
When someone first clones my central repository, is it possible to include hooks into that clone? It seems that the .hgrc file doesn't get cloned automatically.
I did read about site-wide hooks, but as far as I understand it, they work on each created repository, where I only want to have the hooks on some repos.
As Rudi already said, this is (thankfully) not possible for security reasons.
However, you can reduce the per-clone workload to set up hooks manually: Ship the hook scripts as part of your repository, e.g. in a directory .hghooks, and additionally include a script in your repo which sets up these hooks in a clone's hgrc. Each coworker now only needs to call the setup script once per clone.
This is not possible, since that hooks do not propagate to clones is a security measure. If this were possible, one could set up a rouge repository, which runs arbitrary commands on any machine where the repo is cloned.
See http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html#id402330 for more details.
This will allow for centralised per-repo hooks, with a single setup step per user. It will however cause problems for users who are disconnected from the network. An alternative if you tend to have disconnected developers (or ones over high-latency/low bandwidth links) would be to have a repo containing the hooks, and set up each user's global hgrc to point into that repo (and require regular pulls from a central hook repo).
Note that I treat the ID of the first commit as the "repo ID" - this assumes that the first commit in each repository is unique in some way - contents or commit message. If this is not the case you could do the same thing but applying it over the first N commits - but you would then have to account for repos that have fewer than N commits - can't just take repo[:5] for example as newer commits would then change the repo ID. I'd personally suggest that the first commit should probably be a standard .ignore file with a commit message unique to that repo.
Have a central shared_hgrc file, accessible from a network share (or in a hook repo).
Each user's global hgrc has:
%include /path/to/shared_hgrc
Create a shared repository of python hook modules. The hooks must be written in python.
Create your hook functions. In each function, check which repo the hook has been called on by checking the ID of the first commit:
# hooktest.py
import mercurial.util
FOOBAR_REPO = 'b88c69276866d73310be679b6a4b40d875e26d84'
ALLOW_PRECOMMIT_REPOS = set((
FOOBAR_REPO,
))
def precommit_deny_if_wrong_repo(ui, repo, **kwargs):
"""Aborts if the repo is not allowed to do this.
The repo ID is the ID of the first commit to the repo."""
repo_id = repo[0].hex().lower()
if repo_id not in ALLOW_PRECOMMIT_REPOS:
raise mercurial.util.Abort('Repository denied: %s' % (repo_id,))
ui.status('Repository allowed: %s\n' % (repo_id,))
def precommit_skip_if_wrong_repo(ui, repo, **kwargs):
"""Skips the hook if the repo is not allowed to do this.
The repo ID is the ID of the first commit to the repo."""
repo_id = repo[0].hex().lower()
if repo_id not in ALLOW_PRECOMMIT_REPOS:
ui.debug('Repository hook skipped: %s\n' % (repo_id,))
return
ui.status('Repository hook allowed: %s\n' % (repo_id,))
In the shared_hgrc file, set up the hooks you need (make sure you qualify the hook names to prevent conflicts):
[hooks]
pre-commit.00_skip = python:/path/to/hooktest.py:precommit_skip_if_wrong_repo
pre-commit.01_deny = python:/path/to/hooktest.py:precommit_deny_if_wrong_repo
As #Rudi said first, it can't be done for security reasons.
With some prior setup you can make it so that hooks are run on clone, but putting a hook with a repo-relative path in /etc/mercurial or in each user's ~/.hgrc, which in a corporate setting can be done via your system management tools or by building a custom Mercurial installer. In a non-corporate setting follow #Oben's advice and provide the scripts and a readme.

Mercurial hook to test that username is valid when pushing to repository

I have a "central" repository that I want to ensure that no one pushes changes in to with a wrong user name.
But I can not figure out how to make a hook that tests the user name against a positive list. I have found in the Mercurial API a ctx.user() call that seems to be what I want to test my positive list against.
Also the hook could be a precommit hook that is distributed as part of the repository clone or it could be a hook on the central repository as a pre-incoming or something like that.
Any help or pointers would be greatly appreciated.
I have posted two functional examples on Bitbucket. Both examples are for searching a commit message for some specifically formatted text (like an issue tracked case ID), but could be easily modified to check a user against a list of valid users.
The first example is actually a Mercurial extension that wraps the 'commit' command. If it fails to find the appropriate text (or valid user in your case), it will prevent the commit from occurring at all. You can enable this in your .hgrc file by adding these lines:
[extensions]
someName = path/to/script/commit-msg-check.py
The second example uses a in-process pretxncommit hook, which runs between when the commit has been made, but before it becomes permanent. If this check fails it will automatically roll back the commit. You can enable this in your .hgrc file by adding these lines (assuming you kept the same file/function names):
[hooks]
pretxncommit.example = python:commit-msg-check-hook.CheckForIssueRecord
You can execute any Python code you like inside of these hooks, so user validation could be done in many ways.
Thanks for the examples dls.
In the end I decided to run it as a pretxnchangegroup hook and then use the hg log and grep to test the author field of the commits:
[hooks]
pretxnchangegroup.usercheck = hg log --template '{author}\n' -r \
$HG_NODE: | grep -qe 'user1\|user2\|etc'
It does of course not provide a very good feedback other than usercheck failed. But I think it is good enough for now.

Mercurial subrepo and relative path

I have a project, which I have a bitbucket repository for, and it is dependent on another project that I incorporate as a subrepo. Now, I don't have push access to the subrepository, nor do I want or need to--it's a pull-only relationship.
I realize that when you push the main repository, it will try to push the subrepositories, as well. Since I cannot do that, I pulled a local copy of the dependent project, at the same level as the main repository's directory. In essence, I have the following layout:
Main/ ; pushes to https://mine.org/Main
.hg/
.hgsub
Lib/
SubRepo/ ; clone of Main/../SubRepo/
.hg/
SubRepo/ ; local copy of https://forbidden.org/SubRepo
.hg/
The content of .hgsub is something like,
Lib/SubRepo = ../SubRepo
Then I cloned,
~/path/to/Main $ hg clone ../SubRepo/ Lib/SubRepo
So far, so good. The problem is, after I set this all up and committed the changes, when I try to push Main Mercurial will try to push SubRepo to https://mine.org/SubRepo, which does not exist, thereby failing the whole push operation.
Is there something I'm missing?
Why not just create a https://mine.org/SubRepo -- if you don't want to advertise it you can always turn on hide for it in the [web] section in its .hg/hgrc file. This is the pattern I'm used to, where you clone down the main repo and all the subrepos in the same layout at each place you'll use them: both your development box and your web-facing hgweb install.
Alternately, you could use a [subpaths] section in Main/.hg/hgrc with something like this in it:
[subpaths]
https://mine.org/SubRepo = https://forbidden.org/SubRepo
which should let you intercept the derrived target for the push and point it at a place that which it won't let you push, will let you see nothing has changed so push can continue.
It seems like what Mercurial is doing is legitimate: using the paths listed in your .hgsub it's attempting to push to a directory called 'SubRepo' that exists one level up from Main. This is obviously not what you want, so you'll probably have to work some magic here. I can think of two options:
If you can support this, place the local copy of forbidden.org's repository at C:/Forbidden/Subrepo or something like that, and use this absolute path in your .hgsub. Mercurial will be able to push to this and it should work.
There's no problem including the actual forbidden.org url as your subrepo address if you don't make any modifications to this repo. If there are no changes to the subrepo, your push should succeed. Of course, this is a fairly manual option and on a larger team it would be impossible to enforce. If you did accidentally commit some modification to the subrepo, you'd have to go through and use histedit or MQueues to pull it out, and that can be tricky with subrepos.