Improve error reporting to mention how a Git repository is discovered
At the moment, when Git gives up with "fatal: not a git repository", it does not say which directory it actually inspected or where that directory came from. This is especially confusing when a leftover environment variable is steering Git somewhere the user did not expect.
In v2 I tried to address this by explaining why the inspected directory was not a valid repository (missing HEAD, HEAD outside refs/, and so on). Junio pointed out that this is less useful than saying which directory was used as the repository and where that came from, since once the user knows that they can go look at the directory themselves. He also pointed out that v2 was uneven, as it named $GIT_OBJECT_DIRECTORY but did not say where the git directory itself came from.
So this iteration takes that direction instead. The validity checks in is_git_directory() and validate_headref() are left untouched, and we only add information at the points where we are about to die.
With this series:
-
An explicitly given git directory says where it came from:
$ cd /srv/git $ export GIT_DIR=project.git ... $ cd ~/src/myproject # later, same terminal $ git status fatal: not a git repository: 'project.git' this path was taken from $GIT_DIR (which can also be set with --git-dir or --bare)
--git-dir and --bare both just set GIT_DIR, so by the time setup runs we cannot tell them apart. I went with a single wording that is true for all three rather than plumbing that information through. Happy to revisit if it is felt to be worth it.
-
The discovery walk says where it started, where it stopped and what GIT_CEILING_DIRECTORIES is set to:
$ echo 'export GIT_CEILING_DIRECTORIES=$HOME' >> ~/.bashrc ...weeks later... $ cd ~/.config/nvim $ git status fatal: not a git repository (or any of the parent directories): .git searched from '/home/user/.config/nvim' up to '/home/user/.config' $GIT_CEILING_DIRECTORIES is set to '/home/user'
-
An unusable $GIT_OBJECT_DIRECTORY, which was the original motivation for this series, is reported wherever we die for want of a repository (explicit git directory, ceiling and mount point):
$ GIT_OBJECT_DIRECTORY=/does/not/exist git --git-dir repo.git rev-parse --is-bare-repository fatal: not a git repository: 'repo.git' this path was taken from $GIT_DIR (which can also be set with --git-dir or --bare) cannot access object directory '/does/not/exist' set via $GIT_OBJECT_DIRECTORY: No such file or directory
Commands that are fine running outside a repository stay silent and do not build these messages at all.
This series does not handle the following, which I think are better done separately:
- The gitfile case (for instance from inside a submodule or a worktree). A gitfile pointing at an invalid repository dies earlier in read_gitfile() with its own message.
- GIT_ALTERNATE_OBJECT_DIRECTORIES. It never leads to "not a git repository". Its diagnostics are misleading in their own way (one of them points at .git/objects/info/alternates even when the entry came from the environment), but they come from the object database rather than from setup.
- The "$GIT_CEILING_DIRECTORIES is set to" line is printed whenever the variable is set, even if none of its entries is above the current directory and the walk went all the way to '/'. The "searched from ... up to '/'" line makes that visible, and getting it exact would mean passing more state out of the discovery walk.
CI:
They seem to pass.
- GitLab: !672
- GitHub: https://github.com/sivaraam/git/actions/runs/40676055975
Changes since v2:
- Dropped is_git_directory_verbose() and the HEAD-related reasons, as per Junio's review. is_git_directory() and validate_headref() are now unchanged.
- New: say where an explicitly given git directory came from.
- New: say where the discovery walk started and stopped, and what GIT_CEILING_DIRECTORIES is set to.
- Reworked the GIT_OBJECT_DIRECTORY reporting to ask once at the point of failure, and extended it to the discovery walk (ceiling and mount point).
- Dropped the test for HEAD being a symlink outside refs/, as the series no longer cares about it. This test was failing on Windows in v2.
- Reworked the t0009 tests to check the new messages, including that a command which does not need a repository stays silent.
- Kept each message as a single translatable string and added TRANSLATORS comments describing the placeholders.
Fixes #194