Mercurial
A very good alternativ to svn or git
Inhaltsverzeichnis
Installation
install mercurial to use as central repo-server
install mercurial
install mercurial from your prefered distro.
apt-get install mercurial
or
yum install mercurial
install svn-extension
install mercurial-svn extension
mkdir -p /usr/src/mercurial cd /usr/src/mercurial hg clone http://bitbucket.org/durin42/hgsubversion hgsubversion cd hgsubversion python ./setup.py build install
now tell mercurial where hgsubversion is build
edit file /etc/mercurial/hgrc
[extensions] rebase= svn=/usr/src/mercurial/hgsubversion/hgsubversion
from now on you can use hg-commands to pull svn repos
which are converted to mercurial equivalents.
for detailed usage look HERE!
now create a new or pull/convert a svn repo.
Note that you will have to call 'hg svn genignore' to convert svn:ignore proposals to .hgignore |
cd /var/repos/hg/repo_name hg svn genignore
Configuration (Server)
configure mercurial/apache to be a central repo-server
hgwebdir
to serve your repo through http(s) look HERE!
i will use hgwebdir-method which i will describe here.
locate hgwebdir.cgi which is delivered with mercurial package. for me ist here:
/usr/share/doc/mercurial/examples/hgwebdir.cgi
i copied it to somewhere suitable:
cp -a /usr/share/doc/mercurial/examples/hgwebdir.cgi /var/www/html/hgwebdir.cgi
now we have to configure hgwebdir.
note that hgwebdir.cgi expects its config in the same directory!! feel free to change that in hgwebdir.cgi which is a simple python-script |
so we create the config-file: /var/www/html/hgweb.config
[paths] my_repo_name = /var/repos/hg/repo_name
apache
now configure apache to serve...
edit you vhost file and add:
<VirtualHost aaa.bbb.ccc.ddd:80> [...] # set the script-alias ScriptAlias /repo "/var/www/html/hgwebdir.cgi" # protect you repo by password <Location /repo> AuthType Basic AuthName "Mercurial repositories" AuthUserFile /var/repos/hg/.htpasswd_mercurial Require valid-user </Location> [...] </VirtualHost>
if u use an explicit virtual host for repo use something like that:
<VirtualHost aaa.bbb.ccc.ddd:80> [...] ScriptAliasMatch ^(.*) /var/www/html/hgwebdir.cgi/$1 <Location /> AuthType Basic AuthName "Mercurial repositories" AuthUserFile /var/repos/hg/.htpasswd_mercurial Require valid-user </Location> [...] </VirtualHost>
If sharing with the world you should use a SSL-enabled virtual host!!! |
make apache be able to write to your repos:
chown apache:apache /var/repos/hg/*
restart apache!! ;-)
mercurial (hgrc)
if you get messages from 'hg [command]' like this:
Not trusting file /path/to/repos/myrepo/.hg/hgrc from untrusted user apache, group apache
then add apache-user to trusted user's-file. create a file in mercurials hgrc.d-directory:
vi /etc/mercurial/hgrc.d/trusted_users.rc
and add something like that:
[trusted] users = apache # comment in next line for trusted groups # and modify to your needs... #groups = fred, barney
now we had to allow push commands for users.
in my case all (authenticated) users may push!
all users may get repo as .gz, .zip, or .bz2
so decide if you want to allow that for ALL repos or on a per repo-base:
- /etc/mercurial/hgrc ==> allow for all repos
- <path_to_repo>/.hg/hgrc ==> allow for specific repo
[web] baseurl = https://hg.mydomain.tld/my_repo allow_push = * allow_archive = gz zip bz2
the only thing that HAS to be in repo's hgrc-file is baseurl |
for me i put the 2 allow-statements into /etc/mercurial/hgrc
and the baseurl into <path_to_repo>/.hg/hgrc
Hooks (Central Server)
be sure to add only hooks that should be triggered on server-side.
e.g. add hooks for commit-mails here...
or for disallowing to create 2 or more heads!!
for me this inline-hook works fine to prevent remote users
creating more than one head...
# This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. # # To forbid pushes which creates two or more headss # # [hooks] # pretxnchangegroup.forbid_2heads = python:forbid2_head.forbid_2heads from mercurial import ui from mercurial.i18n import gettext as _ def forbid_2heads(ui, repo, hooktype, node, **kwargs): if len(repo.heads()) > 1: ui.warn(_('Trying to push more than one head, try run "hg merge" before.\n')) return True
because this hook is global for all repos we put
the hook-config into /etc/mercurial/hgrc
[...] # global hooks for all repos # put repo-sprecific hooks to: # <path_to_repo>/.hg/hgrc [hooks] # prevent pushes that create 2 or more heads!!! # not allowed on central repo-server # /usr/lib64/python2.4/site-packages/myMercurialInlineHooks.py pretxnchangegroup.forbid_2heads = python:myMercurialInlineHooks.forbid_2heads [...]
the next is that ich want to be informed of changes to my central repo and who did it!
for that to do i activate an external(!) hook that send me an email.
i create a libexec-dir for mercurial hooks because i dont want to put bash, perl or
whatever scripts in the installation dir of mercurial which is installed to the python tree!
mkdir -p /usr/libexec/mercurial/hooks/
now i put my email-notify script in there mail-notify.sh:
#!/bin/bash RECIP="" MODULE="" while [ $# -gt 0 ] ; do case $1 in --recip|-r) shift RECIP="$RECIP $1" shift ;; --module|-m) shift MODULE=$1 shift ;; --module=*) MODULE=${1#--module=} shift; ;; --recip=*) RECIP="$RECIP ${1#--recip=}" shift; ;; esac done hg update -C SUBJECT=$(hg log -r $HG_NODE --template '{desc|firstline}') PARENT=$(hg log --debug -r $HG_NODE | sed -n '/^parent:/{s/^.*: *.*://;p}' | head -1 ) FILES=$(hg log -v -r $HG_NODE | sed -n '/^files:/{s/^.*: *//;p}') if [ -z "$FILES" -o "$HG_SOURCE" != "serve" ]; then exit 0 fi AUTHOR=`hg log -v -r $HG_NODE | sed -n '/^user:/{s/^.*: *//;p}' || echo hgadmin`; (hg log -vr $HG_NODE | egrep -v '^(changeset|parent|date):' | sed 's/^description:$//' \ | cat -s ; hg diff -r $PARENT -r $HG_NODE $FILES) | mail -s "$MODULE: $SUBJECT" $RECIP -- -f"$AUTHOR@mydomain.tld" ### EOF ###
activate this hook in repo's global config.
do NOT use /etc/mercurial/* to configure hook unless you only have one repo
or you have only ONE emailaddress where alle repos send their notification mails to.
AND note that you will not be able to see in which repo the change has been done!!!
for that reason i use the repo-config file at /<path_to_repo>/.hg/hgrc
to activate notifications.
[...] [hooks] changegroup = /usr/libexec/mercurial/hooks/mail-notify.sh --module my-repo-name --recip devel@mydomain.tld [...]
Configuration (Client)
configure your client to be userfriendly! ;-)
~/.hgrc
hg user config-file:
[ui] username = cs # prefix the keywords ''''prefix, username and password'''' with something you want<br/> # if you habe more than one server you want to use. # i prefix with SERVERNAME. [auth] server1.prefix = 10.x.y.zzz server1.username = cs server1.password = cspassword other_server.prefix = hg.other.server.tld other_server.username = cs other_server.password = cspassword_on_other_host [hooks] ...
General usage
keep in mind that mercurial creates a local repo
commits are are going to your local copy/clone and are NOT pushed to the
upstream-repository automatically!
Clone repo (svn checkout)
$ hg clone https://SERVER/path/repo my-repo-clone
creates an exact copy of the repo at SERVER
status of repo (changes)
$ hg status M some_changed_file.cpp ? some_new_file.cpp
show changes of files
$ hg diff some_changed_file.cpp /** - * + * + * + * + * * * @author Christoph Steidl * @since Mar 29, 2010 * @version 6.6.6 * @copyright netcar24 GmbH + * + * + *
revert changes
$ hg revert some_changed_file.cpp
reverts the file some_changed_file.cpp back to the last committed version
Commit changes (to local clone)
$ hg commit
shows up you default editor to enter a commit-comment in the 1st line.
following lines show the files to be commited
enter a comment!!! and write/quit the file...
if NO error appears, hg exits silently
or use -m "comment" on command-line e.g.
$ hg commit -m "my comment"
push changes (to upstream-repo)
$ hg push Remote: adding changesets Remote: adding manifests Remote: adding file changes Remote: added 1 changesets with 2 changes to 2 files $ _
no errors/conflicts
merge repo
if you push-command says something like:
abort: push creates new remote heads on branch 'default'! (you should pull and merge or use push -f to force)
then you will have to merge with changes somebody else has pushed before.
do the following steps:
- hg pull
- hg merge
- conficts are solved automatically if possible
- if NOT possigle:
- hg resolve [--all | FilePath/FileName]
- hg push
info output
hg tags
prints out the tags-list
note that the tag tip is the equivalent ouf your trunk in svn
so your trunk simply is your default-tag
# hg tags tip 4573:72a1a1c04f10 M9 2612:b248ea41c460 M8 2140:3ec0fd753656 trunk-with-XXX 2101:902dd0b485ee merge-xxxxxxx-YYY 1923:9ecb31562ad1 merge-xxxxxxx 1466:4fd4bc5a79fd
hg branches
prints out a list of created branches
# hg branches M9 4573:72a1a1c04f10 default 4571:5742e3be45c5 aa-yyyyy-utf8-fixes 3339:d914991eaa6c M8 2846:c7742dc608e9 M7 2375:0326a021977b trunk-before-zzz 2099:c24644d3367c changelogger-7462 1717:c46758e604b7