gitコマンドがgitリポジトリを探す順番

概要: 多くのgitコマンドは特定のgitリポジトリに対する操作であるから、現在位置から対応するリポジトリを発見する必要がある。環境変数コマンドラインオプションで指定された場合を除き、gitはまず ./.git ファイル、 ./.git/ ディレクトリ、 . の3つを試し、それでだめなら再帰的に親ディレクトリを検索する。

gitリポジトリの検索結果を表示する

git rev-parse --git-dir
git rev-parse --show-toplevel

gitコマンドがgitリポジトリを探す順番

gitが処理をするときはまず、gitdirとworktreeと呼ばれる2つのディレクトリの位置を同定する必要がある。

gitコマンドがgitリポジトリを探す処理は、 setup.c の中の setup_git_directorysetup_git_directory_gentlysetup_git_directory_gently_1に記述されている。

まず、環境変数 GIT_DIR が設定されている場合は、これがそのままgitdirとして使われる。 (git コマンド全体のオプションである --git-dir は単に GIT_DIR をその場で設定するオプションである。) この場合のworktreeの発見手順は複雑だが、例えば GIT_WORK_TREE が設定されているときはこれがそのまま採用される。

GIT_DIR が設定されていない場合はまず以下の順にチェックする。

  1. ./.git という通常ファイルがあり、内容が gitdir:で始まっている。また続く文字列は別のディレクトリへのパスになっており、そのディレクトリはgitdirにふさわしい構造を持っている。このとき、この時点での . がworktreeになる。
  2. ./.git/ というディレクトリがあり、そのディレクトリはgitdirにふさわしい構造を持っている。このとき、この時点での . がworktreeになる。
  3. . というディレクトリがあり、そのディレクトリはgitdirにふさわしい構造を持っている。このときこのリポジトリはbare扱いで、worktreeは設定されない。

以上のチェックをしてもgitdirが見つからない場合は、ひとつ上のディレクトリにcdして同じ探索を繰り返す。ただし、以下の条件で探索を打ち切る。

  • / または、 GIT_CEILING_DIRECTORIES で指定されたディレクトリまで到達した。
  • 異なるファイルシステムに到達したが、 GIT_DISCOVERY_ACROSS_FILESYSTEM が設定されていなかった。

ところで、gitdirにふさわしい構造かどうかは is_git_directoryで判定されている。これは次の3つ全てがあるときにgitdirと判定している。

  • 適切にフォーマットされた ./HEAD ファイル。ただし適切にフォーマットされているとは次のいずれかの条件を満たすことをいう
    • refs/ 以下へのシンボリックリンクである。 (参照先の存在はチェックされない)
    • ref:と任意個の空白から始まる通常ファイルで、その続きには refs/ 以下のファイルへのパスが書かれている。 (参照先の存在はチェックされない)
    • 40桁の16進数(SHA-1ハッシュ)が書かれた通常ファイルである。
  • ディレクトobjects/ が存在する。ただし、 GIT_OBJECT_DIRECTORY 環境変数が存在するなら、 objects/ のかわりにこの環境変数の中身が使われる。
  • ディレクトrefs/ が存在する。

まとめ

上の発見手順からわかるように、non-bareリポジトリ内でも、特に .git 内からコマンドを呼び出している場合はbareリポジトリに準ずる扱いを受ける。(worktreeの内部ではないと判定される。)