特定のリモートリポジトリへの誤プッシュを防ぐ方法

本記事の趣旨

GitHubなどで公開されているリポジトリ(以下Aと表記)を利用する際に、以下のようなことをしたくなったとします。

  • クローンしたリポジトリに加えた修正は、オンプレミスのGitLabなど、プライベートなリポジトリ(以下Bと表記)にプッシュしておきたい。
  • リポジトリAにはプッシュしたくない。

このような場合にもっとも簡単な解決策は、リポジトリBが定期的にリポジトリAをミラーリングするように設定を施して、ローカルの環境ではリポジトリBのみをリモートリポジトリに登録しておくことでしょう。

しかし、常にリポジトリBにこのような設定を施せるとは限りません。例えばGitLabの無料版ではこのような設定ができません

リポジトリAからリポジトリBへのミラーリングが不可能な場合は、運用でどうにかするしかありません。ローカルの環境にはリポジトリAとBの両方をリモートリポジトリとして登録しておき、プッシュはリポジトリBにしつつ、ときどきプルやフェッチをリポジトリAに仕掛けることになるでしょう。

こうした運用を行うと、リポジトリBへのプッシュがしたかったのに、誤ってリポジトリAへのプッシュをしてしまうということが起こりえます。それを防ごうというのが本記事の趣旨です。

解決策:Gitフックの利用

リポジトリAへのプッシュを防ぐには、それを行おうとした際に、自動で阻止される仕組みがあればよいことになります。Gitにはこのように何らかの操作をしようとしたときに自動で何らかの処理を走らせる仕組みがあります。これをGitフックといいます。

プッシュの直前に何らかの処理を走らせたい場合にはpre-pushフックが利用できます。これはローカルにクローンしたリポジトリに.git/hooks/pre-pushというスクリプトを作成しておくと、そのスクリプトがプッシュの直前に実行されるというものです。リポジトリAへのプッシュを防ぐためのスクリプトを書いてみました。

#!/bin/sh

read_only_url="[リポジトリAのURL]"

remote="$1"
url="$2"

case "$url" in "$read_only_url" )
    echo "Pushing to $remote ($read_only_url) is prohibited." >&2
    exit 1
    ;;
esac

内容を簡単に説明します。まずリポジトリAのURLを設定します。次に2つの引数を変数に格納します。これは、pre-pushフックのスクリプトにはプッシュ先のリモートリポジトリの名前と場所が引数として与えられるという仕様に則しています。その後、プッシュ先のリモートリポジトリの場所がリポジトリAのURLと等しければ、警告を出力して処理を終了します。

動作確認

Ubuntu 22.04.3 LTS(Windows Subsystem for Linux)、Git version 2.34.1の環境にて試してみました。

$ vi .git/hooks/pre-push  # 上述のスクリプトを作成する
$ chmod u+x .git/hooks/pre-push
$ git push [リポジトリAの名前]
Pushing to [リポジトリAの名前] ([リポジトリAのURL]) is prohibited.
error: failed to push some refs to '[リポジトリAのURL]'

無事にリポジトリAへのプッシュが阻止されました。