さて、前回唐突に今更感ばりばりの記事を投稿したが、それは今回の前振りだ。

Smart-HTTPというらしいgit-http-backendを用いたGitサーバーでよそからHTTP経由でプッシュされた時にはpre-receive、update、post-update、post-receiveの順にフックなるものが実行される。今回は条件によってプッシュをさえぎりたいのでupdateというフックを用いる。CentOS6でPHPはyumで入れてる前提。PHPで以下のような内容のスクリプトを書き、updateという名前でbareリポジトリのhooksディレクトリーに配置する。オーナーはapache.apacheでパーミッションは755。

#!/usr/bin/php
<?php
// define constants
define("ACCESSFILE", dirname(__FILE__) . "/updateaccess");

$pushbranch = $argv[1];
$pushuser = $_SERVER['GIT_COMMITTER_NAME'];

// read access control file
$branches = parse_ini_file(ACCESSFILE, true);
if (!$branches) {
        echo "can't load access control list.\n";
        exit(51);
}

// check pushuser can push to pushbranch
foreach ($branches['branches'] as $key => $val) {
        if (fnmatch("refs/heads/" . $key, $pushbranch)) {
                // branch name match.
                if($val === '') {
                        // all user can push. success.
                        exit(0);
                }
                $users = explode(',', $val);
                foreach ($users as $no => $user) {
                        if (fnmatch(trim($user), $pushuser)) {
                                // user name match. success.
                                exit(0);
                        }
                }
        }
}

echo "user $pushuser can't push to $pushbranch.\n";
exit(1);

そして、同じくhooksにupdateaccessという名前で以下のような普通のテキストファイルを置く。PHPと同じ文法でコメントなども同じ。

[branches]
master = harada, an*
develop = harada, anmochi
issue-* = anmochi,harada
feature-* = anmochi,guest1,guest2
release-* = anmochi
hotfix-* = *
anmochi = anmochi

branchesというセクションの中に羅列されたものが書き込みできるブランチ名一覧で、これ以外の名前のブランチはプッシュできない。
各ブランチ名にイコールで結ばれ、カンマ区切りにされたものがユーザー名一覧で、ここに挙げられたユーザー名のユーザーのみが該当のブランチにプッシュできる。
ブランチ名、ユーザー名ともにクエスチョンやアスタリスクのワイルドカードが使用できる。
上記の例だと、masterブランチにはharadaとanで始まるユーザー名のユーザー、hotfix-で始まるブランチ名は誰でもプッシュできるようになる。