How to embed version information in source code with Mercurial - mercurial

I would like to embed some version information on top of my source code file with information such as version number, author, and date of edit.
Is there a simple way to do this with Mercurial?

This has been asked a lot here on Stackoverflow and the short answer is: you shouldn't do it.
You don't want a file that changes with every commit it makes merging a nightmare.
Better options are:
write the version string to a file on update
have you build/deploy script run $(hg id) and put that into the build at that time
Trust me, revision strings in files is CVS/SVN thinking. It has no place in a git / Mercurial world.

As comments and other answers mention, it is not a good idea to rely on CVS-like, automatically expanded, tags. Specially since you can extract whatever meta-information you need at any time and almost any granularity afterwards.
However, if you really need it (because your boss says so, for instance), the closest you can get is by making use of the keyword extension that comes bundled with mercurial.

My favorite way is to use the hgversioninfo plugin.
It generates a version.py file on the fly on "hg commit", "hg update", etc.

Yes it is possible, but you need to enable it. What you are asking for is basically the keyword extension. Be careful when enabling this the first time (read the section about kwshrink, kwexpand), because you wouldn't want the actual expanded keywords to become part of the revision history.

Related

Given a file, how to find out which revision in a mercurial repository this is?

Assume that there is a file under hg version control. I have a particular version of that file, and I would like to find out in which revision this file was in this version.
I suspect that there are two possible ways to do this.
Do hg update in a loop and diff the file against subsequent versions (sloooow, but should work).
Make Mercurial put the rev number in a, say, comment in the second line of the file right before committing. From what I have read, a precommit hook might be of use. Then I don't have to compare anything, just look at the file itself (I'm assuming no-one will change this, of course, but this is rather safe assumption in my case).
My use case is a joint paper, written in LaTeX, with two coauthors who have no idea about version control at all, but I prefer to use it (for obvious reasons). We communicate by email, and there's effectively a human-based lock system ("I will not work on this file until you send me the next version, ok?"). The only problem that arises is that I'm sending version X to author B to proofread, then author C sends me a corrected version Y and I commit it into my repo, then author B sends his corrections Z (to version X) and I'm starting to get lost-but I can check the attachment in the email sent to B, and I only need to find out which revision it is.
So, my question is: which of the two ideas above would be better, or maybe there's yet another one to help me deal with this mess?
hg archive is good method for future work, but I can suggest at least 3 alternative work-styles and 1 fix for find-correct-version with updates
Future work
You can use separate named branches for co-authors and default for merged results, send co-author always head from his branch, update his branch after getting corrections (you'll always know, that you sent) and merge branches to default
One branch, revision-of-coworker marked with bookmark, which you later move to next point
Mercurial keywords considered somehow as a "feature of last resort", but in your case it's obvious and usable solution: just add keyword with hash-id in file (defaul extension instead of hook - easier and more reliable)
Current state
For finding changeset with source of file, you can try to use bisect (example) and test in test-script, f.e, CRC of file (you have needed CRC of unversioned file, check versioned file across history)
If you're happy to rely on finding the emails you send the reviewers, why not just include the revision hashes in them along with the files?
You can get this for almost zero extra effort by generating your attachment using hg archive, which will create a file containing 1) your files for review, and 2) .hg_archival.txt, complete with revision hash.
Though I'd be surprised if there isn't a more elegant way, even if your collaborators are dead-set against using version control.

Is it possible to change the username on a mercurial changeset based on the commit message?

I am converting a CVS repository (actually a number of them) into a Mercurial setup, and was wondering if any one had experience with updating and correcting usernames in the changesets.
The issue is that over quite a long period of time a default user has been used fairly often to commit to the CVS repository, and the commit message has then been supplied with '(initials)' at the end to identify the actual person committing. And now that I am converting to Mercurial I would like to clean this up, by setting the correct username.
Having done some research this seems non-trivial and I was thinking that something along the lines of this:
convert to hg and tag/branch commits with a specific initial in the commit message, using --config convert.cvsps.mergeto='{{mergetobranch ([-\w]+)}}'
converting this new repository and then use the --authormap to edit the default user to the persons initials.
But I am unsure if it is possible to selectively convert out branches and then get it back into its original place in the history.
Any help or ideas would be greatly appreciated. I have of course fully control of all the repository clones since it is not published in any way.
You need to use the Convert extension. You can follow the answer from this post.
The Convert extension sadly doesn't provide a convenient way to have conditional author mappings, but it does permit performing the conversion incrementally. You can then perform your conversion in small steps, inside of which a single author map is valid. You can use also script the generation of these "fence post" commits.
I had a similar problem today, where I wanted to conditionally change the username in some old commits in a Mercurial repository. I've bundled up all of my steps into a convenient script, which you can find here. The downside is that it depends on some Mercurial specific behavior, but you can work around this by first converting with a basic, non conditional author map, and then running the conditional conversion on the that repository.
This question is rather old, but if you don't have too many clones out in the wild, it may still be worth your while to run the author-name correcting conversion. Remember: hg convert necessarily changes the hash for every changeset, so you have to deal with all the usual issues of EditingHistory. I suspect this is part of the reason why both of the usual ways of dealing with this, Mercurial Queues and the newer HistEdit Extension, don't play nice with merge changesets -- it's difficult and messy to redo a non-leaf merge, and the presence of merges often indicates that you've shared the repository, which means you should reconsider editing history.

mercurial temporarily ignore versioned files

My question is essentially the same as here but applies to mercurial. I have a set of files that are under version control, and one save operation changes quite a lot of files. Some of the resulting changes are important for revision control, and some of the changes are just junk. I can "partition" off the junk into separate files. These junk files need to be part of a basic checkout in order for it to work, but their contents (and changes over time) aren't that important for revision control. Right now I just tell all our developers not to commit these files, but we all forget and it creates a lot of extra baggage in the repository. I don't really like the svn solution proposed because there are quite a lot of files and I want a simple clone to just work without all this extra manual work, so I was wondering if mercurial has a better alternative. It's kind of like hg shelve but not quite, and kind of like ignore, but not quite. Is there some hg extension that allows for this? Can git do it?
Mercurial doesn't support this. The correct way to do it is to commit thefile.sample and then have your developers (or better you deploy script) do a copy from thefile.sample to thefile if thefile doesn't exist. That way anyone can update the example file, but there's no risk of them committing their local changes (say their personal database connect string).
Aha! So TortoiseHG's repository and global settings have an Auto Exclude List where you can define a list of files that will be unchecked by default when the status, commit, and shelve dialogs open. So they still show up, but the user has to check them in order to actually do a commit. The setting is stored in hgrc, but it's under the [tortoisehg] heading so it's not supported by mercurial per se. Nevertheless, it fits my needs.
One solution to this is to use nested tree support (submodule in git), where the "junk" would be put in a different repository (to avoid cluttering the main repo), while enabling checking out the whole thing out in a consistent manner (right version of both repos in sync).
https://www.mercurial-scm.org/wiki/Subrepository?action=show&redirect=subrepos
In git, submodules are one solution to this issue - but they are not that great UI-wise. What I do instead is to keep two completely independent repositories, and using the subtree merge strategy when I need to update the main repo with the junk repo: http://progit.org/book/ch6-7.html

How good is my method of embedding version numbers into my application using Mercurial hooks?

This is not quite a specifc question, and more me like for a criticism of my current approach.
I would like to include the program version number in the program I am developing. This is not a commercial product, but a research application so it is important to know which version generated the results.
My method works as follows:
There is a "pre-commit" hook in my .hg/hgrc file link to version_gen.sh
version_gen.sh consists solely of:
hg parent --template "r{rev}_{date|shortdate}" > version.num
In the makefile, the line version="%__VERSION__% in the main script is replaced with the content of the version.num file.
Are there better ways of doing this? The only real short coming I can see is that if you only commit a specfic file, version.num will be updated, but it won't be commited, and if I tried to add always committing that file, that would result in an infite loop (unless I created some temp file to indicate I was already in a commit, but that seems ugly...).
The problem
As you've identified, you've really created a Catch-22 situation here.
You can't really put meaningful information in the version.num file until the changes are committed and because you are storing version.num in the repository, you can't commit changes to the repository until you have populated the version.num file.
My solution
What I would suggest is:
Get rid of the "pre-commit" hook and hg forget the version.num file.
Add version.num to your .hgignore file.
Adjust version_gen.sh to consist of:
hg parent --template "r{node|short}_{date|shortdate}" > version.num
In the makefile, make sure version_gen.sh is run before version.num is used to set the version parameter.
My reasons
As #Ry4an suggests, getting the build system to insert revision information into the software at build time, using information from the Version Control System is a much better option. The only problem with this is if you try to compile the code from an hg archive of the repository, where the build system cannot extract the relevant information.
I would be inclined to discourage this however - in my own build system, the build failed if revision information couldn't be extracted.
Also, as #Kai Inkinen suggests, using the revision number is not portable. Rev 21 on one machine might be rev 22 on another. While this may not be a problem right now, it could be in the future, if you start colaborating with other people.
Finally, I explain my reasons for not liking the Keyword extension in a question of mine, which touches on similar issues to your own question:
I looked at Mercurials Keyword extension, since it seemed like the obvious solution. However the more I looked at it and read peoples opinions, the more that I came to the conclusion that it wasn't the right thing to do.
I also remember the problems that keyword substitution has caused me in projects at previous companies. ...
Also, I don't particularly want to have to enable Mercurial extensions to get the build to complete. I want the solution to be self contained, so that it isn't easy for the application to be accidentally compiled without the embedded version information just because an extension isn't enabled or the right helper software hasn't been installed.
Then in comments to an answer which suggested using the keyword extension anyway:
... I rejected using the keyword extension as it would be too easy to end up with the string "$Id$" being compiled into the executable. If keyword expansion was built into mercurial rather than an extension, and on by default, I might consider it, but as it stands it just wouldn't be reliable. – Mark Booth
A don't think that there can be a more reliable solution. What if someone accidentally damages .hg or builds not from a clone but from an archive? – Mr.Cat
#Mr.Cat - I don't think there can be a less reliable solution than the keywords extension. Anywhere you haven't explicitly enabled the extension (or someone has disabled it) then you get the literal string "$ID$" compiled into the object file without complaint. If mercurial or the repo is damaged (not sure which you meant) you need to fix that first anyway. As for hg archive, my original solution fails to compile if you try to build it from an archive! That is precisely what I want. I don't want any source to be compiled into our apps without it source being under revision control! – Mark Booth
What you are trying to do is called Keyword Expansion, which is not supported in Mercurial core.
You can integrate that expansion in make file, or (simpler) with the Keyword extension.
This extension allows the expansion of RCS/CVS-like and user defined keys in text files tracked by Mercurial.
Expansion takes place in the working directory or/and when creating a distribution using "hg archive"
That you use a pre-commit hook is what's concerning. You shouldn't be putting the rest of version_gen.sh into the source files thesemves, just into the build/release artifacts which you can do more accurately with an 'update' hook.
You don't want the Makefile to actually change in the repo with each commit, that just makes merges hell. You want to insert the version after checking out the files in advance of a build, which is is what an update hook does.
In distributed systems like Mercurial, the actual "version number" does not necessarily mean the same thing in every environment. Even if this is a single person project, and you are really careful with having only your central repo, you would still probably want to use the sha1-sum instead, since that is truly unique for the given repository state. The sha1 can be fetched through the template {node}
As a suggestion, I think that a better workflow would be to use tags instead, which btw are also local to your repository until you push them upstream. Don't write your number into a file, but instead tag your release code with a meaningful tag like
RELEASE_2
or
RELEASE_2010-04-01
or maybe script this and use the template to create the tag?
You can then add the tag to your non-versioned (in .hgignore) version.num file to be added into the build. This way you can give meaningful names to the releases and you tie the release to the unique identifier.

Moving from Visual Sourcesafe to Mercurial

What's the best way to move a Visual Sourcesafe repository to Mercurial (I'm interested in retaining all history)?
While I haven't made that particular conversion, I have gone from VSS to SVN using (IIRC) this script. You'll probably want to look into tailor and do a search for vss2hg. Also keep in mind that it may make sense to go through an intermediate step like vss2svn + svn2hg or similar.
The primary bit of advice I'd give though is: script the conversion so you can re-run it easily. That will let you run nightly conversions from VSS to Hg and make sure that everything is converting correctly before you pull the trigger on it.
I am the author of the vss2hg.pl script and have used it to move many projects from VSS to Mercurial. It has one or two minor bugs where some comments are not completely converted but I haven't seen any other issues. It converts complete history and works-around a problem with VSS where a user's PC clock can affect the order in which changes appear to be made.
A version of the script is available here.
I used the vss2hg.pl script from here. It is a Perl script, so you need to install ActivePerl first.
It worked great, but I ran into a problem with the dates. It turns out that the script supports three kinds of date formats. By default it is set to the UK date format (in line 547). The other two date formats are commented out in the code. After enabling the US date format, the script converted my SourceSafe database without a problem.
The Mercurial wiki has this page, which might be of interest: https://www.mercurial-scm.org/wiki/SourceSafeConversion. I've never used Visual source safe, so I don't have any personal experience with it.
I also found a mail from Patrick Mézard about the subject, but unfortunately he writes that a VSS converter will be difficult. He also talks about converting to Subversion first, and then from Subversion to Mercurial. I guess that means that there are VSS -> SVN converts out there. You can probably google that yourself.
I have done a conversion from SourceSafe to Mercurial for a client. I first converted the SourceSafe database to a Subversion repository and then from Subversion to Mercurial using the hg convert extension. See my blog post for details.
I just tried using vss2hg and ran into a problem that it only pickup up and converted 1 user. This means all my changesets etc will not be accurate as I won't be able to see who did them. Is this because I've not pre-setup all the required users in hg?