Back to blog

Fatal: Not a Git Repository? The 60-Second Fix

28 September 2026

did this fix it?

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:

  1. 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.
  2. You cloned a repo and expected the files here, but git clone always 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 .git as “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 init doesn’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

SymptomLikely causeFix
Error in one project, ls -a shows no .gitZIP download / copied filesgit clone again
Error from a subfolder, root worksStanding outside the treecd "$(git rev-parse --show-toplevel)"
Error in every directory, even ones that workedGIT_DIR exportedunset GIT_DIR, purge it from the shell profile
Error inside a submodule folderSubmodule not initializedgit submodule update --init --recursive
.git is a file, error persistsDangling worktree/submodule pointergit 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

$ Get the next how-to by email

One email per post. Fix it and move on.

self-hosted · no third parties · one-click unsubscribe

what is this?