Mercurial 独特の概念として、マルチプルヘッドというものがあります。
@ 2:d9ae2b51cade | head b
| default
|
| o 1:8141de67f6ee | head a
|/ default
|
o 0:6af850d9f57f | initial commit
default
図1. defaultブランチがマルチプルヘッド(先端(HEAD)が複数存在している状態)
マルチプルヘッドは hg merge でマージして一つのヘッドに統合してからpushするのがマナーですが、push -fで強制的にpushすることができてしまいます。
[troter:~/tmp/multiple-head]
% hg push
pushing to /home/troter/tmp/central
searching for changes
abort: push creates new remote head 8141de67f6ee!
(did you forget to merge? use push -f to force)
[troter:~/tmp/multiple-head]
% hg push -f
pushing to /home/troter/tmp/central
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files (+1 heads)
[troter:~/tmp/multiple-head]
%
mercurialにはリポジトリに変更を加える前、加えた後にフックスクリプトを実行できます。
フックスクリプトの実行のタイミングはhgrcのhooksの項で確認できます。
今回の例では「リモートからリポジトリに変更が加えられた際」に実行される pretxnchangegroup が利用できそうです。pretxnchangegroupは呼び出したフックスクリプトの終了ステータスが0以外の場合(正常終了以外の場合)トランザクションをロールバックします。
スクリプトを作成しました。(参考にしたスクリプト)
元のスクリプトを改造し、「ユニファイしたブランチ数」と「ユニファイしていないブランチ数」を比較し、数が異なった場合はexit 1しています。
セントラルリポジトリの.hgrcでフックを登録します。
[hooks]
pretxnchangegroup.forceonehead = /path/to/force-one-head
フックスクリプトを.hgディレクトリ以下に置いてある場合は次のように相対パスでしていもできます。
[hooks]
pretxnchangegroup.forceonehead = .hg/force-one-head
では改めて push -f してみましょう。
[troter:~/tmp/multiple-head]
% hg push -f
pushing to /home/trote/tmp/central
searching for changes
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 2 files (+1 heads)
There are multiple heads.
Please 'hg pull' and get your repository up to date first.
Also, don't 'hg push --force' because that won't work either.
transaction abort!
rollback completed
abort: pretxnchangegroup.forceonehead hook exited with status 1
[troter:~/tmp/multiple-head]
%
禁止することができました!
参考にしたスクリプト
を教えてくれた@voluntasさん、バグを指摘してくれた@yoppiblogさん、ありがとうございます。