クイックフィックス (TL;DR)
今すぐ解決が必要な場合は、リポジトリのルートで以下の3つのコマンドを実行して権限をリセットし、チームでGitが正常に動作するように強制します。
# 1. 所有グループをチームのグループ(例: 'developers')に変更する
sudo chown -R :developers .git
# 2. グループに読み取り/書き込み/移動(実行)権限を付与する
sudo chmod -R g+rwX .git
# 3. 今後作成されるすべてのオブジェクトでグループ権限を尊重するようGitに強制する
git config core.sharedRepository group
何が起きているのか?
これは典型的なLinuxの権限の衝突です。通常、複数の開発者が各自のアカウントを使用してSSH経由でコードをデプロイするステージングサーバーや共有ワークステーションで発生します。
この衝突はデフォルトのumaskから始まります。Aliceがgit pullを実行すると、Gitは.git/objectsフォルダ内に新しいオブジェクトを作成します。デフォルトでは、これらのファイルはAliceが所有し、他のユーザーは読み取り専用になることがよくあります。5分後にBobが変更をコミットしようとすると、Gitはそれらと同じディレクトリを変更しようとしますが、Aliceのファイルに対する書き込み権限がないため、Bobはエラーに直面します。
恒久的な解決策
1. 既存のファイル所有権を修復する
まず、現在の混乱を整理する必要があります。共有グループ内のすべてのユーザーがリポジトリデータベースを実際に操作できるようにする必要があります。まず、共有グループ名を確認することから始めましょう。
# 自分が所属しているグループを確認する
groups
# .gitフォルダのグループを再帰的に更新する
sudo chown -R :developers .git
# グループがディレクトリの読み取り、書き込み、アクセスができるよう 'rwX' を適用する
sudo chmod -R g+rwX .git
2. 「魔法の弾丸」:Git共有リポジトリモード
一度権限を修正するだけでは、一時的な応急処置にすぎません。次に誰かがコードをプッシュしたとき、Gitは再び制限の厳しい0644権限で新しいファイルを作成してしまいます。リポジトリを「共有対応」にする必要があります。
git config core.sharedRepository group
この設定はGitの動作を変更します。ユーザーのデフォルトマスクを使用する代わりに、新しいファイルがグループ書き込み可能(通常は0664または0775)になるよう強制します。完全にオープンな内部サーバーであれば、groupの代わりにworldを使用することもできますが、安全な策とは言えません。
3. グループメンバーシップの再確認
ユーザーが実際に指定したグループに属していない場合、この修正は機能しません。ユーザーをdevelopersグループに追加するのは簡単です。
sudo usermod -a -G developers username
注意:グループの変更はすぐには反映されません。システムが新しい権限を認識するには、ユーザーは一度ログアウトしてからログインし直す必要があります。
修正の確認方法
言葉を鵜呑みにせず、実際に確認しましょう。別のユーザーアカウントに切り替えて、リポジトリ全体の更新を試みてください。ガベージコレクション(GC)タスクは、ほぼすべてのオブジェクトに触れるため、最適なテストになります。
# objectsディレクトリの権限を確認する
ls -la .git/objects
# 手動でガベージコレクションを実行する
git gc
If git gc が「insufficient permission」エラーを出さずに完了すれば、リポジトリの制御に成功したことになります。
予防のためのプロのヒント
Linuxの権限設定は、特に775や664のような8進数値を計算し始めると頭痛の種になります。複雑な環境を構築する場合は、Unix Permissions Calculatorを使用して、誰がアクセス権を得るのかを正確に可視化してください。これにより、ワークフローのボトルネックを解消しようとして誤ってセキュリティホールを作ってしまうのを防ぐことができます。
スティッキービットによる解決策
「一度設定すればあとはお任せ」のアプローチには、setgidビットを使用します。これにより、誰が作成したかにかかわらず、.git/objects内に作成された新しいファイルは自動的にdevelopersグループを継承するようになります。
find .git/objects -type d -exec chmod g+s {} +

