views:

52

answers:

2

As the definite guide aptly points out (search for "Tags and cloning"):

When you run hg clone -r foo to clone a repository as of tag foo, the new clone will not contain any revision newer than the one the tag refers to, including the revision where the tag was created. The result is that you'll get exactly the right subset of the project's history in the new repository, but not the tag you might have expected.

It means hg tags in your new clone does NOT show the foo tag. Same thing happens if you had cloned before foo tag was added, and you do hg pull -r foo.

(Digression: tag is about the only thing I don't quite get in hg. I understand there are advantages (e.g. merge) in putting it in a changeset, but it always feels weird to have meta data mixed with source code.)

It should be obvious that I'm asking for an automated way, instead of pulling the tag changeset as a separate manual step.

I know I could check for this scenario in an incoming hook (so it works for both clone and pull), or wrap clone and pull.

But is there a better/easier way?


UPDATE hg bug tracker already has this issue.

+1  A: 

There is a postclone hook. It's called post-clone (the hgrc manpage shows a post-ANYCOMMAND and pre-ANYCOMMAND exist) though as you pointed out you could also use *changegroup or update hooks too, since clone uses both of those functions (unless you suppress update with -U).

What about just adding a --localtag so you have the name but not the extra changeset if you need it for reference only. Something like

hg clone -r tagname URL
hg tag --local tagname

which you could easily build into a shell alias.

Other than that there's not necessarily guaranteed to be a way to have revision X and the revision where revision X is tagged without also having other revisions you don't want since the tag could have been applied after other work was done. You can, of course, always update to 'X' and to have subsequent changesets in you working dir, but they'll still be in your repo.

Honestly, once I figured out that the tag name doesn't come a long when you clone up to a tag, which I admit confused the heck out of me at first, I didn't find any need to bring along the changeset with the tag in it.

Ry4an
Thanks for the `post-clone` hook. I removed "and since there's no `postclone` hook" from the question. I don't quite like the local tag since I'll pull in the tag changeset some time later for sure. Also without the tag changeset, I may commit a tag myself, then I'll have to merge the tags.
Geoffrey Zheng
Yeah, it's not perfect but there's no way to do it w/o pulling additional changesets that you might not yet want (all those between the work and the tagging cset). At least tags merge seamlessly and the local's can't conflict or get pushed.
Ry4an
I'll only pull the tag changeset if it's the only child of the tagged. @Richard's answer gave me the idea to use a pre-clone and pre-pull hook to check for the case and change the clone/pull revision to the tag changeset. Will post back.
Geoffrey Zheng
+2  A: 

You want a giant hack with bash and an embedded Perl script? Well, here it is...

#!/bin/bash
if [[ "$1" == "" || "$2" == "" || "$3" == "" ]]; then
  echo 'hgclonetag <src> <tgt> <tag>'
  exit 1;
fi

REV=`hg log -R $1 --rev $3: --limit=2 | perl -F: -lane 'if (/:([\dA-Fa-f]+)$/) {print $F[2] if defined($flag);$flag=1;}'`
hg clone --rev $REV $1 $2

This invokes the hg log command to extract the revision number after the first tag-related revision and then clones to this revision.

Currently this does not work on remote repos: -R switch only works on local repos unfortunately.

Richard Cook
I surely would've accepted it had you not explicitly included git-tish words like "giant", "hack" (oops, did I just offend Lord Linus? *Remote thunder gathering...*), "bash", and "perl". I'm hoping for a small, elegant, hg-based, python solution :) +1 nevertheless.
Geoffrey Zheng
Should be straightforward to Pythonize this using `os.system` and some regular expression matching. Nice comment: +1 yourself!
Richard Cook
This wont work when you tag an old revision... if I do `hg tag -r 100 foo`, then I may be creating revision 1000. So fetching revision 101 wont bring in the tag.
Martin Geisler