Mercurial

Aus SchnallIchNet
Wechseln zu: Navigation, Suche

A very good alternativ to svn or git

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.

Achtung.jpeg 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.

Achtung.jpeg 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>
Achtung.jpeg 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
Achtung.jpeg 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:

  1. hg pull
  2. hg merge
    1. conficts are solved automatically if possible
    2. if NOT possigle:
      1. hg resolve [--all | FilePath/FileName]
  3. 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