bos@559: bos@559: dongsheng@625: bos@572: bos@559: Handling repository events with hooks bos@559: bos@559: Mercurial offers a powerful mechanism to let you perform bos@559: automated actions in response to events that occur in a bos@559: repository. In some cases, you can even control Mercurial's bos@559: response to those events. bos@559: bos@559: The name Mercurial uses for one of these actions is a bos@559: hook. Hooks are called bos@559: triggers in some revision control systems, but the bos@559: two names refer to the same idea. bos@559: bos@559: bos@559: An overview of hooks in Mercurial bos@559: bos@559: Here is a brief list of the hooks that Mercurial supports. bos@559: We will revisit each of these hooks in more detail later, in dongsheng@625: section . bos@559: bos@559: bos@559: changegroup: This bos@559: is run after a group of changesets has been brought into the bos@559: repository from elsewhere. bos@559: bos@559: commit: This is bos@559: run after a new changeset has been created in the local bos@559: repository. bos@559: bos@559: incoming: This is bos@559: run once for each new changeset that is brought into the bos@559: repository from elsewhere. Notice the difference from bos@559: changegroup, which is run bos@559: once per group of changesets brought bos@559: in. bos@559: bos@559: outgoing: This is bos@559: run after a group of changesets has been transmitted from bos@559: this repository. bos@559: bos@559: prechangegroup: bos@559: This is run before starting to bring a group of changesets bos@559: into the repository. bos@559: bos@559: bos@559: precommit: bos@559: Controlling. This is run before starting a commit. bos@559: bos@559: bos@559: preoutgoing: bos@559: Controlling. This is run before starting to transmit a group bos@559: of changesets from this repository. bos@559: bos@559: bos@559: pretag: bos@559: Controlling. This is run before creating a tag. bos@559: bos@559: bos@559: pretxnchangegroup: Controlling. This bos@559: is run after a group of changesets has been brought into the bos@559: local repository from another, but before the transaction bos@559: completes that will make the changes permanent in the bos@559: repository. bos@559: bos@559: bos@559: pretxncommit: bos@559: Controlling. This is run after a new changeset has been bos@559: created in the local repository, but before the transaction bos@559: completes that will make it permanent. bos@559: bos@559: bos@559: preupdate: bos@559: Controlling. This is run before starting an update or merge bos@559: of the working directory. bos@559: bos@559: bos@559: tag: This is run bos@559: after a tag is created. bos@559: bos@559: bos@559: update: This is bos@559: run after an update or merge of the working directory has bos@559: finished. bos@559: bos@559: bos@559: Each of the hooks whose description begins with the word bos@559: Controlling has the ability to determine whether bos@559: an activity can proceed. If the hook succeeds, the activity may bos@559: proceed; if it fails, the activity is either not permitted or bos@559: undone, depending on the hook. bos@559: bos@559: bos@559: bos@559: bos@559: Hooks and security bos@559: bos@559: bos@559: Hooks are run with your privileges bos@559: bos@559: When you run a Mercurial command in a repository, and the bos@559: command causes a hook to run, that hook runs on bos@559: your system, under bos@559: your user account, with bos@559: your privilege level. Since hooks are bos@559: arbitrary pieces of executable code, you should treat them bos@559: with an appropriate level of suspicion. Do not install a hook bos@559: unless you are confident that you know who created it and what bos@559: it does. bos@559: bos@559: bos@559: In some cases, you may be exposed to hooks that you did bos@559: not install yourself. If you work with Mercurial on an bos@559: unfamiliar system, Mercurial will run hooks defined in that bos@559: system's global /.hgrc\ bos@559: file. bos@559: bos@559: bos@559: If you are working with a repository owned by another bos@559: user, Mercurial can run hooks defined in that user's bos@559: repository, but it will still run them as you. bos@559: For example, if you hg pull bos@559: from that repository, and its .hg/hgrc defines a local outgoing hook, that hook will run bos@559: under your user account, even though you don't own that bos@559: repository. bos@559: bos@559: bos@559: bos@559: This only applies if you are pulling from a repository bos@559: on a local or network filesystem. If you're pulling over bos@559: http or ssh, any outgoing bos@559: hook will run under whatever account is executing the server bos@559: process, on the server. bos@559: bos@559: bos@559: bos@559: XXX To see what hooks are defined in a repository, use the bos@559: hg config hooks command. If bos@559: you are working in one repository, but talking to another that bos@559: you do not own (e.g. using hg bos@559: pull or hg bos@559: incoming), remember that it is the other bos@559: repository's hooks you should be checking, not your own. bos@559: bos@559: bos@559: bos@559: bos@559: Hooks do not propagate bos@559: bos@559: In Mercurial, hooks are not revision controlled, and do bos@559: not propagate when you clone, or pull from, a repository. The bos@559: reason for this is simple: a hook is a completely arbitrary bos@559: piece of executable code. It runs under your user identity, bos@559: with your privilege level, on your machine. bos@559: bos@559: bos@559: It would be extremely reckless for any distributed bos@559: revision control system to implement revision-controlled bos@559: hooks, as this would offer an easily exploitable way to bos@559: subvert the accounts of users of the revision control system. bos@559: bos@559: bos@559: Since Mercurial does not propagate hooks, if you are bos@559: collaborating with other people on a common project, you bos@559: should not assume that they are using the same Mercurial hooks bos@559: as you are, or that theirs are correctly configured. You bos@559: should document the hooks you expect people to use. bos@559: bos@559: bos@559: In a corporate intranet, this is somewhat easier to bos@559: control, as you can for example provide a bos@559: standard installation of Mercurial on an NFS bos@559: filesystem, and use a site-wide bos@559: /.hgrc\ file to define hooks that all users will bos@559: see. However, this too has its limits; see below. bos@559: bos@559: bos@559: bos@559: bos@559: Hooks can be overridden bos@559: bos@559: Mercurial allows you to override a hook definition by bos@559: redefining the hook. You can disable it by setting its value bos@559: to the empty string, or change its behaviour as you wish. bos@559: bos@559: bos@559: If you deploy a system- or site-wide /.hgrc\ file that defines some bos@559: hooks, you should thus understand that your users can disable bos@559: or override those hooks. bos@559: bos@559: bos@559: bos@559: bos@559: Ensuring that critical hooks are run bos@559: bos@559: Sometimes you may want to enforce a policy that you do not bos@559: want others to be able to work around. For example, you may bos@559: have a requirement that every changeset must pass a rigorous bos@559: set of tests. Defining this requirement via a hook in a bos@559: site-wide /.hgrc\ won't bos@559: work for remote users on laptops, and of course local users bos@559: can subvert it at will by overriding the hook. bos@559: bos@559: bos@559: Instead, you can set up your policies for use of Mercurial bos@559: so that people are expected to propagate changes through a bos@559: well-known canonical server that you have bos@559: locked down and configured appropriately. bos@559: bos@559: bos@559: One way to do this is via a combination of social bos@559: engineering and technology. Set up a restricted-access bos@559: account; users can push changes over the network to bos@559: repositories managed by this account, but they cannot log into bos@559: the account and run normal shell commands. In this scenario, bos@559: a user can commit a changeset that contains any old garbage bos@559: they want. bos@559: bos@559: bos@559: When someone pushes a changeset to the server that bos@559: everyone pulls from, the server will test the changeset before bos@559: it accepts it as permanent, and reject it if it fails to pass bos@559: the test suite. If people only pull changes from this bos@559: filtering server, it will serve to ensure that all changes bos@559: that people pull have been automatically vetted. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Care with <literal>pretxn</literal> hooks in a bos@559: shared-access repository bos@559: bos@559: If you want to use hooks to do some automated work in a bos@559: repository that a number of people have shared access to, you bos@559: need to be careful in how you do this. bos@559: bos@559: bos@559: Mercurial only locks a repository when it is writing to the bos@559: repository, and only the parts of Mercurial that write to the bos@559: repository pay attention to locks. Write locks are necessary to bos@559: prevent multiple simultaneous writers from scribbling on each bos@559: other's work, corrupting the repository. bos@559: bos@559: bos@559: Because Mercurial is careful with the order in which it bos@559: reads and writes data, it does not need to acquire a lock when bos@559: it wants to read data from the repository. The parts of bos@559: Mercurial that read from the repository never pay attention to bos@559: locks. This lockless reading scheme greatly increases bos@559: performance and concurrency. bos@559: bos@559: bos@559: With great performance comes a trade-off, though, one which bos@559: has the potential to cause you trouble unless you're aware of bos@559: it. To describe this requires a little detail about how bos@559: Mercurial adds changesets to a repository and reads those bos@559: changes. bos@559: bos@559: bos@559: When Mercurial writes metadata, it bos@559: writes it straight into the destination file. It writes file bos@559: data first, then manifest data (which contains pointers to the bos@559: new file data), then changelog data (which contains pointers to bos@559: the new manifest data). Before the first write to each file, it bos@559: stores a record of where the end of the file was in its bos@559: transaction log. If the transaction must be rolled back, bos@559: Mercurial simply truncates each file back to the size it was bos@559: before the transaction began. bos@559: bos@559: bos@559: When Mercurial reads metadata, it reads bos@559: the changelog first, then everything else. Since a reader will bos@559: only access parts of the manifest or file metadata that it can bos@559: see in the changelog, it can never see partially written data. bos@559: bos@559: bos@559: Some controlling hooks (pretxncommit and pretxnchangegroup) run when a bos@559: transaction is almost complete. All of the metadata has been bos@559: written, but Mercurial can still roll the transaction back and bos@559: cause the newly-written data to disappear. bos@559: bos@559: bos@559: If one of these hooks runs for long, it opens a window of bos@559: time during which a reader can see the metadata for changesets bos@559: that are not yet permanent, and should not be thought of as bos@559: really there. The longer the hook runs, the bos@559: longer that window is open. bos@559: bos@559: bos@559: bos@559: The problem illustrated bos@559: bos@559: In principle, a good use for the pretxnchangegroup hook would be to bos@559: automatically build and test incoming changes before they are bos@559: accepted into a central repository. This could let you bos@559: guarantee that nobody can push changes to this repository that bos@559: break the build. But if a client can pull bos@559: changes while they're being tested, the usefulness of the test bos@559: is zero; an unsuspecting someone can pull untested changes, bos@559: potentially breaking their build. bos@559: bos@559: bos@559: The safest technological answer to this challenge is to bos@559: set up such a gatekeeper repository as bos@559: unidirectional. Let it take changes bos@559: pushed in from the outside, but do not allow anyone to pull bos@559: changes from it (use the preoutgoing hook to lock it down). bos@559: Configure a changegroup hook so bos@559: that if a build or test succeeds, the hook will push the new bos@559: changes out to another repository that people bos@559: can pull from. bos@559: bos@559: bos@559: In practice, putting a centralised bottleneck like this in bos@559: place is not often a good idea, and transaction visibility has bos@559: nothing to do with the problem. As the size of a bos@559: project&emdash;and the time it takes to build and bos@559: test&emdash;grows, you rapidly run into a wall with this bos@559: try before you buy approach, where you have bos@559: more changesets to test than time in which to deal with them. bos@559: The inevitable result is frustration on the part of all bos@559: involved. bos@559: bos@559: bos@559: An approach that scales better is to get people to build bos@559: and test before they push, then run automated builds and tests bos@559: centrally after a push, to be sure all is bos@559: well. The advantage of this approach is that it does not bos@559: impose a limit on the rate at which the repository can accept bos@559: changes. bos@559: bos@559: bos@559: bos@559: dongsheng@625: bos@559: A short tutorial on using hooks bos@559: bos@559: It is easy to write a Mercurial hook. Let's start with a bos@559: hook that runs when you finish a hg bos@559: commit, and simply prints the hash of the changeset bos@559: you just created. The hook is called commit. bos@559: bos@559: bos@559: All hooks follow the pattern in this example. bos@559: bos@567: &interaction.hook.simple.init; bos@559: bos@559: You add an entry to the hooks section of your /.hgrc. On the left is the name of bos@559: the event to trigger on; on the right is the action to take. As bos@559: you can see, you can run an arbitrary shell command in a hook. bos@559: Mercurial passes extra information to the hook using environment bos@559: variables (look for HG_NODE in the example). bos@559: bos@559: bos@559: bos@559: Performing multiple actions per event bos@559: bos@559: Quite often, you will want to define more than one hook bos@559: for a particular kind of event, as shown below. bos@559: bos@567: &interaction.hook.simple.ext; bos@559: bos@559: Mercurial lets you do this by adding an bos@559: extension to the end of a hook's name. bos@559: You extend a hook's name by giving the name of the hook, bos@559: followed by a full stop (the bos@559: . character), followed by bos@559: some more text of your choosing. For example, Mercurial will bos@559: run both commit.foo and bos@559: commit.bar when the bos@559: commit event occurs. bos@559: bos@559: bos@559: To give a well-defined order of execution when there are bos@559: multiple hooks defined for an event, Mercurial sorts hooks by bos@559: extension, and executes the hook commands in this sorted bos@559: order. In the above example, it will execute bos@559: commit.bar before bos@559: commit.foo, and commit bos@559: before both. bos@559: bos@559: bos@559: It is a good idea to use a somewhat descriptive extension bos@559: when you define a new hook. This will help you to remember bos@559: what the hook was for. If the hook fails, you'll get an error bos@559: message that contains the hook name and extension, so using a bos@559: descriptive extension could give you an immediate hint as to bos@559: why the hook failed (see section for an example). dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: Controlling whether an activity can proceed bos@559: bos@559: In our earlier examples, we used the commit hook, which is run after a bos@559: commit has completed. This is one of several Mercurial hooks bos@559: that run after an activity finishes. Such hooks have no way bos@559: of influencing the activity itself. bos@559: bos@559: bos@559: Mercurial defines a number of events that occur before an bos@559: activity starts; or after it starts, but before it finishes. bos@559: Hooks that trigger on these events have the added ability to bos@559: choose whether the activity can continue, or will abort. bos@559: bos@559: bos@559: The pretxncommit hook runs bos@559: after a commit has all but completed. In other words, the bos@559: metadata representing the changeset has been written out to bos@559: disk, but the transaction has not yet been allowed to bos@559: complete. The pretxncommit bos@559: hook has the ability to decide whether the transaction can bos@559: complete, or must be rolled back. bos@559: bos@559: bos@559: If the pretxncommit hook bos@559: exits with a status code of zero, the transaction is allowed bos@559: to complete; the commit finishes; and the commit hook is run. If the pretxncommit hook exits with a bos@559: non-zero status code, the transaction is rolled back; the bos@559: metadata representing the changeset is erased; and the bos@559: commit hook is not run. bos@559: bos@559: bos@567: &interaction.hook.simple.pretxncommit; bos@559: bos@559: The hook in the example above checks that a commit comment bos@559: contains a bug ID. If it does, the commit can complete. If bos@559: not, the commit is rolled back. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Writing your own hooks bos@559: bos@559: When you are writing a hook, you might find it useful to run bos@559: Mercurial either with the option, or the verbose config item set to bos@559: true. When you do so, Mercurial will print a bos@559: message before it calls each hook. bos@559: bos@559: dongsheng@625: bos@559: Choosing how your hook should run bos@559: bos@559: You can write a hook either as a normal bos@559: program&emdash;typically a shell script&emdash;or as a Python bos@559: function that is executed within the Mercurial process. bos@559: bos@559: bos@559: Writing a hook as an external program has the advantage bos@559: that it requires no knowledge of Mercurial's internals. You bos@559: can call normal Mercurial commands to get any added bos@559: information you need. The trade-off is that external hooks bos@559: are slower than in-process hooks. bos@559: bos@559: bos@559: An in-process Python hook has complete access to the bos@559: Mercurial API, and does not shell out to bos@559: another process, so it is inherently faster than an external bos@559: hook. It is also easier to obtain much of the information bos@559: that a hook requires by using the Mercurial API than by bos@559: running Mercurial commands. bos@559: bos@559: bos@559: If you are comfortable with Python, or require high bos@559: performance, writing your hooks in Python may be a good bos@559: choice. However, when you have a straightforward hook to bos@559: write and you don't need to care about performance (probably bos@559: the majority of hooks), a shell script is perfectly fine. bos@559: bos@559: bos@559: dongsheng@625: bos@559: Hook parameters bos@559: bos@559: Mercurial calls each hook with a set of well-defined bos@559: parameters. In Python, a parameter is passed as a keyword bos@559: argument to your hook function. For an external program, a bos@559: parameter is passed as an environment variable. bos@559: bos@559: bos@559: Whether your hook is written in Python or as a shell bos@559: script, the hook-specific parameter names and values will be bos@559: the same. A boolean parameter will be represented as a bos@559: boolean value in Python, but as the number 1 (for bos@559: true) or 0 (for false) as an bos@559: environment variable for an external hook. If a hook bos@559: parameter is named foo, the keyword bos@559: argument for a Python hook will also be named bos@559: foo, while the environment variable for an bos@559: external hook will be named HG_FOO. bos@559: bos@559: bos@559: bos@559: bos@559: Hook return values and activity control bos@559: bos@559: A hook that executes successfully must exit with a status bos@559: of zero if external, or return boolean false if bos@559: in-process. Failure is indicated with a non-zero exit status bos@559: from an external hook, or an in-process hook returning boolean bos@559: true. If an in-process hook raises an bos@559: exception, the hook is considered to have failed. bos@559: bos@559: bos@559: For a hook that controls whether an activity can proceed, bos@559: zero/false means allow, while bos@559: non-zero/true/exception means deny. bos@559: bos@559: bos@559: bos@559: bos@559: Writing an external hook bos@559: bos@559: When you define an external hook in your /.hgrc\ and the hook is run, its bos@559: value is passed to your shell, which interprets it. This bos@559: means that you can use normal shell constructs in the body of bos@559: the hook. bos@559: bos@559: bos@559: An executable hook is always run with its current bos@559: directory set to a repository's root directory. bos@559: bos@559: bos@559: Each hook parameter is passed in as an environment bos@559: variable; the name is upper-cased, and prefixed with the bos@559: string HG_. bos@559: bos@559: bos@559: With the exception of hook parameters, Mercurial does not bos@559: set or modify any environment variables when running a hook. bos@559: This is useful to remember if you are writing a site-wide hook bos@559: that may be run by a number of different users with differing bos@559: environment variables set. In multi-user situations, you bos@559: should not rely on environment variables being set to the bos@559: values you have in your environment when testing the hook. bos@559: bos@559: bos@559: bos@559: bos@559: Telling Mercurial to use an in-process hook bos@559: bos@559: The /.hgrc\ syntax bos@559: for defining an in-process hook is slightly different than for bos@559: an executable hook. The value of the hook must start with the bos@559: text python:, and continue bos@559: with the fully-qualified name of a callable object to use as bos@559: the hook's value. bos@559: bos@559: bos@559: The module in which a hook lives is automatically imported bos@559: when a hook is run. So long as you have the module name and bos@559: PYTHONPATH right, it should just bos@559: work. bos@559: bos@559: bos@559: The following /.hgrc\ bos@559: example snippet illustrates the syntax and meaning of the bos@559: notions we just described. bos@559: bos@559: [hooks] commit.example = bos@559: python:mymodule.submodule.myhook bos@559: When Mercurial runs the commit.example bos@559: hook, it imports mymodule.submodule, looks bos@559: for the callable object named myhook, and bos@559: calls it. bos@559: bos@559: bos@559: bos@559: bos@559: Writing an in-process hook bos@559: bos@559: The simplest in-process hook does nothing, but illustrates bos@559: the basic shape of the hook API: bos@559: bos@559: def myhook(ui, repo, **kwargs): bos@559: pass bos@559: The first argument to a Python hook is always a ui object. The second bos@559: is a repository object; at the moment, it is always an bos@559: instance of localrepository. bos@559: Following these two arguments are other keyword arguments. bos@559: Which ones are passed in depends on the hook being called, but bos@559: a hook can ignore arguments it doesn't care about by dropping bos@559: them into a keyword argument dict, as with bos@559: **kwargs above. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Some hook examples bos@559: bos@559: bos@559: Writing meaningful commit messages bos@559: bos@559: It's hard to imagine a useful commit message being very bos@559: short. The simple pretxncommit bos@559: hook of the example below will prevent you from committing a bos@559: changeset with a message that is less than ten bytes long. bos@559: bos@559: bos@567: &interaction.hook.msglen.go; bos@559: bos@559: bos@559: bos@559: Checking for trailing whitespace bos@559: bos@559: An interesting use of a commit-related hook is to help you bos@559: to write cleaner code. A simple example of cleaner bos@559: code is the dictum that a change should not add any bos@559: new lines of text that contain trailing bos@559: whitespace. Trailing whitespace is a series of bos@559: space and tab characters at the end of a line of text. In bos@559: most cases, trailing whitespace is unnecessary, invisible bos@559: noise, but it is occasionally problematic, and people often bos@559: prefer to get rid of it. bos@559: bos@559: bos@559: You can use either the precommit or pretxncommit hook to tell whether you bos@559: have a trailing whitespace problem. If you use the precommit hook, the hook will not know bos@559: which files you are committing, so it will have to check every bos@559: modified file in the repository for trailing white space. If bos@559: you want to commit a change to just the file bos@559: foo, but the file bos@559: bar contains trailing whitespace, doing a bos@559: check in the precommit hook bos@559: will prevent you from committing foo due bos@559: to the problem with bar. This doesn't bos@559: seem right. bos@559: bos@559: bos@559: Should you choose the pretxncommit hook, the check won't bos@559: occur until just before the transaction for the commit bos@559: completes. This will allow you to check for problems only the bos@559: exact files that are being committed. However, if you entered bos@559: the commit message interactively and the hook fails, the bos@559: transaction will roll back; you'll have to re-enter the commit bos@559: message after you fix the trailing whitespace and run hg commit again. bos@559: bos@559: bos@567: &interaction.hook.ws.simple; bos@559: bos@559: In this example, we introduce a simple pretxncommit hook that checks for bos@559: trailing whitespace. This hook is short, but not very bos@559: helpful. It exits with an error status if a change adds a bos@559: line with trailing whitespace to any file, but does not print bos@559: any information that might help us to identify the offending bos@559: file or line. It also has the nice property of not paying bos@559: attention to unmodified lines; only lines that introduce new bos@559: trailing whitespace cause problems. bos@559: bos@559: bos@559: The above version is much more complex, but also more bos@559: useful. It parses a unified diff to see if any lines add bos@559: trailing whitespace, and prints the name of the file and the bos@559: line number of each such occurrence. Even better, if the bos@559: change adds trailing whitespace, this hook saves the commit bos@559: comment and prints the name of the save file before exiting bos@559: and telling Mercurial to roll the transaction back, so you can bos@559: use the bos@559: option to hg commit to reuse bos@559: the saved commit message once you've corrected the problem. bos@559: bos@559: bos@567: &interaction.hook.ws.better; bos@559: bos@559: As a final aside, note in the example above the use of bos@559: perl's in-place editing feature to get rid bos@559: of trailing whitespace from a file. This is concise and bos@559: useful enough that I will reproduce it here. bos@559: bos@559: perl -pi -e 's,\s+$,,' filename bos@559: bos@559: bos@559: bos@559: bos@559: Bundled hooks bos@559: bos@559: Mercurial ships with several bundled hooks. You can find bos@559: them in the hgext bos@559: directory of a Mercurial source tree. If you are using a bos@559: Mercurial binary package, the hooks will be located in the bos@559: hgext directory of bos@559: wherever your package installer put Mercurial. bos@559: bos@559: bos@559: bos@559: <literal role="hg-ext">acl</literal>&emdash;access bos@559: control for parts of a repository bos@559: bos@559: The acl extension lets bos@559: you control which remote users are allowed to push changesets bos@559: to a networked server. You can protect any portion of a bos@559: repository (including the entire repo), so that a specific bos@559: remote user can push changes that do not affect the protected bos@559: portion. bos@559: bos@559: bos@559: This extension implements access control based on the bos@559: identity of the user performing a push, bos@559: not on who committed the changesets bos@559: they're pushing. It makes sense to use this hook only if you bos@559: have a locked-down server environment that authenticates bos@559: remote users, and you want to be sure that only specific users bos@559: are allowed to push changes to that server. bos@559: bos@559: bos@559: bos@559: Configuring the <literal role="hook">acl</literal> bos@559: hook bos@559: bos@559: In order to manage incoming changesets, the acl hook must be used as a bos@559: pretxnchangegroup hook. This bos@559: lets it see which files are modified by each incoming bos@559: changeset, and roll back a group of changesets if they bos@559: modify forbidden files. Example: bos@559: bos@559: [hooks] pretxnchangegroup.acl = bos@559: python:hgext.acl.hook bos@559: bos@559: The acl extension is bos@559: configured using three sections. bos@559: bos@559: bos@559: The acl section has bos@559: only one entry, sources, bos@559: which lists the sources of incoming changesets that the hook bos@559: should pay attention to. You don't normally need to bos@559: configure this section. bos@559: bos@559: bos@559: serve: bos@559: Control incoming changesets that are arriving from a bos@559: remote repository over http or ssh. This is the default bos@559: value of sources, and bos@559: usually the only setting you'll need for this bos@559: configuration item. bos@559: bos@559: bos@559: pull: bos@559: Control incoming changesets that are arriving via a pull bos@559: from a local repository. bos@559: bos@559: bos@559: push: bos@559: Control incoming changesets that are arriving via a push bos@559: from a local repository. bos@559: bos@559: bos@559: bundle: bos@559: Control incoming changesets that are arriving from bos@559: another repository via a bundle. bos@559: bos@559: bos@559: bos@559: The acl.allow bos@559: section controls the users that are allowed to add bos@559: changesets to the repository. If this section is not bos@559: present, all users that are not explicitly denied are bos@559: allowed. If this section is present, all users that are not bos@559: explicitly allowed are denied (so an empty section means bos@559: that all users are denied). bos@559: bos@559: bos@559: The acl.deny bos@559: section determines which users are denied from adding bos@559: changesets to the repository. If this section is not bos@559: present or is empty, no users are denied. bos@559: bos@559: bos@559: The syntaxes for the acl.allow and acl.deny sections are bos@559: identical. On the left of each entry is a glob pattern that bos@559: matches files or directories, relative to the root of the bos@559: repository; on the right, a user name. bos@559: bos@559: bos@559: In the following example, the user bos@559: docwriter can only push changes to the bos@559: docs subtree of the bos@559: repository, while intern can push changes bos@559: to any file or directory except source/sensitive. bos@559: bos@559: [acl.allow] docs/** = docwriter [acl.deny] bos@559: source/sensitive/** = intern bos@559: bos@559: bos@559: bos@559: Testing and troubleshooting bos@559: bos@559: If you want to test the acl hook, run it with Mercurial's bos@559: debugging output enabled. Since you'll probably be running bos@559: it on a server where it's not convenient (or sometimes bos@559: possible) to pass in the option, don't forget bos@559: that you can enable debugging output in your /.hgrc: bos@559: bos@559: [ui] debug = true bos@559: With this enabled, the acl hook will print enough bos@559: information to let you figure out why it is allowing or bos@559: forbidding pushes from specific users. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: <literal bos@559: role="hg-ext">bugzilla</literal>&emdash;integration with bos@559: Bugzilla bos@559: bos@559: The bugzilla extension bos@559: adds a comment to a Bugzilla bug whenever it finds a reference bos@559: to that bug ID in a commit comment. You can install this hook bos@559: on a shared server, so that any time a remote user pushes bos@559: changes to this server, the hook gets run. bos@559: bos@559: bos@559: It adds a comment to the bug that looks like this (you can bos@559: configure the contents of the comment&emdash;see below): bos@559: bos@559: Changeset aad8b264143a, made by Joe User bos@559: <joe.user@domain.com> in the frobnitz repository, refers bos@559: to this bug. For complete details, see bos@559: http://hg.domain.com/frobnitz?cmd=changeset;node=aad8b264143a bos@559: Changeset description: Fix bug 10483 by guarding against some bos@559: NULL pointers bos@559: The value of this hook is that it automates the process of bos@559: updating a bug any time a changeset refers to it. If you bos@559: configure the hook properly, it makes it easy for people to bos@559: browse straight from a Bugzilla bug to a changeset that refers bos@559: to that bug. bos@559: bos@559: bos@559: You can use the code in this hook as a starting point for bos@559: some more exotic Bugzilla integration recipes. Here are a few bos@559: possibilities: bos@559: bos@559: bos@559: Require that every changeset pushed to the bos@559: server have a valid bug ID in its commit comment. In this bos@559: case, you'd want to configure the hook as a pretxncommit hook. This would bos@559: allow the hook to reject changes that didn't contain bug bos@559: IDs. bos@559: bos@559: bos@559: Allow incoming changesets to automatically bos@559: modify the state of a bug, as well as bos@559: simply adding a comment. For example, the hook could bos@559: recognise the string fixed bug 31337 as bos@559: indicating that it should update the state of bug 31337 to bos@559: requires testing. bos@559: bos@559: bos@559: dongsheng@625: bos@559: Configuring the <literal role="hook">bugzilla</literal> bos@559: hook bos@559: bos@559: You should configure this hook in your server's bos@559: /.hgrc\ as an incoming hook, for example as bos@559: follows: bos@559: bos@559: [hooks] incoming.bugzilla = bos@559: python:hgext.bugzilla.hook bos@559: bos@559: Because of the specialised nature of this hook, and bos@559: because Bugzilla was not written with this kind of bos@559: integration in mind, configuring this hook is a somewhat bos@559: involved process. bos@559: bos@559: bos@559: Before you begin, you must install the MySQL bindings bos@559: for Python on the host(s) where you'll be running the hook. bos@559: If this is not available as a binary package for your bos@559: system, you can download it from bos@559: web:mysql-python. bos@559: bos@559: bos@559: Configuration information for this hook lives in the bos@559: bugzilla section of bos@559: your /.hgrc. bos@559: bos@559: bos@559: version: The version bos@559: of Bugzilla installed on the server. The database bos@559: schema that Bugzilla uses changes occasionally, so this bos@559: hook has to know exactly which schema to use. At the bos@559: moment, the only version supported is bos@559: 2.16. bos@559: bos@559: bos@559: host: bos@559: The hostname of the MySQL server that stores your bos@559: Bugzilla data. The database must be configured to allow bos@559: connections from whatever host you are running the bos@559: bugzilla hook on. bos@559: bos@559: bos@559: user: bos@559: The username with which to connect to the MySQL server. bos@559: The database must be configured to allow this user to bos@559: connect from whatever host you are running the bugzilla hook on. This user bos@559: must be able to access and modify Bugzilla tables. The bos@559: default value of this item is bugs, bos@559: which is the standard name of the Bugzilla user in a bos@559: MySQL database. bos@559: bos@559: bos@559: password: The MySQL bos@559: password for the user you configured above. This is bos@559: stored as plain text, so you should make sure that bos@559: unauthorised users cannot read the /.hgrc\ file where you bos@559: store this information. bos@559: bos@559: bos@559: db: bos@559: The name of the Bugzilla database on the MySQL server. bos@559: The default value of this item is bos@559: bugs, which is the standard name of bos@559: the MySQL database where Bugzilla stores its data. bos@559: bos@559: bos@559: notify: If you want bos@559: Bugzilla to send out a notification email to subscribers bos@559: after this hook has added a comment to a bug, you will bos@559: need this hook to run a command whenever it updates the bos@559: database. The command to run depends on where you have bos@559: installed Bugzilla, but it will typically look something bos@559: like this, if you have Bugzilla installed in /var/www/html/bugzilla: bos@559: bos@559: cd /var/www/html/bugzilla && bos@559: ./processmail %s nobody@nowhere.com bos@559: bos@559: The Bugzilla bos@559: processmail program expects to be bos@559: given a bug ID (the hook replaces bos@559: %s with the bug ID) bos@559: and an email address. It also expects to be able to bos@559: write to some files in the directory that it runs in. bos@559: If Bugzilla and this hook are not installed on the same bos@559: machine, you will need to find a way to run bos@559: processmail on the server where bos@559: Bugzilla is installed. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Mapping committer names to Bugzilla user names bos@559: bos@559: By default, the bugzilla hook tries to use the bos@559: email address of a changeset's committer as the Bugzilla bos@559: user name with which to update a bug. If this does not suit bos@559: your needs, you can map committer email addresses to bos@559: Bugzilla user names using a usermap section. bos@559: bos@559: bos@559: Each item in the usermap section contains an bos@559: email address on the left, and a Bugzilla user name on the bos@559: right. bos@559: bos@559: [usermap] jane.user@example.com = bos@559: jane bos@559: You can either keep the usermap data in a normal bos@559: ~/.hgrc, or tell the bos@559: bugzilla hook to read the bos@559: information from an external usermap bos@559: file. In the latter case, you can store bos@559: usermap data by itself in (for example) bos@559: a user-modifiable repository. This makes it possible to let bos@559: your users maintain their own usermap entries. The main bos@559: /.hgrc\ file might look bos@559: like this: bos@559: bos@559: # regular hgrc file refers to external usermap bos@559: file [bugzilla] usermap = bos@559: /home/hg/repos/userdata/bugzilla-usermap.conf bos@559: While the usermap file that it bos@559: refers to might look like this: bos@559: bos@559: # bugzilla-usermap.conf - inside a hg bos@559: repository [usermap] stephanie@example.com = bos@559: steph bos@559: bos@559: bos@559: bos@559: Configuring the text that gets added to a bug bos@559: bos@559: You can configure the text that this hook adds as a bos@559: comment; you specify it in the form of a Mercurial template. bos@559: Several /.hgrc\ entries bos@559: (still in the bugzilla bos@559: section) control this behaviour. bos@559: bos@559: bos@559: strip: The number of bos@559: leading path elements to strip from a repository's path bos@559: name to construct a partial path for a URL. For example, bos@559: if the repositories on your server live under /home/hg/repos, and you bos@559: have a repository whose path is /home/hg/repos/app/tests, bos@559: then setting strip to bos@559: 4 will give a partial path of bos@559: app/tests. The bos@559: hook will make this partial path available when bos@559: expanding a template, as webroot. bos@559: bos@559: bos@559: template: The text of the bos@559: template to use. In addition to the usual bos@559: changeset-related variables, this template can use bos@559: hgweb (the value of the bos@559: hgweb configuration item above) and bos@559: webroot (the path constructed using bos@559: strip above). bos@559: bos@559: bos@559: bos@559: In addition, you can add a baseurl item to the web section of your /.hgrc. The bugzilla hook will make this bos@559: available when expanding a template, as the base string to bos@559: use when constructing a URL that will let users browse from bos@559: a Bugzilla comment to view a changeset. Example: bos@559: bos@559: [web] baseurl = bos@559: http://hg.domain.com/ bos@559: bos@559: Here is an example set of bugzilla hook config information. bos@559: bos@559: [bugzilla] host = bugzilla.example.com bos@559: password = mypassword version = 2.16 # server-side repos bos@559: live in /home/hg/repos, so strip 4 leading # separators bos@559: strip = 4 hgweb = http://hg.example.com/ usermap = bos@559: /home/hg/repos/notify/bugzilla.conf template = Changeset bos@559: {node|short}, made by {author} in the {webroot} repo, refers bos@559: to this bug.\\nFor complete details, see bos@559: {hgweb}{webroot}?cmd=changeset;node={node|short}\\nChangeset bos@559: description:\\n\\t{desc|tabindent} bos@559: bos@559: bos@559: bos@559: Testing and troubleshooting bos@559: bos@559: The most common problems with configuring the bugzilla hook relate to running bos@559: Bugzilla's processmail script and bos@559: mapping committer names to user names. bos@559: bos@559: bos@559: Recall from section above that the user bos@559: that runs the Mercurial process on the server is also the bos@559: one that will run the processmail bos@559: script. The processmail script bos@559: sometimes causes Bugzilla to write to files in its bos@559: configuration directory, and Bugzilla's configuration files bos@559: are usually owned by the user that your web server runs bos@559: under. bos@559: bos@559: bos@559: You can cause processmail to be run bos@559: with the suitable user's identity using the bos@559: sudo command. Here is an example entry bos@559: for a sudoers file. bos@559: bos@559: hg_user = (httpd_user) NOPASSWD: bos@559: /var/www/html/bugzilla/processmail-wrapper bos@559: %s bos@559: This allows the hg_user user to run a bos@559: processmail-wrapper program under the bos@559: identity of httpd_user. bos@559: bos@559: bos@559: This indirection through a wrapper script is necessary, bos@559: because processmail expects to be run bos@559: with its current directory set to wherever you installed bos@559: Bugzilla; you can't specify that kind of constraint in a bos@559: sudoers file. The contents of the bos@559: wrapper script are simple: bos@559: bos@559: #!/bin/sh cd `dirname $0` && bos@559: ./processmail "$1" nobody@example.com bos@559: It doesn't seem to matter what email address you pass to bos@559: processmail. bos@559: bos@559: bos@559: If your usermap is bos@559: not set up correctly, users will see an error message from bos@559: the bugzilla hook when they bos@559: push changes to the server. The error message will look bos@559: like this: bos@559: bos@559: cannot find bugzilla user id for bos@559: john.q.public@example.com bos@559: What this means is that the committer's address, bos@559: john.q.public@example.com, is not a valid bos@559: Bugzilla user name, nor does it have an entry in your bos@559: usermap that maps it to bos@559: a valid Bugzilla user name. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: <literal role="hg-ext">notify</literal>&emdash;send email bos@559: notifications bos@559: bos@559: Although Mercurial's built-in web server provides RSS bos@559: feeds of changes in every repository, many people prefer to bos@559: receive change notifications via email. The notify hook lets you send out bos@559: notifications to a set of email addresses whenever changesets bos@559: arrive that those subscribers are interested in. bos@559: bos@559: bos@559: As with the bugzilla bos@559: hook, the notify hook is bos@559: template-driven, so you can customise the contents of the bos@559: notification messages that it sends. bos@559: bos@559: bos@559: By default, the notify bos@559: hook includes a diff of every changeset that it sends out; you bos@559: can limit the size of the diff, or turn this feature off bos@559: entirely. It is useful for letting subscribers review changes bos@559: immediately, rather than clicking to follow a URL. bos@559: bos@559: bos@559: bos@559: Configuring the <literal role="hg-ext">notify</literal> bos@559: hook bos@559: bos@559: You can set up the notify hook to send one email bos@559: message per incoming changeset, or one per incoming group of bos@559: changesets (all those that arrived in a single pull or bos@559: push). bos@559: bos@559: [hooks] # send one email per group of changes bos@559: changegroup.notify = python:hgext.notify.hook # send one bos@559: email per change incoming.notify = bos@559: python:hgext.notify.hook bos@559: bos@559: Configuration information for this hook lives in the bos@559: notify section of a bos@559: /.hgrc\ file. bos@559: bos@559: bos@559: test: bos@559: By default, this hook does not send out email at all; bos@559: instead, it prints the message that it bos@559: would send. Set this item to bos@559: false to allow email to be sent. The bos@559: reason that sending of email is turned off by default is bos@559: that it takes several tries to configure this extension bos@559: exactly as you would like, and it would be bad form to bos@559: spam subscribers with a number of broken bos@559: notifications while you debug your configuration. bos@559: bos@559: bos@559: config: bos@559: The path to a configuration file that contains bos@559: subscription information. This is kept separate from bos@559: the main /.hgrc\ so bos@559: that you can maintain it in a repository of its own. bos@559: People can then clone that repository, update their bos@559: subscriptions, and push the changes back to your server. bos@559: bos@559: bos@559: strip: bos@559: The number of leading path separator characters to strip bos@559: from a repository's path, when deciding whether a bos@559: repository has subscribers. For example, if the bos@559: repositories on your server live in /home/hg/repos, and bos@559: notify is considering a bos@559: repository named /home/hg/repos/shared/test, bos@559: setting strip to bos@559: 4 will cause notify to trim the path it bos@559: considers down to shared/test, and it will bos@559: match subscribers against that. bos@559: bos@559: bos@559: template: The template bos@559: text to use when sending messages. This specifies both bos@559: the contents of the message header and its body. bos@559: bos@559: bos@559: maxdiff: The maximum bos@559: number of lines of diff data to append to the end of a bos@559: message. If a diff is longer than this, it is bos@559: truncated. By default, this is set to 300. Set this to bos@559: 0 to omit diffs from notification bos@559: emails. bos@559: bos@559: bos@559: sources: A list of bos@559: sources of changesets to consider. This lets you limit bos@559: notify to only sending bos@559: out email about changes that remote users pushed into bos@559: this repository via a server, for example. See section bos@559: for the sources you can bos@559: specify here. bos@559: bos@559: bos@559: bos@559: If you set the baseurl bos@559: item in the web section, bos@559: you can use it in a template; it will be available as bos@559: webroot. bos@559: bos@559: bos@559: Here is an example set of notify configuration information. bos@559: bos@559: bos@559: [notify] # really send email test = false # subscriber data bos@559: lives in the notify repo config = bos@559: /home/hg/repos/notify/notify.conf # repos live in bos@559: /home/hg/repos on server, so strip 4 "/" chars strip = 4 bos@559: template = X-Hg-Repo: {webroot} Subject: {webroot}: bos@559: {desc|firstline|strip} From: {author} changeset {node|short} bos@559: in {root} details: bos@559: {baseurl}{webroot}?cmd=changeset;node={node|short} bos@559: description: {desc|tabindent|strip} [web] baseurl = bos@559: http://hg.example.com/ bos@559: bos@559: bos@559: This will produce a message that looks like the bos@559: following: bos@559: bos@559: bos@559: X-Hg-Repo: tests/slave Subject: tests/slave: Handle error bos@559: case when slave has no buffers Date: Wed, 2 Aug 2006 bos@559: 15:25:46 -0700 (PDT) changeset 3cba9bfe74b5 in bos@559: /home/hg/repos/tests/slave details: bos@559: http://hg.example.com/tests/slave?cmd=changeset;node=3cba9bfe74b5 bos@559: description: Handle error case when slave has no buffers bos@559: diffs (54 lines): diff -r 9d95df7cf2ad -r 3cba9bfe74b5 bos@559: include/tests.h --- a/include/tests.h Wed Aug 02 bos@559: 15:19:52 2006 -0700 +++ b/include/tests.h Wed Aug 02 bos@559: 15:25:26 2006 -0700 @@ -212,6 +212,15 @@ static __inline__ bos@559: void test_headers(void *h) [...snip...] bos@559: bos@559: bos@559: bos@559: bos@559: Testing and troubleshooting bos@559: bos@559: Do not forget that by default, the notify extension will not ori@561: send any mail until you explicitly configure it to do so, bos@559: by setting test to bos@559: false. Until you do that, it simply bos@559: prints the message it would send. bos@559: bos@559: bos@559: bos@559: bos@559: dongsheng@625: bos@559: Information for writers of hooks bos@559: bos@559: bos@559: In-process hook execution bos@559: bos@559: An in-process hook is called with arguments of the bos@559: following form: bos@559: bos@559: bos@559: def myhook(ui, repo, **kwargs): pass bos@559: bos@559: The ui parameter is a ui object. The bos@559: repo parameter is a localrepository bos@559: object. The names and values of the bos@559: **kwargs parameters depend on the hook bos@559: being invoked, with the following common features: bos@559: bos@559: bos@559: If a parameter is named bos@559: node or parentN, it bos@559: will contain a hexadecimal changeset ID. The empty string bos@559: is used to represent null changeset ID bos@559: instead of a string of zeroes. bos@559: bos@559: bos@559: If a parameter is named bos@559: url, it will contain the URL of a bos@559: remote repository, if that can be determined. bos@559: bos@559: bos@559: Boolean-valued parameters are represented as bos@559: Python bool objects. bos@559: bos@559: bos@559: bos@559: An in-process hook is called without a change to the bos@559: process's working directory (unlike external hooks, which are bos@559: run in the root of the repository). It must not change the bos@559: process's working directory, or it will cause any calls it bos@559: makes into the Mercurial API to fail. bos@559: bos@559: bos@559: If a hook returns a boolean false value, it bos@559: is considered to have succeeded. If it returns a boolean bos@559: true value or raises an exception, it is bos@559: considered to have failed. A useful way to think of the bos@559: calling convention is tell me if you fail. bos@559: bos@559: bos@559: Note that changeset IDs are passed into Python hooks as bos@559: hexadecimal strings, not the binary hashes that Mercurial's bos@559: APIs normally use. To convert a hash from hex to binary, use bos@559: the \pymodfunc{mercurial.node}{bin} function. bos@559: bos@559: bos@559: bos@559: bos@559: External hook execution bos@559: bos@559: An external hook is passed to the shell of the user bos@559: running Mercurial. Features of that shell, such as variable bos@559: substitution and command redirection, are available. The hook bos@559: is run in the root directory of the repository (unlike bos@559: in-process hooks, which are run in the same directory that bos@559: Mercurial was run in). bos@559: bos@559: bos@559: Hook parameters are passed to the hook as environment bos@559: variables. Each environment variable's name is converted in bos@559: upper case and prefixed with the string bos@559: HG_. For example, if the bos@559: name of a parameter is node, bos@559: the name of the environment variable representing that bos@559: parameter will be HG_NODE. bos@559: bos@559: bos@559: A boolean parameter is represented as the string bos@559: 1 for true, bos@559: 0 for false. bos@559: If an environment variable is named HG_NODE, bos@559: HG_PARENT1 or HG_PARENT2, it bos@559: contains a changeset ID represented as a hexadecimal string. bos@559: The empty string is used to represent null changeset bos@559: ID instead of a string of zeroes. If an environment bos@559: variable is named HG_URL, it will contain the bos@559: URL of a remote repository, if that can be determined. bos@559: bos@559: bos@559: If a hook exits with a status of zero, it is considered to bos@559: have succeeded. If it exits with a non-zero status, it is bos@559: considered to have failed. bos@559: bos@559: bos@559: bos@559: bos@559: Finding out where changesets come from bos@559: bos@559: A hook that involves the transfer of changesets between a bos@559: local repository and another may be able to find out bos@559: information about the far side. Mercurial bos@559: knows how changes are being transferred, bos@559: and in many cases where they are being bos@559: transferred to or from. bos@559: bos@559: dongsheng@625: bos@559: Sources of changesets bos@559: bos@559: Mercurial will tell a hook what means are, or were, used bos@559: to transfer changesets between repositories. This is bos@559: provided by Mercurial in a Python parameter named bos@559: source, or an environment variable named bos@559: HG_SOURCE. bos@559: bos@559: bos@559: bos@559: serve: Changesets are bos@559: transferred to or from a remote repository over http or bos@559: ssh. bos@559: bos@559: bos@559: pull: Changesets are bos@559: being transferred via a pull from one repository into bos@559: another. bos@559: bos@559: bos@559: push: Changesets are bos@559: being transferred via a push from one repository into bos@559: another. bos@559: bos@559: bos@559: bundle: Changesets are bos@559: being transferred to or from a bundle. bos@559: bos@559: bos@559: bos@559: dongsheng@625: bos@559: Where changes are going&emdash;remote repository bos@559: URLs bos@559: bos@559: When possible, Mercurial will tell a hook the location bos@559: of the far side of an activity that transfers bos@559: changeset data between repositories. This is provided by bos@559: Mercurial in a Python parameter named bos@559: url, or an environment variable named bos@559: HG_URL. bos@559: bos@559: bos@559: This information is not always known. If a hook is bos@559: invoked in a repository that is being served via http or bos@559: ssh, Mercurial cannot tell where the remote repository is, bos@559: but it may know where the client is connecting from. In bos@559: such cases, the URL will take one of the following forms: bos@559: bos@559: bos@559: remote:ssh:1.2.3.4&emdash;remote bos@559: ssh client, at the IP address bos@559: 1.2.3.4. bos@559: bos@559: bos@559: remote:http:1.2.3.4&emdash;remote bos@559: http client, at the IP address bos@559: 1.2.3.4. If the client is using SSL, bos@559: this will be of the form bos@559: remote:https:1.2.3.4. bos@559: bos@559: bos@559: Empty&emdash;no information could be bos@559: discovered about the remote client. bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: Hook reference bos@559: dongsheng@625: bos@559: <literal role="hook">changegroup</literal>&emdash;after bos@559: remote changesets added bos@559: bos@559: This hook is run after a group of pre-existing changesets bos@559: has been added to the repository, for example via a hg pull or hg bos@559: unbundle. This hook is run once per operation bos@559: that added one or more changesets. This is in contrast to the bos@559: incoming hook, which is run bos@559: once per changeset, regardless of whether the changesets bos@559: arrive in a group. bos@559: bos@559: bos@559: Some possible uses for this hook include kicking off an bos@559: automated build or test of the added changesets, updating a bos@559: bug database, or notifying subscribers that a repository bos@559: contains new changes. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: changeset ID of the first changeset in the group that was bos@559: added. All changesets between this and bos@559: \index{tags!tip}tip, bos@559: inclusive, were added by a single hg pull, hg push or hg unbundle. bos@559: bos@559: bos@559: source: A string. The bos@559: source of these changes. See section for details. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: incoming (section dongsheng@625: ), prechangegroup (section ), pretxnchangegroup (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">commit</literal>&emdash;after a new bos@559: changeset is created bos@559: bos@559: This hook is run after a new changeset has been created. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: changeset ID of the newly committed changeset. bos@559: bos@559: bos@559: parent1: A changeset ID. bos@559: The changeset ID of the first parent of the newly bos@559: committed changeset. bos@559: bos@559: bos@559: parent2: A changeset ID. bos@559: The changeset ID of the second parent of the newly bos@559: committed changeset. bos@559: bos@559: bos@559: bos@559: See also: precommit dongsheng@625: (section ), pretxncommit (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">incoming</literal>&emdash;after one bos@559: remote changeset is added bos@559: bos@559: This hook is run after a pre-existing changeset has been bos@559: added to the repository, for example via a hg push. If a group of changesets bos@559: was added in a single operation, this hook is called once for bos@559: each added changeset. bos@559: bos@559: bos@559: You can use this hook for the same purposes as the bos@559: changegroup hook (section ); it's simply bos@559: more convenient sometimes to run a hook once per group of bos@559: changesets, while other times it's handier once per changeset. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: ID of the newly added changeset. bos@559: bos@559: bos@559: source: A string. The bos@559: source of these changes. See section for details. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: changegroup dongsheng@625: (section ) prechangegroup (section ), pretxnchangegroup (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">outgoing</literal>&emdash;after bos@559: changesets are propagated bos@559: bos@559: This hook is run after a group of changesets has been bos@559: propagated out of this repository, for example by a hg push or hg bos@559: bundle command. bos@559: bos@559: bos@559: One possible use for this hook is to notify administrators bos@559: that changes have been pulled. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: changeset ID of the first changeset of the group that was bos@559: sent. bos@559: bos@559: bos@559: source: A string. The bos@559: source of the of the operation (see section ). If a remote bos@559: client pulled changes from this repository, bos@559: source will be bos@559: serve. If the client that obtained bos@559: changes from this repository was local, bos@559: source will be bos@559: bundle, pull, or bos@559: push, depending on the operation the bos@559: client performed. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: preoutgoing dongsheng@625: (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal bos@559: role="hook">prechangegroup</literal>&emdash;before starting bos@559: to add remote changesets bos@559: bos@559: This controlling hook is run before Mercurial begins to bos@559: add a group of changesets from another repository. bos@559: bos@559: bos@559: This hook does not have any information about the bos@559: changesets to be added, because it is run before transmission bos@559: of those changesets is allowed to begin. If this hook fails, bos@559: the changesets will not be transmitted. bos@559: bos@559: bos@559: One use for this hook is to prevent external changes from bos@559: being added to a repository. For example, you could use this bos@559: to freeze a server-hosted branch temporarily or bos@559: permanently so that users cannot push to it, while still bos@559: allowing a local administrator to modify the repository. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: source: A string. The bos@559: source of these changes. See section for details. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: changegroup dongsheng@625: (section ), incoming (section ), , pretxnchangegroup (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">precommit</literal>&emdash;before bos@559: starting to commit a changeset bos@559: bos@559: This hook is run before Mercurial begins to commit a new bos@559: changeset. It is run before Mercurial has any of the metadata bos@559: for the commit, such as the files to be committed, the commit bos@559: message, or the commit date. bos@559: bos@559: bos@559: One use for this hook is to disable the ability to commit bos@559: new changesets, while still allowing incoming changesets. bos@559: Another is to run a build or test, and only allow the commit bos@559: to begin if the build or test succeeds. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: parent1: A changeset ID. bos@559: The changeset ID of the first parent of the working bos@559: directory. bos@559: bos@559: bos@559: parent2: A changeset ID. bos@559: The changeset ID of the second parent of the working bos@559: directory. bos@559: bos@559: bos@559: If the commit proceeds, the parents of the working bos@559: directory will become the parents of the new changeset. bos@559: bos@559: bos@559: See also: commit (section dongsheng@625: ), pretxncommit (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">preoutgoing</literal>&emdash;before bos@559: starting to propagate changesets bos@559: bos@559: This hook is invoked before Mercurial knows the identities bos@559: of the changesets to be transmitted. bos@559: bos@559: bos@559: One use for this hook is to prevent changes from being bos@559: transmitted to another repository. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: source: A string. The bos@559: source of the operation that is attempting to obtain bos@559: changes from this repository (see section ). See the documentation bos@559: for the source parameter to the bos@559: outgoing hook, in section dongsheng@625: , for possible values bos@559: of bos@559: this parameter. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: outgoing (section dongsheng@625: ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">pretag</literal>&emdash;before bos@559: tagging a changeset bos@559: bos@559: This controlling hook is run before a tag is created. If bos@559: the hook succeeds, creation of the tag proceeds. If the hook bos@559: fails, the tag is not created. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: local: A boolean. Whether bos@559: the tag is local to this repository instance (i.e. stored bos@559: in .hg/localtags) or bos@559: managed by Mercurial (stored in .hgtags). bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: ID of the changeset to be tagged. bos@559: bos@559: bos@559: tag: A string. The name of bos@559: the tag to be created. bos@559: bos@559: bos@559: bos@559: If the tag to be created is revision-controlled, the bos@559: precommit and pretxncommit hooks (sections and ) will also be run. bos@559: bos@559: bos@559: See also: tag (section dongsheng@625: ) dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal bos@559: role="hook">pretxnchangegroup</literal>&emdash;before bos@559: completing addition of remote changesets bos@559: bos@559: This controlling hook is run before a bos@559: transaction&emdash;that manages the addition of a group of new bos@559: changesets from outside the repository&emdash;completes. If bos@559: the hook succeeds, the transaction completes, and all of the bos@559: changesets become permanent within this repository. If the bos@559: hook fails, the transaction is rolled back, and the data for bos@559: the changesets is erased. bos@559: bos@559: bos@559: This hook can access the metadata associated with the bos@559: almost-added changesets, but it should not do anything bos@559: permanent with this data. It must also not modify the working bos@559: directory. bos@559: bos@559: bos@559: While this hook is running, if other Mercurial processes bos@559: access this repository, they will be able to see the bos@559: almost-added changesets as if they are permanent. This may bos@559: lead to race conditions if you do not take steps to avoid bos@559: them. bos@559: bos@559: bos@559: This hook can be used to automatically vet a group of bos@559: changesets. If the hook fails, all of the changesets are bos@559: rejected when the transaction rolls back. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: changeset ID of the first changeset in the group that was bos@559: added. All changesets between this and bos@559: \index{tags!tip}tip, bos@559: inclusive, were added by a single hg pull, hg push or hg unbundle. bos@559: bos@559: bos@559: source: A string. The bos@559: source of these changes. See section for details. bos@559: bos@559: bos@559: url: A URL. The location bos@559: of the remote repository, if known. See section for more bos@559: information. bos@559: bos@559: bos@559: bos@559: See also: changegroup dongsheng@625: (section ), incoming (section ), prechangegroup (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">pretxncommit</literal>&emdash;before bos@559: completing commit of new changeset bos@559: bos@559: This controlling hook is run before a bos@559: transaction&emdash;that manages a new commit&emdash;completes. bos@559: If the hook succeeds, the transaction completes and the bos@559: changeset becomes permanent within this repository. If the bos@559: hook fails, the transaction is rolled back, and the commit bos@559: data is erased. bos@559: bos@559: bos@559: This hook can access the metadata associated with the bos@559: almost-new changeset, but it should not do anything permanent bos@559: with this data. It must also not modify the working bos@559: directory. bos@559: bos@559: bos@559: While this hook is running, if other Mercurial processes bos@559: access this repository, they will be able to see the bos@559: almost-new changeset as if it is permanent. This may lead to bos@559: race conditions if you do not take steps to avoid them. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: changeset ID of the newly committed changeset. bos@559: bos@559: bos@559: parent1: A changeset ID. bos@559: The changeset ID of the first parent of the newly bos@559: committed changeset. bos@559: bos@559: bos@559: parent2: A changeset ID. bos@559: The changeset ID of the second parent of the newly bos@559: committed changeset. bos@559: bos@559: bos@559: bos@559: See also: precommit dongsheng@625: (section ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">preupdate</literal>&emdash;before bos@559: updating or merging working directory bos@559: bos@559: This controlling hook is run before an update or merge of bos@559: the working directory begins. It is run only if Mercurial's bos@559: normal pre-update checks determine that the update or merge bos@559: can proceed. If the hook succeeds, the update or merge may bos@559: proceed; if it fails, the update or merge does not start. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: parent1: A changeset ID. bos@559: The ID of the parent that the working directory is to be bos@559: updated to. If the working directory is being merged, it bos@559: will not change this parent. bos@559: bos@559: bos@559: parent2: A changeset ID. bos@559: Only set if the working directory is being merged. The ID bos@559: of the revision that the working directory is being merged bos@559: with. bos@559: bos@559: bos@559: bos@559: See also: update (section dongsheng@625: ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">tag</literal>&emdash;after tagging a bos@559: changeset bos@559: bos@559: This hook is run after a tag has been created. bos@559: bos@559: bos@559: Parameters to this hook: bos@559: bos@559: bos@559: local: A boolean. Whether bos@559: the new tag is local to this repository instance (i.e. bos@559: stored in .hg/localtags) or managed by bos@559: Mercurial (stored in .hgtags). bos@559: bos@559: bos@559: node: A changeset ID. The bos@559: ID of the changeset that was tagged. bos@559: bos@559: bos@559: tag: A string. The name of bos@559: the tag that was created. bos@559: bos@559: bos@559: bos@559: If the created tag is revision-controlled, the commit hook (section ) is run before this hook. bos@559: bos@559: bos@559: See also: pretag (section dongsheng@625: ) dongsheng@625: dongsheng@625: dongsheng@625: dongsheng@625: bos@559: <literal role="hook">update</literal>&emdash;after bos@559: updating or merging working directory bos@559: bos@559: This hook is run after an update or merge of the working bos@559: directory completes. Since a merge can fail (if the external bos@559: hgmerge command fails to resolve conflicts bos@559: in a file), this hook communicates whether the update or merge bos@559: completed cleanly. bos@559: bos@559: bos@559: bos@559: error: A boolean. bos@559: Indicates whether the update or merge completed bos@559: successfully. bos@559: bos@559: bos@559: parent1: A changeset ID. bos@559: The ID of the parent that the working directory was bos@559: updated to. If the working directory was merged, it will bos@559: not have changed this parent. bos@559: bos@559: bos@559: parent2: A changeset ID. bos@559: Only set if the working directory was merged. The ID of bos@559: the revision that the working directory was merged with. bos@559: bos@559: bos@559: bos@559: See also: preupdate dongsheng@625: (section ) bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: bos@559: