How to push code to multiple servers by Mercurial? - mercurial

How can we push code to multiple servers? We have many servers which needs to have the same copy of the code. It is difficult to push to individual server. I know mercurial has hooks but none of them gives a proper solution.

In your central server you create a changegroup hook.
So your central server would have the following hgrc:
[paths]
server2=http://server2
server3=http://server3
[hooks]
changegroup.server2 = hg push -f server2
changegroup.server3 = hg push -f server3
You can have multiple hooks for the same event, so that shouldn't be an issue.
The advantage of the changegroup hook over the changeset hook is that it is run far less often.

In your .hg/hgrc file you should have a [paths] directive, which contains your default location. What about adding something like:
[paths]
default = http://server1
server2 = http://server2
And then do a:
hg push default
hg push server2

i assume that one of the servers is a master repo, the rest are deployments. in such a situation, i would interact with just the master and leave the deployments up to cron:
cat >$HOME/bin/dist <<'EOM'
#!/bin/sh
cd ${1:?}
tip=$(hg tip --template '{node}')
for r in $remotes; do
hg push -r $tip $r
done
EOM
chmod +x $HOME/bin/dist
(crontab -l; echo '*/5 * * * * $HOME/bin/dist /var/repos/master') | crontab -

Related

Push secret changesets

That may look paradoxical, I know that secret changesets are meant to be private, but what if I want to backup those secret changesets?
I work with some branches in parallel and sometimes I want to push one, but not the others. To achieve that, I work in separate clones but I hate that.
So now mercurial has phases, I can make secret branches and have everything in the same repository. The problem is that between the beginning of the secret branch and its publication, I want to backup those secret changesets (I have a clone in another machine just to hold my backups in case something happens with my local repo or my machine).
Is there a way of doing that or my workflow is completly wrong?
No need to mark anything secret. If you only want to push one branch, use:
hg push -r REV
This will push REV and its ancestors only.
Secret is good for Mercurial patch queue revisions, since they can't be pushed anyway and it prevents a local clone from copying them.
Draft is good for tracking unpushed changes. If you still want to back them up, pushing them will flip them to Public, but you can reset them back to draft (as compared to another repository) with:
hg phase -fd 'outgoing(URL)'
(URL can be blank for the default push repo).
It seems like phases are still relatively new and some workflows, such as this, don't seem to be included, yet. As of 2013-03-19, I believe the only way you can do this is manually changing the phases from secret to public.
You can use these commands from the command line:
for /f "delims=" %a in ('hg log --template "{rev} " -r "secret()"') do #set secret=%a
hg phase -d %secret%
hg push -f
hg phase -sf %secret%
This doesn't change the commits to secret on the repository you are pushing to, I tried to change the push to do this (but was unsuccessful):
hg push -f --remotecmd hg phase -sf %secret%
The commits would have to match exactly for the remote hg command to work, but I couldn't get it to change on the remote repository anyway.
============================================================
If you want to use a GUI like TortoiseHG Workbench you will have to do this all manually (change the phases in the GUI on any repositories you want to) at the moment. Sorry, and hopefully, we can find a better solution, soon!
The best approach is a combination of #mischab1's answer, #mark-tolonen's answer and aliases.
By following mischab1's answer, you make sure that pushing to your backup location will not change the phase to "public".
Second step would be to add the backup location to your repository's hgrc/paths:
[paths]
default = ...
backup = backup_location
The next step is to define a backup command via alias in the global hgrc, e.g. "bubr" (for backup current branch) or "burev" (backup current rev).
[alias]
bubr = push -b . backup
burev = push -r . backup
hg bubr or hg burev will then push the current branch/revision to the location defined as "backup" path.
Edit This still has the drawback that you could accidentally push all changes with "hg push" so defining also an hg pubr command to push the current branch and not using "hg push" per default might be helpful.
This is the best I have come up with so far. I think its essentially equivalent to what you want push/pull to be able to do.
Mark all the secret changesets you want to transfer as draft
In the source repo run hg bundle -r last_draft_rev bundlefile.hg path\to\backup\repo
In the destination repo run hg unbundle bundlefile.hg
The changesets will come into the backup as DRAFT
Mark the first draft changeset as secret, and all its descendants will be marked thusly
I couldn't get #2 to work if the changesets were still marked secret.
#echo off
rem hgfullpull_naive.cmd
setlocal
set SRC_REPO=%~f1
set DST_REPO=%~f2
set TMP_DIR=%TEMP%\%~n0.tmp
set NODES_LIST=%TMP_DIR%\%~n0.%RANDOM%.tmp
if "%SRC_REPO%"=="" exit /b 1
if "%DST_REPO%"=="" exit /b 1
if "%SRC_REPO%"=="%DST_REPO%" exit /b 1
call :ALL
del /Q "%NODES_LIST%"
endlocal
goto :eof
:ALL
md "%TMP_DIR%"
hg log --rev "secret()" --template "{node}\n" --repository "%SRC_REPO%" >"%NODES_LIST%" || exit /b 1
call :CHANGE_PHASE "%SRC_REPO%" --draft
hg pull --repository "%DST_REPO%" "%SRC_REPO%"
call :CHANGE_PHASE "%SRC_REPO%" --secret
call :CHANGE_PHASE "%DST_REPO%" --secret
goto :eof
:CHANGE_PHASE
setlocal
set REPO=%~1
set PHASE=%~2
for /F "eol=; delims= usebackq" %%i IN ("%NODES_LIST%") DO (hg phase %PHASE% --force --rev %%i --repository "%REPO%")
endlocal
goto :eof
The easiest thing to do now-days, is to mark your backup repository as non-publishing by adding the following to its hgrc config file.
[phases]
publish = False
See Mercurial's Wiki for more info.

Get tip changeset of remote Mercurial repository

My .hg/hgrc file has the line:
default = http://some/remote/repository
Is there a quick command to print the tip revision of that repository (which may or may not be inside my local repository)?
You can use the identify command like this:
$ hg identify $(hg paths default)
This is one of the few commands that can operate on a remote repository. If you need more information about the remote repository, then I suggest you take a look at hg incoming.
The following returns the latest changeset number (tip) of a remote repository:
hg identify --id http://www.myrepo.com
hg id default
This is a shorter form of "hg identify $(hg paths default)".

How can I add remote repositories in Mercurial?

I am working with Git repositories in the following way:
I have the master repository and several remotes on the different production machines.
I am pushing the production code to the remotes and restart the services for the changes to take effect.
I am about to switch from Git to Mercurial and I would like to know ahead how I can achieve something like that.
You add entries to the [paths] section of your local clone's .hg/hgrc file. Here's an example of a section that would go in the .hg/hgrc file:
[paths]
remote1 = http://path/to/remote1
remote2 = http://path/to/remote2
You can then use commands like hg push remote1 to send changesets to that repo. If you want that remote repo to update is working directory you'd need to put a changegroup hook in place at that remote location that does an update. That would look something like:
[hooks]
changegroup = hg update 2>&1 > /dev/null && path/to/script/restart-server.sh
Not everyone is a big fan of having remote repos automatically update their working directories on push, and it's certainly not the default.
if you want to add default path, you have to work with default in your ~project/.hg/hgrc file. As Follows:
[paths]
default = https://path/to/your/repo
Good Luck.
You could have a look at hg-git GitHub plugin:
adding the ability to push to and pull from a Git server repository from Mercurial.
This means you can collaborate on Git based projects from Mercurial, or use a Git server as a collaboration point for a team with developers using both Git and Mercurial.
Note: I haven't tested that tool with the latest versions of Mercurial.
If you're on Unix and you have Git installed, you can use this bash function to readily add a path to the remotes without a text editor:
add-hg-path() {
git config -f $(hg root)/.hg/hgrc --add paths.$1 $2
awk '{$1=$1}1' $(hg root)/.hg/hgrc > /tmp/hgrc.tmp
mv /tmp/hgrc.tmp $(hg root)/.hg/hgrc
}
Then invoke it with:
$ add-hg-path remote1 https://path.to/remote1
If someone would like to build a Powershell equivalent, I'd like to include that as well. Other potentials improvements include error checking on the parameters and factoring out the call to $(hg root).

List remote branches in Mercurial

Is there a way to list remote branches in Mercurial like there in Git?
git branch -r
I want to list the branches on a remote machine (e.g. Bitbucket), so using:
hg branches -R `hg showconfig paths.default` --color false
fails with abort: repository not local
The mercurial API allows it:
from mercurial import ui, hg, node
peer = hg.peer(ui.ui(), {}, 'http://hg.python.org/cpython')
for name, rev in peer.branchmap().items():
print(name, node.short(rev[0]))
The above snippet produces:
default aaa68dce117e
legacy-trunk b77918288f7d
3.2 4787b9b2f860
3.0 4cd9f5e89061
3.1 5a6fa1b8767f
2.3 364638d6434d
2.2 61b0263d6881
2.1 e849d484029f
2.0 5fd74354d73b
2.7 260f3ad7af4b
2.6 f130ce67387d
2.5 b48e1b48e670
2.4 ceec209b26d4
No, it is not possible to list branches of a remote repository without cloning it to local.
If there is SSH access to the machine having the remote repository, then Mercurial could be used directly: ssh server hg -R path/to/repo branches.
If the repository is served with hgweb, then a list of branches can be fetched from that, using the raw style for easy parsing: https://www.mercurial-scm.org/repo/hg/branches?style=raw
BitBucket has its own API, where it is possible to get the branches, see their help and make a query like to a URL like https://api.bitbucket.org/1.0/repositories/mirror/mercurial/branches/
To expand on #gvalkov’s answer, you can make this a real extension by writing a file rheads.py:
from mercurial import hg, commands, cmdutil, node
cmdtable = {}
command = cmdutil.command(cmdtable)
#command('rheads', commands.remoteopts, 'hg rheads [SOURCE]')
def rheads(ui, repo, source='default', **opts):
"""print (possibly remote) heads
Prints a series of lines consisting of hashes and branch names.
Specify a local or remote repository, defaulting to the configured remote.
"""
other = hg.peer(ui or repo, opts, ui.expandpath(source))
for tag, heads in other.branchmap().iteritems():
for h in heads:
ui.write("%s %s\n" % (node.short(h), tag))
When configured in ~/.hgrc with
[extensions]
rheads = …/rheads.py
you can run it like:
hg rheads
I tried to make it a command that can be invoked outside any repository, just specifying the URL as an argument, but could not get the syntax to work:
commands.norepo += " rheads"
maybe you are looking for hg incoming -B This worked quite well for me. This shows the bookmarks.
Please note, this will not display remote only branches, it will only show branches that your local repository is aware of.
As the only relevant question to appear when googling "hg command line list branches", I thought I'd leave this here. When you run the following -
hg log | grep "branch" | grep -v "summary" | sort --unique
it outputs;
branch: branch1
branch: branch2
branch: branch3
branch: branch4
branch: branch5

In Mercurial, after "hg init" to create a project and pushing onto server, how to make local directory to have "hg path" of the server?

When a project is started with
mkdir proj
cd proj
hg init
[create some files]
hg add file.txt
hg commit
hg push ssh://me#somewhere.somehost.com/proj
now when hg path is issued, nothing will show. How do we actually change the repository so that it is as if it is cloned from me#somewhere.somehost.com/proj ? Is it just by editing .hg/hgrc and adding
[paths]
default = ssh://me#somewhere.somehost.com/proj
because that feels like too low level an operation to do (by editing a text file)
It's the only way to do it in this situation. There are plenty of other cases where you have to edit the hgrc by hand, like setting up hooks or enabling extensions, so it's not as if it's unusual.
(As you probably already know, hg clone will set the path entry in the clone to point back to the original.)