課題:外部サービスに依存せずにコードを共有したい
3〜4人のチームで社内プロジェクトを進めているが、機密情報が含まれているためGitHub publicにはpushできない。GitHub Privateは費用がかかるか制限があり、GitLab self-hostedやGiteaはソフトウェアのインストール、データベース設定、nginx、HTTPSの構成など——最初のコードをpushするまでに膨大な準備が必要だ。
ある日の午後、遊んでいるVPSを眺めながらふと思い出した:Gitはもともとdistributed version controlだ。派手なweb UIもissue trackerも必要ない——メンバー間でコードをpush/pullできる場所さえあればいい。SSHを経由したGit bareリポジトリがその答えで、この方法を1年以上使っているが、問題が起きたことは一度もない。
分析:小規模チームにGiteaやGitHubが不要な理由
GiteaやGitHubはweb UI、pull request、code review、CI/CD integrationなど多くの大規模な課題を解決する。しかし、毎日顔を合わせて働く2〜5人のチームであれば、これらはオーバースペックだ。
Giteaのインストールには以下が必要:
- バックグラウンドで動作するバイナリ(またはDockerコンテナ)
- データベース——SQLiteでも可だが、それでも追加のdependencyが増える
- Nginxリバースプロキシ + SSL証明書
- web UIでのユーザー管理と定期的なソフトウェアアップデート
Git bareリポジトリなら:
- 追加インストール不要——Gitはほとんどのディストリビューションに標準搭載
- SSH keyによる認証——どのチームでも既に使っているもの
- 10分でセットアップ完了
- 外部に公開されるwebサービスがないため、attack surfaceが少ない
トレードオフは明確だ:web UIとpull requestは使えなくなる。しかし、直接顔を合わせて働く小規模チームなら、チャットとgit diffによるレビューで十分だ。
その他の選択肢
ガイドに入る前に、自分のニーズに合ったものを選べるよう、各オプションを簡単に確認しておこう:
- GitHub/GitLab.com——便利だがコードがサードパーティに置かれる。data sovereigntyや社内情報のセキュリティ要件があるプロジェクトには不向き。
- Gitea/Gogs self-hosted——GitHubライクな美しいweb UIを持つが、長期的なインストールと保守が必要。チームが大きくなるか、本格的なweb interfaceが必要な場合に適している。
- SSH経由のGit bareリポジトリ——最も軽量でweb UIはないが、小規模チームには十分。以下で詳しく解説する。
最善策:SSHを使ったGit bareリポジトリのセットアップ
事前準備
必要なもの:
- Linuxサーバー——VPS、社内サーバー、Raspberry Piでも可
- そのサーバーへのSSHアクセス
- Gitがインストールされていること(未インストールの場合は
sudo apt install git)
ステップ1:サーバーにgit専用ユーザーを作成する
ベストプラクティスとして、rootや個人ユーザーを使わず、Git専用のユーザーを作成する:
sudo adduser git
sudo mkdir -p /home/git/.ssh
sudo touch /home/git/.ssh/authorized_keys
sudo chmod 700 /home/git/.ssh
sudo chmod 600 /home/git/.ssh/authorized_keys
sudo chown -R git:git /home/git/.ssh
ステップ2:各メンバーのSSH public keyを追加する
各メンバーが自分のSSH public key(通常は~/.ssh/id_ed25519.pubにある)を送ってくる。そのkeyをサーバーのauthorized_keysファイルに追加する:
# サーバー上でsudo権限で実行
sudo bash -c 'echo "ssh-ed25519 AAAAC3Nza... member1@laptop" >> /home/git/.ssh/authorized_keys'
sudo bash -c 'echo "ssh-ed25519 AAAAC3Nza... member2@workstation" >> /home/git/.ssh/authorized_keys'
あるいは、メンバーが一時的にサーバーにSSHできる場合は、自分のマシンから以下のコマンドでkeyを追加できる:
ssh-copy-id git@your-server-ip
ステップ3:bareリポジトリを作成する
bareリポジトリとはworking treeを持たないリポジトリで、通常のリポジトリ内の.gitディレクトリに相当する純粋なGitデータのみを格納する。サーバー上に必要なのはこれだ。
# サーバー上で、gitユーザーに切り替え
sudo su - git
# 全リポジトリを格納するディレクトリを作成
mkdir -p ~/repos
cd ~/repos
# bareリポジトリを初期化
git init --bare myproject.git
慣例として、bareリポジトリであることがわかるよう.gitという拡張子を末尾につける。
ステップ4:メンバーのマシンからcloneする
サーバーにリポジトリが作成されたら、各メンバーが自分のマシンにcloneする:
# リポジトリをclone(your-server-ipを実際のIPアドレスに置き換える)
git clone git@your-server-ip:repos/myproject.git
# SSHがポート22を使用していない場合
git clone ssh://git@your-server-ip:2222/home/git/repos/myproject.git
以降のワークフローはGitHubとまったく同じだ:
git add .
git commit -m "feat: ログイン機能を追加"
git push origin main
# 同僚の最新コードを取得
git pull origin main
ステップ5:gitユーザーの権限を制限する(推奨)
gitユーザーはGit操作専用であるべきで、フルシェルは必要ない。git-shellで権限を制限しよう:
# git-shellのパスを確認
which git-shell
# /usr/bin/git-shell
# /etc/shellsに追加(まだ存在しない場合)
echo $(which git-shell) | sudo tee -a /etc/shells
# gitユーザーのログインシェルを変更
sudo chsh git -s $(which git-shell)
設定後、gitユーザーとしてSSHしてもGitコマンドの実行でなければ、以下が表示される:
fatal: Interactive git shell is not enabled.
小さいが有効なセキュリティレイヤーを一つ追加することになる。
ステップ6:必要に応じて新しいリポジトリを追加する
新しいプロジェクトができたら、ステップ3を繰り返すだけだ:
sudo su - git
cd ~/repos
git init --bare project2.git
git init --bare internal-tools.git
新メンバーがチームに加わった場合:SSH keyをauthorized_keysに追加するだけ——アカウント作成も追加設定も不要だ。
git push –forceで得た痛い教訓
間違ったブランチにforce pushして重要なコードを失ったことがある——それ以来git push --forceには細心の注意を払っている。具体的には、ローカルブランチをrebaseしてforce pushした際、同僚がそのブランチに新しいcommitを持っていたことを忘れていた。彼らのcommitは完全に上書きされ、git reflogで復元するのに2時間かかった。
bareリポジトリでこれを防ぐために、server-side hookでforce pushを禁止しよう——誰もbypassできない種類のhookだ:
# サーバー上で、bareリポジトリのディレクトリ内にhookを作成
cat > ~/repos/myproject.git/hooks/update << 'EOF'
#!/bin/bash
refname="$1"
oldrev="$2"
newrev="$3"
# mainブランチへのforce pushを禁止
if [ "$refname" = "refs/heads/main" ]; then
if git merge-base --is-ancestor "$oldrev" "$newrev"; then
exit 0
else
echo "mainブランチへのforce pushは禁止されています!"
exit 1
fi
fi
exit 0
EOF
chmod +x ~/repos/myproject.git/hooks/update
より快適に使うための追加ヒント
IPアドレスを覚えなくて済むSSHエイリアスを設定する
各メンバーのマシンの~/.ssh/configに以下を追加する:
Host gitserver
HostName your-server-ip
User git
Port 22
IdentityFile ~/.ssh/id_ed25519
これでより短くcloneできるようになる:
git clone gitserver:repos/myproject.git
シンプルなbareリポジトリのバックアップ
# bundleを作成——全履歴を含む単一ファイル
git -C ~/repos/myproject.git bundle create /backup/myproject-$(date +%Y%m%d).bundle --all
Giteaへのアップグレードはいつ検討すべきか?
SSH経由のGit bareリポジトリは、チームが5人以下でターミナルに慣れており、web UIやpull requestワークフローが不要で、少ないメンテナンスで素早くセットアップしたい場合に適している。
チームが大きくなった場合、新メンバーを頻繁にonboardする必要がある場合、inline commentによるcode reviewが必要な場合、またはメンバーがGit CLIに不慣れな場合はGiteaを検討すべきだ。
嬉しいのは、後で移行しても全く苦労しないことだ:アップグレードが必要になったら、bareリポジトリをGiteaにpushするだけ——全commitの履歴がそのまま保持され、何も失わない。

