Git has two option --git-dir and --work-tree. What is the use for them?

Usually, when we create a project repository in dir ~/projects/foo via git init command. The git directory is ~/projects/foo/.git, where all the repository info is stored like the following:

├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects
│   ├── 0c
│   │   └── fa957df522a120551c8d6147cacbeffd97d4e1
│   ├── 5e
│   │   └── fb9bc29c482e023e40e0a2b3b7e49cec842034
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

The repository’s work tree is the root directory of this project, i.e., ~/projects/foo. When we use git command such as git status inside in git repository, git will find .git directory in the directory or upward until it finds the .git directory. So we do not need to specify where the .git dir is.

When we want to get the info a repository outside it, we now need to specify the --git-dir and --work-tree to tell git which repository we refer to:

# outside ~/projects/foo
git --git-dir=$HOME/projects/foo/.git --work-tree=$HOME/projects/foo status

Note that the path to --git-dir and --work-tree can be an absolute or relative path (relative to current working directory). If it is an absolute path, tilde ~ won’t be expanded . You need to use $HOME or absolute path.

As a matter of fact, the .git and work-tree for a repository does not need to be in the same location. For example, run the following command:

mkdir a b
git init --separate-git-dir a/ b/

Directory a/ will act as .git directory storing all the info for work-tree root at b/. If you look at the b/.git, it will a plain file pointing to the absolute path of a/ directory:

gitdir: /path/to/a/dir

To get info about this repository, we can run git like this:

git --git-dir=a/ --work-tree=b/ status