Is it possible to add custom field to mercurial log? - mercurial

we're moving from Subversion to Mercurial now. In Subversion there was possibility to add custom column into log (e.g. bug id) and force user to fill this column on every commit.
Is it possible to implement such feature in Mercurial?

Yes it's possible.
But before you go and do that, why isn't it enough to require bug fix commit messages to uphold to a certain pattern?
i.e. util: rename the util.localpath that uses url to urllocalpath (issue2875) (taken from Mercurial's repo)
Then you can install a hook on your central repository that scans incoming commit messages, and does whatever is needed when that pattern is found.
Furthermore, why would you want to force this on every commit? Is this for a QA team that should only commit bug fixes? If that's the case, a pre-commit hook that greps the commit message for the pattern sounds appropriate.
If you still want the extra field: when Mercurial commits something, it is possible to pass it a dictionary of strings, which you can fill with anything. See the transplant extension on how you might do that. You would also need to wrap the commit command and add a new command line option to it.
But I strongly suggest you think twice before doing this, because aside from the time consuming work involved in coding, testing (and maintaining this between Mercurial releases), you would also need to ensure that it is deployed on every environment where Mercurial is used.

Related

Mercurial: Prevent commiting certain changes

I'm sure we've all done that thing where you temporarily hot-wire part of your application while you test something. We really don't want to commit such changes though.
Usually I mark such lines with a comment reminding me not to commit this change. But is there some way I can program Mercurial itself to refuse to commit any line containing a certain text fragment? (Not the entire file, just the marked line.) Is there some extension or something that does that?
The answer is a clear 'No, but...' (or 'Yes, but...' - depends on how you see it).
If you always indicate WIP lines in the same manner, I recommend to write and install a (local) commit hook which will fail, if any such WIP lines are detected in the changeset.
See https://www.mercurial-scm.org/wiki/Hook and https://www.mercurial-scm.org/wiki/UsefulHooks
In order to commit only some hunks, you can make use of the record extension (it's a default extension, just needs enabling). It allows you to cherry-pick the hunks at commit time. But it will fail at cherry-picking if the WIP code and the 'actual' code are in the same hunk.
Contrary to (good and correct in terms of sense) platetmaker's answer I'll suggest another way:
Enable, learn and use MQ Extension (see also Tutorial page) or, as lightweight alternative, Shelve Extension
Store your WIP (modifications in working directory) as MQ-patches or shelves locally until they aren't finished

Mercurial precommit script to change a file

Despite the decentralized nature of Mercurial, we have a centralized server that we all push to and that does nightly builds, packaging, etc...
Here's what we want to achieve: One of the files that is source controlled contains the major+minor version numbers which ideally would have to be increased with every commit. Since centralized numbering is not possible on developer's machines, we were thinking of a precommit script on the main server that would write a new minor version number to that file for each commit that is pushed. The question is/are:
since it's precommit, can this file change be part of the same commit?
if not, can precommit cause another commit and how do you prevent it from cascading/recursing?
how would one do that?
is there a better solution?
A "precommit" script is triggered only at commit time. By the time users are pushing to the "central" server they have already committed, and it's too late for a precommit hook to do anything at all. You can have changegroup and incoming hooks that are triggered to run on the "central" server when the developers push, but those can't modify the commits -- the commits are already committed/baked/done at that point, they can only react to them.
As a suggestion don't actually put the version string in the file -- having a file that changes with every commit just makes merging a pain. Instead do one or more of these:
have a CI server (like Jenkins) do builds on every push and use the Jenkins build number, which can be passed into your build script
use the Mercurial nodeid (hash) as part of your version string so you can always knew exactly what revision is in a build -- and don't put it in a file, just query for it in your build (or deploy) script
use a changegroup hook to automatically tag-on-push, which applies a pretty (possibly sequential) name to the commits (note, this pretty much doubles your number of commits since every tag is a commit)
Personally, I use something like this in my build script:
build.sh --version_string=$(hg log -r . --template '{latesttag}.{latesttagdistance}-{node|short}')
That gets me version strings that look like "1.0.3-5fd8ed67272e" which can be roughly read as "built from the changeset three commits since version 1.0 was tagged with nodeid 5fd8ed67272e", which is pretty darn good -- and it's never saved into a file it's either baked into the compile (for compiled languages) or written into a VERSION file when my deploy script uploads it to the server.
See this page in the Mercurial documentation for some comments and ideas about this issue. See also How to expand some version keywords in Mercurial? and the other SO answers referenced there.

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.

How do I reject pushes to a Mercurial server based on a script, without risking a bad pull during that time?

I'd like to write a script that examines the incoming changesets on a push to a mercurial server and rejects the push if the changesets do not conform to a particular standard. It seems like my options are the prechangegroup, pre-changegroup, and pretxnchangegroup hooks. Unfortunately, the prechangegroup and pre-changegroup hooks do not appear to have access to the incoming changesets, so I would need pretxnchangegroup. But according to the documentation at http://hgbook.red-bean.com/read/handling-repository-events-with-hooks.html#sec:hook:pretxnchangegroup, this can lead to inconsistent state for people using the repository while the hook is executing:
"While this hook is running, if other Mercurial processes access this repository, they will be able to see the almost-added changesets as if they are permanent. This may lead to race conditions if you do not take steps to avoid them."
I'm really not crazy about random weirdness happening if someone does a pull while my script is in the process of rejecting a changeset. Is there another hook that I can use? If not, what are the "steps to avoid them" that I need to take? Is there a way I can lock the repository during my hook?
If you expand the comments for the quoted paragraph, Meister Geisler confirmed some users' observation that the issue was resolved since hg 1.2, such that the not-yet-permanent incoming changesets are not visible, thus will not be pulled.

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