hook propagation document redone; should flow much easier now

This commit is contained in:
Sitaram Chamarty 2011-11-13 07:53:39 +05:30
parent f19a9cf480
commit 9b66643f3a

View file

@ -3,131 +3,132 @@
Some users like to know how hooks propagate, and when, and why there appear to Some users like to know how hooks propagate, and when, and why there appear to
be two places to put them, and so on. I'll try and set out the logic here. be two places to put them, and so on. I'll try and set out the logic here.
**Note**: This is **not** the document to read if you just want to install a **Note**: You don't need to read all this just to add your own hooks or your
new custom hook; treat it as more "theory" than "lab". ([Here][customhooks] is the own functionality to a hook that gitolite uses. See [here][customhooks] and
"lab" version!) [here][hookchaining].
## hooks used by gitolite ## what hooks do repos get?
Gitolite uses only 2 hooks. **All** repos have an `update` hook, without * `update`: all repos have this; it does the write-level access control
which there is no write-level access control (per-branch permissions). The (per-branch permissions).
special **gitolite-admin** repo has a special `post-update` hook, which is
required to do its, umm, special things, like running the "compile" script,
etc.
In addition there is a "sentinel file" -- an empty file called * `post-receive`: if you've enabled [mirroring][], all repos have this.
"gitolite-hooked". We'll see later what this does.
The final objective of all this is that each repo's `hooks/` directory should * `post-update`: only the special "gitolite-admin" repo has this; it acts
get all the hooks that it is meant to get. upon the changes you push to the admin repo.
## **where** do I (the admin) put the hooks? * `gitolite-hooked`: not really a hook, but a special, zero-byte file; see
below.
In general, **all** hooks go into the `hooks/common` directory. Only the * you can add any other hooks you want (see note at the top of this doc),
special `post-update` hook meant for the admin repo goes into and gitolite will propagate them into all repos along with the others.
`hooks/gitolite-admin`.
Now we'll discuss the locations of these `hooks/common` and ## when do repos "get" hooks?
`hooks/gitolite-admin` directories. This depends on which install method you
used.
(Please refer to [doc/1-INSTALL.mkd][install] for what these "methods" are). * When the "compile" script runs, any repo that is named explicitly in the
conf file, and the "gitolite-hooked" file is not present, gets hooks.
### the `GL_PACKAGE_HOOKS` directory * When someone runs `gl-setup` on the server, then *all* repos physically
present inside `$REPO_BASE` get them.
You might recall that the "root", and "non-root" methods run a command called A repo does not have to be defined in the config for this to happen.
`gl-system-install`, the third argument of which is some directory of your Also, this includes the initial install; if you already had some repos in
choice (like maybe `/usr/share/gitolite/hooks`). Even though it is not `REPO_BASE` they get the hooks.
necessary to know this, internally this becomes the value of the
`$GL_PACKAGE_HOOKS` variable, so in this document we will refer to that
variable instead of the location (because you might choose any location you
like for it).
The "package" method also has the same property, except that the packager has * If `GL_WILDREPOS` is set, a repo gets hooks when a user creates a repo or
already decided what that location is, and the package creation/install uses the "fork" command in "contrib/adc". <font color="gray">In the
process does the equivalent of `gl-system-install`. latter case the hooks are explicitly copied from the source repo using the
"cp" command, not using the code internal to gitolite</font>.
So now we know there's a location called `$GL_PACKAGE_HOOKS` where you can ## what exactly does "get hooks" mean?
place your hooks.
### the `$HOME/.gitolite` directory The "hooks/" directory of the bare repo on the server will *forcibly* have
symlinks created for each of the hooks mentioned in the "what hooks..."
section.
You might also recall that, in these three methods, each **hosting user** has Other files are left alone, so you *can* manually add a hook file to specific
to run `gl-setup`. This sets up, among other things, `$HOME/.gitolite` repos, directly on the server, so long as there is no name clash.
directory, which also contains a `hooks/` directory.
So now there are two places you can put your hooks, apparently. ## where do the symlinks point?
### why two places? There are two places the symlinks can point.
Just think of the "package" and "root" methods for now, even if you're using * `$GL_PACKAGE_HOOKS/common` contains the "system" hooks.
the "non-root" method. `GL_PACKAGE_HOOKS` is defined in the rc file.
In these two methods, it is reasonable to assume that the entire site (or * `$HOME/.gitolite/hooks/common` has the "user" hooks.
server) has certain policies that they want to implement using hooks. They
want to enforce these hooks on *each hosting user*. These hooks go into
`$GL_PACKAGE_HOOKS`.
Each hosting user then has the discretion to add his own hooks (modulo name <font color="gray">The special "post-update" hook for the equally special
clashes, which may necessitate hook chaining, etc., like we already do for the "gitolite-admin" repo is not in either of those places. It's in
hooks that gitolite cares about). He adds these hooks to his `../gitolite-admin` relative to them. Just don't worry about it, and don't
`$HOME/.gitolite/hooks` directory. fiddle with it. **There is no spoon**.</font>
When hooks propagate, the ones in `$GL_PACKAGE_HOOKS` override/overwrite the `GL_PACKAGE_HOOKS` is "/var/gitolite/hooks" or some such path for RPM/DEB or
ones in `$HOME/.gitolite/hooks`. Otherwise it wouldn't make sense; you "root" method, and "$HOME/share/gitolite/hooks" for the non-root method.
wouldn't be able to enforce site-wide hooks. (<font color="gray">Basically, it's whatever you gave as the 3rd argument to
'gl-system-install' when you used the root or non-root methods, or whatever
the packager decided if you used the RPM/DEB method</font>).
[NOTE: due to a minor quirk, the site-wide hooks in `$GL_PACKAGE_HOOKS` also ## so where do I put my hooks?
get copied to `$HOME/.gitolite/hooks` when you "install". I need to fix and
thoroughly test this later; for now, just ignore the extra files you see in
there; they're harmless/redundant (TODO)]
### special case: the "non-root" method Put them in the "user" location (`~/.gitolite/hooks/common`).
This method was created later, just piggy-backing on everything that already The "system" location hooks override the ones in the "user" location, as you
existed to cater to the "package" and "root" methods. In this method, the can see from the picture below. This can be useful to enforce site-wide hooks
`$GL_PACKAGE_HOOKS` is as accessible or under your control as when using the RPM/DEB or root install methods. (For the non-root install
`$HOME/.gitolite`, so it doesn't matter where you put your hooks. it's useless, since both locations are under the control of the user).
## **when** do hooks propagate? .gv
First: realise that gitolite *wants to make sure* that all the hooks in your edge [dir=forward color="blue"]
`hooks/common` directory get copied (symlinked, actually) to *every* repo that splines = false
gets created. **Not doing so is generally a security risk; because the
primary purpose of gitolite is access control, people generally *want* hooks
to run.**
Here's how/when hooks are created/propagated: glph [ shape = none label = <
<table>
<tr>
<td colspan="3" bgcolor="red">package/system hooks<br/>$GL_PACKAGE_HOOKS/common</td>
</tr><tr>
<td port="u" bgcolor="lightblue">update</td>
<td port="y1">yourhook1</td>
<td port="y2">yourhook2</td>
</tr>
</table>
>]
1. anytime you do an install, gitolite trawls through *all* existing repos gladh [ shape = none label = <
(using the unix `find` command) and force-links all the hooks in all the <table>
repos so they all get the latest and greatest hooks. <tr>
<td colspan="3" bgcolor="green">user hooks<br/>~/.gitolite/hooks/common</td>
</tr><tr>
<td port="u" bgcolor="lightblue">update</td>
<td port="y1">yourhook1</td>
<td port="y3">yourhook3</td>
</tr>
</table>
>]
2. anytime you do a "compile" (meaning push changes to the admin repo), rh [ shape = none label = <
gitolite looks through all the repos named in the config. It first checks <table>
if the repo exists, creating it if needed. It then looks for a sentinel <tr>
file called "gitolite-hooked" (an empty file in the hooks directory). If <td colspan="4" bgcolor="green">individual repo hooks<br/>$REPO_BASE/reponame.git/hooks</td>
it doesn't find it, it will assume that hooks need to be propagated. </tr><tr>
<td port="u" bgcolor="lightblue">update</td>
<td port="y1">yourhook1</td>
<td port="y2">yourhook2</td>
<td port="y3">yourhook3</td>
</tr>
</table>
>]
This is because people often copy a repo from elsewhere, add it to the rh:y3:n .. gladh:y3
config, and expect things to work. Without this step, those repos don't rh:u:n .. glph:u:s
get the hooks, which is bad -- the access control would have failed rh:y1:n .. glph:y1
silently! rh:y2:n .. glph:y2
3. anytime a new repo is created, the same force-linking of hooks happens. As you can see, when both locations have the same hook, the symlink points to
The 3 places a new repo is created are: the "system" hook.
* the "compile" case mentioned above, where the admin added a normal
repo to the config and pushed
* the wildrepos case, where you have "C" permissions and the repo does
not already exist
* the `fork` command in `contrib/adc`. In this case the hooks are
explicitly copied from the source repo using the `cp` command, not
using the code internal to gitolite.
For people who do not want certain hooks to run for certain repos, one simple
solution that will work right now is to check the value of `$GL_REPO` at the
start of the hook, and `exit 0` based on what it contains/matches.
By default, the only reason you need to touch the "system" location is if you
want to modify the 'update' hook, but why would you fiddle with the most
important part of gitolite, huh? You're a good admin, and will use [hook
chaining][hookchaining] properly, right?