virtual refs
VREF-makers shipped with gitolite
restricting pushes by dir/file name
The "NAME" VREF allows you to restrict pushes by the names of dirs and files changed. (Side note: the NAME VREF is the only one directly implemented within the update hook, so you won't find it in the VREF directory).
Here's an example. Say you don't want junior developers pushing changes to the Makefile, because it's quite complex:
repo foo RW+ = @senior_devs RW = @junior_devs - VREF/NAME/Makefile = @junior_devs
When a senior dev pushes, the VREF is not invoked at all. But when a junior dev pushes, the VREF is invoked, and it returns a list of files changed as virtual refs, looking like this:
VREF/NAME/file-1
VREF/NAME/dir-2/file-3
...etc...
Each of these refs is matched against the access rules. If one of them
happens to be the Makefile, then the ref returned (VREF/NAME/Makefile
) will
match the deny rule and kill the push.
Another way to use this is when you know what is allowed instead of what is not allowed. Let's say the QA person is only allowed to touch a file called CHANGELOG and any files in a directory called ReleaseNotes:
repo foo RW+ = @senior_devs RW = @junior_devs RW+ = QA-guy RW+ VREF/NAME/CHANGELOG = QA-guy RW+ VREF/NAME/ReleaseNotes/ = QA-guy - VREF/NAME/ = QA-guy
number of changed or new files
The COUNT VREF is used like this:
- VREF/COUNT/9 = @junior-developers
In response, if anyone in the user list pushes a commit series that
changes more than 9 files, a virtual ref of VREF/COUNT/9
is returned.
Gitolite uses that as a "ref" to match against all the rules, hits the same
rule that invoked it, and denies the request.
If the user did not push more than 9 files, the VREF code returns nothing, and nothing happens.
COUNT can take one more argument:
- VREF/COUNT/9/NEWFILES = @junior-developers
This is the same as before, but have to be more than 9 new files not just changed files.
advanced filetype detection
Note: this is more for illustration than use; it's rather specific to one of the projects I manage but the idea is the important thing.
Sometimes a file has a standard extension (that cannot be 'gitignore'd), but it is actually automatically generated. Here's one way to catch it:
- VREF/FILETYPE/AUTOGENERATED = @all
You can look at src/VREF/FILETYPE
to see how it handles the
'AUTOGENERATED' option. You could also have a more generic option, like
perhaps BINARY, and handle that in the FILETYPE vref too.
checking author email
Some people want to ensure that "you can only push your own commits".
If you force it on everyone, this is a very silly idea (see "Philosophical
Notes" section of src/VREF/EMAIL-CHECK
).
But there may be value in enforcing it just for the junior developers.
The neat thing is that the existing contrib/update.email-check
was just
copied to src/VREF/EMAIL-CHECK
and it works, because VREFs get
the same first 3 arguments and those are all that it cares about. (Note: you
have to change one subroutine in that script if you want to use it)
voting on commits
Although gitolite can't/won't do the whole "code review + workflow
enforcement" thing that Gerrit Code Review does, a basic implementation of
voting on a commit is surprisingly easy. See src/VREF/VOTES
for details
(and note that the actual code is just 2-3 lines; the rest is inline
documentation).
other ideas -- code welcome!
"no non-merge first-parents"
Shruggar on #gitolite wanted this. Possible code to implement it would be something like this (untested)
[ -z "$(git rev-list --first-parent --no-merges $2..$3)" ]
This can be implemented using src/VREF/MERGE-CHECK
as a model. That script
does what the 'M' qualifier does in access rules (see last part of
this), although the syntax to be used in conf/gitolite will be
quite different.
other ideas for VREFs
Here are some more ideas:
- Number of commits (
git rev-list --count $old $new
). - Number of binary files in commit (currently I only know to count
occurrences of
Bin
in the output ofgit diff --stat
. - Number of new binary files (count
Bin 0 ->
ingit diff --stat
output). - Time of day/day of week (see example snippet somewhere above).
- IP address.
- Phase of the moon.
Note that pretty much anything that involves $oldsha..$newsha
will have to
deal with the issue that when you push a new tag or branch, the "old" part
is all 0's, and unless you consider --all
existing branches and tags it
becomes meaningless in terms of "number of new files" etc.