Git says it can't find a repo where you're standing. Nine times out of ten it's the wrong directory, a missing .git, or an ownership check.
You run git status, expecting the usual list of changed files, and instead git slaps you with:
fatal: not a git repository (or any of the parent directories): .git
This one trips up beginners and senior engineers alike, usually because git is telling the literal truth and we don't believe it. Git walks up from your current directory looking for a .git folder. It checks where you are, then the parent, then the parent of that, all the way to the filesystem root. If it never finds one, you get this error. That's the whole mechanism. Every fix below is just a different reason git couldn't find that folder.
Let me walk through the causes in the order I actually hit them, most common first.
This is the boring answer and it's right most of the time. You opened a new terminal, or a script cd'd somewhere, and now you're standing in a folder that has nothing to do with your repo.
Check where you are:
pwd
# /Users/kiril/Downloads
ls -la | grep git
# (nothing)
No .git here. Go to where your repo actually lives:
cd ~/projects/my-app
git status
# On branch main
# nothing to commit, working tree clean
Fixed. Before you do anything clever, run pwd and ls -la. I have wasted real minutes debugging git only to realise I was one directory too high.
Sometimes there's genuinely no repository because you never made one. You created a folder, dropped some files in, and started running git commands as if it were already tracked.
ls -la
# total 8
# drwxr-xr-x 4 kiril staff 128 Jul 11 09:14 .
# drwxr-xr-x 20 kiril staff 640 Jul 11 09:10 ..
# -rw-r--r-- 1 kiril staff 42 Jul 11 09:14 main.py
No .git directory in that listing. If this folder should be a repo, initialise it:
git init
# Initialized empty Git repository in /Users/kiril/projects/thing/.git/
git add .
git commit -m "initial commit"
If it's supposed to be a clone of something remote, don't git init on top of it. Clone it fresh into a new folder instead.
A close cousin. You cloned a repo, but the .git folder ended up somewhere you didn't expect, or someone (maybe a cleanup script, maybe you) deleted it.
The tell is that all your files are present and correct, but git acts like it's never seen them. That's because the working files and the .git metadata are separate things. Delete .git and you've got a plain folder full of files with no history.
ls -la
# your files are all here...
# but no .git directory
If you have a remote, the cleanest fix is to re-clone and copy your uncommitted work over:
git clone git@github.com:you/my-app.git /tmp/my-app-fresh
# then move any local-only changes into the fresh clone
Trying to resurrect a half-deleted .git is rarely worth it. Re-clone and move on.
Git only searches upward, never downward. If your repo is at ~/projects/my-app and you're sitting in ~/projects, git looks in ~/projects, then ~, then /, and finds nothing. It will never look into my-app for you.
pwd
# /Users/kiril/projects
git log
# fatal: not a git repository (or any of the parent directories): .git
cd my-app
git log
# commit 4f1a9c2 (HEAD -> main) ...
One cd down and you're back in business.
Less common, but nasty when it happens. Git respects the GIT_DIR environment variable. If some script or a stray line in your shell profile exported it to a path that doesn't exist, git will look there and only there, ignoring the .git under your feet.
echo $GIT_DIR
# /some/old/path/.git
unset GIT_DIR
git status
# On branch main
If unsetting it fixes things, hunt down whatever set it. Check ~/.zshrc, ~/.bashrc, and any wrapper scripts you source.
Clone a repo with submodules and the submodule folders show up empty. Step into one and run a git command, and you get the same error, because the submodule's .git link hasn't been populated yet.
cd libs/shared
git status
# fatal: not a git repository ...
cd ../..
git submodule update --init --recursive
# Submodule path 'libs/shared': checked out 'a1b2c3d'
Now the submodule has its git data and behaves.
This one wears a different mask. You'll see a message like:
fatal: detected dubious ownership in repository at '/repo'
To add an exception for this directory, call:
git config --global --add safe.directory /repo
The .git folder is right there, but git refuses to touch it because the directory is owned by a different user than the one running git. It's a security feature, added to stop a repo you don't own from executing config hooks as you. You hit it constantly in Docker containers, on mounted volumes, and after copying repos around with sudo.
If you trust the repo, add the exception git already suggested:
git config --global --add safe.directory /repo
Do not reach for safe.directory * to make it shut up everywhere. That switches off the protection wholesale. Add the specific paths you trust. In a container, fixing ownership at the source is cleaner:
chown -R $(id -u):$(id -g) /repo
Two commands settle almost every case. First, confirm whether a .git exists nearby:
ls -la
Second, ask git where it thinks the repo root is:
git rev-parse --show-toplevel
# /Users/kiril/projects/my-app <- you're inside a repo
# or: fatal: not a git repository <- you're not
If --show-toplevel prints a path, you're inside a repo and the error was likely a stale terminal or a GIT_DIR issue. If it errors, you're genuinely outside one, so it's a directory or an init problem.
Run pwd and ls -la before you theorise. The overwhelming majority of these are you standing in the wrong folder, and you'll spot it in two seconds instead of two minutes. If the .git is present but git still balks, check for the dubious-ownership message and GIT_DIR before you assume anything is broken. Save the re-clone for when the .git is truly gone, and never blanket-whitelist safe.directory * just to silence a warning that exists to protect you. For the wider set of git failures, keep our Git troubleshooting guide within reach.
Get the latest tutorials, guides, and insights on AI, DevOps, Cloud, and Infrastructure delivered directly to your inbox.
The metrics stack you self-host is free software plus a real ops bill. Datadog hands you everything and mails you the invoice. Here's how we pick.
Static keys leak and live forever. Short-lived credentials from STS and Vault expire on their own — here's the token-exchange machinery and the TTL math that make it work.
Explore more articles in this category
The IaC landscape fractured after the Terraform license change. This is the map to what each tool is actually best at, and how to choose without regret.
Terragrunt keeps large Terraform setups DRY and orchestrated, but small teams often pay its learning curve for little return.
A practical comparison of Kubernetes-native continuous reconciliation against the classic CLI-driven, state-file IaC model for platform teams.
Evergreen posts worth revisiting.