3 <center>(part 1)</center>
7 VREFs are a mechanism to add additional constraints to a push.
9 They are also the simplest way to add your old update hooks to gitolite --
10 they'll just work, no coding changes needed. If that's all you need, you
11 should head over to the [cookbook](cookbook) and look for the section on "adding your
14 !!! danger "IMPORTANT:"
16 Fallthru is success in VREFs, unlike for normal refs. That won't make
17 sense until you read further, but I had to put it up here for folks who
22 Here's an example to start you off.
24 To disallow junior developers from changing more than five files, or from
25 touching the Makefile, you can do this:
31 - VREF/COUNT/5 = @junior-devs
32 - VREF/NAME/Makefile = @junior-devs
35 Here's a pictorial representation of what happens, at a very high level, based
36 on the `VREF/COUNT/5` rule in the rule list above.
40 1. To start with, git-receive-pack calls the update hook with what we will
41 call a "real" ref, something like "refs/heads/master", or
42 "refs/tags/v1.0" -- in general, something that starts with "refs/".
44 This ref is sent through "[check #2][c1c2]" (please click to refresh your
47 Any rules that specify a [refex][] starting with "VREF/" clearly won't
48 match and are ignored in this check.
50 2. Assuming that check did not fail, the gitolite code in the update hook
51 then starts looking at each "VREF" rule in the rule list that applies to
52 that repo accessed by that user. For each one, it runs the actual VREF
53 program whose name is given in the word after `VREF/`. (The rest of the
54 words, if any, along with all sorts of other information, are supplied as
55 [arguments][vref-args]).
57 3. The STDOUT of the called program is captured and any line that starts with
58 the characters `VREF/` is taken as a "**virtual**" ref, and is run through
59 the same "[check #2][c1c2]". <span class="red">**The only difference is that, unlike
60 for a regular ref, fallthru does not result in failure, but
63 [c1c2]: conf-2#putting-it-all-together
64 [refex]: conf#the-refex-field
65 [vref-args]: vref#what-arguments-are-passed-to-the-vref-maker
67 # basic use and understanding
69 Normally, rules deal with branches and tags (which git collectively calls
70 "refs"). The "ref" is a property of the push which gitolite checks against
73 "Virtual refs" are other properties of a push that gitolite can be told to
74 check, in addition to the normal ref. For example, "this push has more than 5
75 changed files" could be one property. Or "this push changed the file called
76 Makefile" could be another. These properties are represented as "virtual
77 refs" that start with `VREF/`. (Recall that "normal" refs start with
80 The simplest way to use them is as *additional* "deny" rules to fail a push
81 that might otherwise have passed. This is what the example at the top shows.
83 It helps to separate VREF rules from normal rules, since no access rule can
84 match both a normal ref and a virtual ref. Here's a good way to structure your
87 * Put your normal ref rules first. These apply to the branch name or tag
88 name that git itself knows about and sends to gitolite's update hook.
90 Fallthru is failure here, which means the ref being pushed **must** match
91 some rule in this set for the push to succeed.
93 * Put your VREF rules next. These apply to the virtual refs you want to
94 use as additional checks for the push.
96 Fallthru is success here, which means the (virtual) ref must be
97 **explicitly denied** in order for the push to fail.
101 More complex uses are possible, but may be harder to understand. You may want
102 to experiment with the rules to solidify your understanding as you read this.
104 ## differences from normal refs
106 We know where normal refs (like `refs/heads/master` or `refs/tags/v1.0`) come
107 from -- they are supplied by git itself when it calls the update hook.
109 Virtual refs have two differences with normal refs:
111 * Gitolite has to generate them somehow.
112 * Fallthru is success, not failure.
116 * First, the normal ("real") ref is checked.
118 As you already know, the push dies if the ref hits a deny rule **or** it
119 falls through without hitting an allow rule.
121 * Next, virtual refs are generated and checked one by one.
123 We'll talk about the generaton later, but for the check, a virtual ref
124 kills the push *only* if it meets an explicit deny rule ("-"); fallthru
125 does *not* cause failure. Other than that, the checking is done the same
126 way as for a normal ref, viz., as described in the flow for [check #2][c1c2].
128 ## generating virtual refs
130 Gitolite uses the VREF rules themselves to help it generate the virtual refs.
132 Specifically, it looks at each rule that contains a VREF (there are 2 in the
133 above example) and calls a VREF-maker for each of them.
135 We'll take the COUNT example rule above.
137 When gitolite sees that rule, it calls the "COUNT" VREF-maker. Specifically,
138 this is the `VREF/COUNT` program (See [here](non-core) for actual locations on
141 Gitolite passes it the string "5" as an argument (actually, as the *eighth*
142 argument; details later).
144 The program (which can be written in any language) is expected to do one of
147 * If the condition is satisfied (i.e., there *are* more than 5 files in this
148 push), it should print `VREF/COUNT/5` to STDOUT.
150 You can see that when this virtual ref is processed through the rules, it
151 will encounter the "deny" rule, and thus kill the push.
153 * Otherwise it should print nothing. That is, there is no virtual ref to
154 run through "[check #2][c1c2]", so nothing happens.
156 It should exit with an exit code of zero in either case.
158 If it exits with a non-zero, the push dies regardless of what is printed (see
159 "mimicking a plain old update hook" for why this is useful).
161 # more details and nuances
163 ## mimicking a plain old update hook
165 If the VREF maker exits with a non-zero exit code, then regardless of what it
166 prints or does not, the push dies.
168 This is just like a plain 'update' hook. Since the first 3 arguments (see
169 later) are also the same that a plain 'update' hook receives, you can actually
170 use any existing update hook as a VREF-maker.
172 To repurpose an existing update hook as a VREF-maker, just copy it to the VREF
173 directory (again, see [here](non-core) for actual locations on disk). Then
174 add this rule to your repos:
177 repo foo # or maybe even 'repo @all'
178 - VREF/my-update-hook = @all
183 ## what if the VREF-maker prints a different virtual ref?
185 Unless you know what you're upto, don't do that.
187 But it's allowed and the behaviour is defined. The VREF-maker for the NAME
188 VREF is a good example. It ignores the arguments and just makes VREFs out of
189 the name of every file that was changed in the push.
191 Here's another example. Consider the problem of not allowing pushes at
192 specific times. Let's say repo 'foo' cannot be pushed between 4 and 7pm, and
193 repo 'bar' can only be pushed before 9am. And of course all this only applies
194 to the junior developers, the poor guys!
196 In this example, we write the "Hour" VREF-maker to *ignore the argument
197 passed* and just print `VREF/Hour/NN` where NN can be between 00 to 23
198 inclusive and of course represents the current hour.
200 If foo is pushed at 6:30pm, the VREF-maker prints VREF/Hour/18, which
201 satisfies the third rule and is rejected.
203 If bar is pushed at, say, 7:20am, the vref printed is VREF/Hour/07, which does
204 not match any of the rules. And fallthru is success so it passes.
210 - VREF/Hour/16 = @junior-devs
211 - VREF/Hour/17 = @junior-devs
212 - VREF/Hour/18 = @junior-devs
217 - VREF/Hour/09 = @junior-devs
218 - VREF/Hour/1[0-9] = @junior-devs
219 - VREF/Hour/2[0-9] = @junior-devs
222 ## why is fallthru considered success with VREFs
224 Virtual refs are **best used** (1) as **additional** "deny" rules, performing
225 extra checks that core gitolite cannot. You usually want such extra checks
226 only for some people.
228 When fallthru is success, you can simply *ignore* all the other users (for
229 whom such additional checks are not needed).
231 If fallthru were to be considered 'failure', you'd be forced to add a "success
232 rule" like this for *every* virtual ref you used in this repo, in each case
233 listing every user who was not already mentioned in the context of that vref:
236 RW+ VREF/VREFNAME = @userlist # uggh! what a pain!
239 Worse, since every virtual ref involves calling an external program, many of
240 these calls may be wasted.
242 <font color="gray">(1) "best used as..." does not mean "only used as...". For
243 example it's perfectly easy to turn this around if, instead of having a list
244 of people who *do* need extra checks, all you have is the complementary
248 RW+ VREF/NAME/Makefile = @senior-devs
249 - VREF/NAME/Makefile = @all
254 ## what if the VREF-maker prints something that's not even a virtual ref?
256 The VREF-maker can print anything it wants to STDOUT. Lines not starting with
257 `VREF/` are printed as is (so your VREF-maker can do mostly-normal printing to
258 STDOUT). This is especially useful if you've turned an existing update hook
259 into a VREF-maker, and it prints stuff meant for the user, but you don't want
262 For lines starting with `VREF/`, the first word in each such line will be
263 treated as a virtual ref, while the rest, if any, is a message to be added to
264 the standard "...DENIED..." message that gitolite will print if that refex
265 matches and the rule is a deny rule.
267 ## in what order are VREF-makers called?
269 VREF-makers are called in the sequence in which they appear in the conf file.
271 There are some optimisations to prevent calling the same VREF-maker with the
272 same arguments more than once, and the VREF-maker code for the NAME VREF
273 (which is special) is called only once regardless of how many times it appears
274 but these details should not concern anyone but a developer.
276 ## what arguments are passed to the vref-maker?
278 * Arguments **1, 2, 3**: the `ref`, `oldsha`, and `newsha` that git passed
279 to the update hook (see `man githooks`).
281 This, combined with the fact that non-zero exits are detected, mean that
282 you can simply use an existing update.secondary as a VREF-maker as-is, no
285 * Arguments **4 and 5**: the 'oldtree' and 'newtree' SHAs. These are the
286 same as the oldsha and newsha values, except if one of them is all-0.
287 (indicating a ref creation or deletion). In that case the corresponding
288 'tree' SHA is set (by gitolite, as a courtesy) to the special SHA
289 `4b825dc642cb6eb9a060e54bf8d69288fbee4904`, which is the hash of an empty
292 (None of these shenanigans would have been needed if `git diff $oldsha $newsha`
293 would not error out when passed an all-0 SHA.)
295 * Argument **6**: the attempted access flag. Typically `W` or `+`, but
296 could also be `C`, `D`, or any of these 4 followed by `M`. If you have to
297 ask what they mean, you haven't read enough gitolite documentation to be
298 able to make virtual refs work.
300 * Argument **7**: is the entire refex; say `VREF/COUNT/3/NEWFILES`.
302 * Arguments **8 onward**: are the split out (by `/`) portions of the refex,
303 excluding the first two components. In our example they would be `3`
304 followed by `NEWFILES`.
306 Yes, argument 7 is redundant if you have 8 and 9. It's just more convenient
307 for scripts to have both available, without having to split/join.