Version 18 (modified by 14 years ago) ( diff ) | ,
---|
Mercurial Branches
This page documents how to use Mercurial, rather than Subversion, to hack on Django. See also DjangoBranches.
Core developers
For people who are core committers, and want to use Mercurial rather than Subversion as their client:
- Install the hgsubversion extension (and understand basically how it works).
- Clone the Subversion repository (do this using hg version 1.5 or higher, or else the changeset hashes generated by hgsubversion will be incompatible with those from repos generated using newer hg versions, including the official Django hg mirror).:
hg clone svn+http://code.djangoproject.com/svn/django/ django
This will take a Good While (lots of hours), and in some cases can take a Very Long Time for just one changeset (I gave up on r11505).
ALTERNATIVELY:- Clone the official Django hg mirror in the normal way, using hg 1.5 or greater.
- Edit .hg/hgrc to say:
default = svn+http://code.djangoproject.com/svn/django/
- Do
hg svn rebuildmeta
. This works because the official Django mirror was created by hgsubversion, and is updated only by hgsubversion.
- Use normal hg commands to make commits, switch branches, push back to the subversion repository etc. Remember to use
hg rebase --svn
, and nothg merge
.
Tips
- Use the bookmarks extension for git-style local feature branches, or named branches for feature branches that you need other people to see.
- Alternatively, use the queues extension to manage long lived patches.
- To collapse several commits into a single commit before pushing back to svn, use the histedit extension
- To backport a changeset from trunk, use the transplant extension. Or use this handy script which will generate the commit message for you:
The command line is like one of the following:
#!/bin/bash function usage { echo "Usage: hg_backport <branch> <hgrevision>"; echo " or: hg_backport <branch> --svnrev <svnrevision>"; } if [ $# -lt 2 ] then usage; exit 1; fi hg st -a -r -m | grep '' > /dev/null && { echo "Working directory not clean - exiting" > /dev/stderr; exit 1; } SHORTBRANCH="$1" BRANCH="releases/$SHORTBRANCH" if [ "$2" = "--svnrev" ] then SVNREV="$3" HGREV=`hg log -r "svnrev($SVNREV)" --template '{rev}'` if [ "x$HGREV" = "x" ] then echo "Can't find hg rev" exit 1; fi else HGREV="$2" SVNREV=`hg svn info -r $HGREV | egrep '^Revision' | cut -f 2 -d ' '` if [ "x$SVNREV" = "x" ] then echo "Can't find svn rev"; exit 1; fi fi echo "Backporting Subversion revision $SVNREV" hg update $BRANCH || exit 1; # Make a commit message first in case the transplant fails hg log -r $HGREV --template "[$SHORTBRANCH] {desc}\n\nBackport of [$SVNREV] from trunk.\n" > hg-commit-message.txt || exit 1 hg transplant $HGREV || exit 1; # Modify the commit message # We need to get added files, since after rollback this is forgotten ADDED=$(hg log -r tip --template '{file_adds}') REMOVED=$(hg log -r tip --template '{file_dels}') hg rollback > /dev/null || exit 1 if [ "x$ADDED" != "x" ] then hg add $ADDED || exit 1 fi if [ "x$REMOVED" != "x" ] then hg remove $REMOVED || exit 1 fi hg commit -l hg-commit-message.txt || exit 1 echo "Backport committed."
where 1.2.X is a directory under 'releases/' in the Subversion repo, 13643 is a hg revision ID, and 13237 is a Subversion revision ID. The change is already committed to the local repo, but not 'pushed', so you can still rollback if changes need to be made.hg_backport 1.2.X 13643 hg_backport 1.2.X --svnrev 13237
An alternate approach
Another way of doing the same thing: Use the --filter option to the transplant extension. This requires the use of a Python script. Put the following in backport.py, and stick it in a tools directory somewhere:
#!/usr/bin/python import os import sys msg = sys.argv[1] patch = sys.argv[2] print branch = os.environ.get('DJANGO_BRANCH',None) if branch is None: branch = raw_input('Backport branch: ') else: print "Backport branch:", branch msg_file = open(msg, 'r') outlines = [] firstline = True for raw_line in msg_file: line = raw_line.strip() if firstline: if line.startswith('#'): outlines.append(line) else: firstline = False print 'MERGING: %s' % line outlines.append('[%s] %s' % (branch, line)) else: outlines.append(line) msg_file.close() svn_revision = os.environ.get('SVNMERGE_REVISION',None) if svn_revision is None: svn_revision = raw_input('SVN Revision: ') else: print "SVN Revision:", svn_revision outlines.append('') outlines.append('Backport of r%s from trunk.' % svn_revision) # And write the updated message file. msg_file = open(msg,'w') for line in outlines: print >> msg_file, line msg_file.close() # In case of a clash, write the filename of the message file print "Log message written to",msg
Then, use the following shell script to do the actual backport:
export SVNMERGE_REVISION=`hg svn info -r $1 | egrep '^Revision' | cut -f 2 -d ' '` export DJANGO_BRANCH=`hg branch | cut -f 2 -d '/'` hg transplant $1 --filter /path/to/backport.py unset SVNMERGE_REVISION unset DJANGO_BRANCH
If you call this script 'hg_backport', then
The command line is like:
hg_backport 13643
Any hg revision ID can be used as the argument; since the most common usage pattern is to backport the most recent svn commit on trunk, you can use 'tip':
hg_backport tip
Gotchas
If you make two commits, and only want to push the first, you will have some trouble, since the HgSubversion extensions doesn't support specifying revisions with the hg push
command when pushing to a Subversion repository. Nice solutions to this welcome!