The fastest way to lose twenty minutes is typing git pull in the folder above your repo. Git answers fatal: not a git repository (or any of the parent directories): .git, and most answers online reply with git init — which is wrong for three of the four real causes.
The 60-second triage:
git rev-parse --show-toplevel || ls -a --show-toplevel prints your repository root when one exists above you: wrong directory, case closed, cd there. When it fails too, the same line lists the folder’s contents: no .git in that list means there was never a repo here to find. That single command separates the two causes behind most occurrences. The rest of this post is the smaller cases.
Why does Git say “fatal: not a git repository”?
Git finds a repository by walking up from the current directory, hunting for a .git entry, and stops at the first one. That walk breaks in exactly four ways: you stand outside the tree, the .git folder is gone, an environment variable redirects the search, or .git exists but points at nothing. Stack Overflow’s 2022 Developer Survey put Git on roughly 94% of developer machines, so the error is a shared rite of passage. Learn the four cases once and they stop costing time.
(If your repo is fine and you actually came here to undo a commit, Undo Anything in Git collects every repair path on this site in one place.)
Case 1: you are in the wrong directory
The common one. Two shapes:
- You
cd‘d into a subfolder (docs/,src/api/) and the shell habit from another project says the repo root is here. Git walks up, finds nothing, quits. - You cloned a repo and expected the files here, but
git clonealways creates a subdirectory named after the repo. The checkout sits one level below where you’re standing.
git rev-parse --show-toplevel # prints the root when one exists
cd "$(git rev-parse --show-toplevel)" # jump there in one step The second command is the permanent fix for the muscle-memory problem: it works from any depth inside the repo.
Case 2: there is no .git — the folder never was a repo
ls -a shows no .git. Usually one of:
- A GitHub ZIP download. Code → Download ZIP ships the files only: no
.git, no history, no remote. GitHub’s own docs confirm the ZIP archive contains the source snapshot alone. - Files copied in from a machine or another project, without the hidden folder.
- A cleanup tool deleted
.gitas “hidden junk”.
Fix: re-clone to recover the history.
cd ..
git clone https://github.com/<user>/<repo>.git git init here starts a fresh repository; nothing is recovered. And the copied-files mess usually drags untracked strays with it; git remove untracked files covers the cleanup once the clone is in place.
git initdoesn’t repair a repo — it creates an empty one where you stand.
Case 3: GIT_DIR is set, and breaks every repo
The tell: the error follows you into directories where Git worked an hour ago. An exported GIT_DIR tells Git to look at one fixed path instead of discovering the repo, so every “ordinary” directory becomes “not a repository”.
env | grep GIT_DIR # GIT_DIR=/some/old/path
unset GIT_DIR If it comes back every morning, a line in ~/.bashrc, ~/.zshrc, or a CI wrapper exports it. CI systems set GIT_DIR deliberately: correct inside the pipeline, a landmine in your interactive shell.
Case 4: the submodule was never initialized
You cd into vendor/libfoo/, and Git says the directory is not a repository. It isn’t: until initialized, a submodule directory is an empty folder with an entry in .gitmodules and nothing checked out.
cat .gitmodules # lists the submodule paths
git submodule update --init --recursive Run that from the repo root, not inside the submodule. The same walk-up rule applies, and the empty submodule has no root to walk to.
Case 5: .git is a file, and its target is gone
Worktrees and submodules make .git a one-line file: gitdir: /path/to/real/gitdir. When the real gitdir is deleted (a cleaned .git/modules, a moved drive), the pointer dangles and the walk-up finds a .git that answers nothing:
$ ls -la .git
-rw-r--r-- 1 you you 35 Sep 28 10:12 .git # a file, not a directory
$ cat .git
gitdir: ../.git/modules/libfoo git worktree repair # re-links worktrees whose paths changed If worktree repair can’t find the target, the gitdir is gone for good. Re-clone. The history lives in the parent repo’s .git/modules/<name> for submodules; check it exists before assuming the worst.
Symptom → cause → fix
| Symptom | Likely cause | Fix |
|---|---|---|
Error in one project, ls -a shows no .git | ZIP download / copied files | git clone again |
| Error from a subfolder, root works | Standing outside the tree | cd "$(git rev-parse --show-toplevel)" |
| Error in every directory, even ones that worked | GIT_DIR exported | unset GIT_DIR, purge it from the shell profile |
| Error inside a submodule folder | Submodule not initialized | git submodule update --init --recursive |
.git is a file, error persists | Dangling worktree/submodule pointer | git worktree repair, else re-clone |
So is git init ever the right fix?
Once: when ls -a shows no .git and you intend to start a brand-new repository here. Run it, and the next command is git add, not git log.
Everywhere else it’s a trap with a signature. git init one folder too deep builds a nested repo with zero commits, and your next git log answers fatal: your current branch 'main' does not have any commits yet. That error means you just created a repository where you stood, and the real one is one level up. The cleanup is surgical:
cd the-nested-folder
rm -rf .git # removes only the accidental repo, files untouched Double-check the prompt before that rm: it must run inside the nested folder, never at the project root. Then cd back to the real root and confirm with git rev-parse --show-toplevel that Git finds what it was always supposed to find.
FAQ
Why does git status say fatal: not a git repository?
Git searches the current folder and every parent for a .git directory. No .git anywhere up the tree means no repository: usually you are in the wrong folder, or the project arrived without one.
Does git init fix fatal: not a git repository?
Only where no repo ever existed. init creates a new, empty repository and cannot recover history from anywhere. Run it one folder too deep and you get a nested repo with no commits instead.
How do I fix the error inside a submodule?
From the repo root: git submodule update --init --recursive. A submodule directory stays empty until then, and Git calls it not a repository.
Why does the error appear in every repository on my machine?
An exported GIT_DIR variable overrides repo discovery everywhere. Run env | grep GIT_DIR, then unset GIT_DIR, and remove it from your shell profile if it keeps coming back.
— mrsaynothing
$ Share this post
$ Get the next how-to by email
One email per post. Fix it and move on.
what is this?