Git's "fatal: this operation must be run in a work tree" appears when a working-tree command runs in a bare repo or inside .git. Fix it by leaving .git, cloning the repo, or correcting core.bare.
Git repositories come in two forms: normal (non-bare) repositories and bare repositories. A normal repository has both a working tree (the directory where your actual files live and can be edited) and a `.git` directory containing all the version-control metadata, history, and configuration. A bare repository, created with `git init --bare` or `git clone --bare`, contains only the contents that would normally live inside `.git`, with no working tree attached. Bare repositories are designed for sharing code on servers (like GitHub or your own Git server) where no one directly edits files. When you push to a remote, you are typically pushing to a bare repository. Commands like `git status`, `git checkout`, `git add`, and `git diff` need a working tree to compare against or modify files on disk. If no working tree is available, Git aborts with `fatal: this operation must be run in a work tree`. This commonly happens when you accidentally `cd` into the `.git` directory, when you are inside a bare repository, or when a repository's configuration incorrectly reports itself as bare.
The most common cause is accidentally navigating into the .git folder. Check your current location:
pwdIf the path ends in .git, move back up to the repository root:
cd ..
git statusGit commands should now work normally.
Ask Git directly whether it considers the current repository bare:
git rev-parse --is-bare-repositoryIf this returns true, you are in a bare repository. You can also inspect the directory:
ls -laA bare repository contains entries like objects/, refs/, HEAD, and config directly in the current directory, with no .git subdirectory and no source files.
If you need a working copy of a bare repository, clone it. This is the simplest and safest way to get a normal repository with a working tree:
# If the bare repo is local
git clone /path/to/bare-repo.git my-working-copy
cd my-working-copy
# If it's a remote bare repo
git clone git@server:/path/to/repo.git my-working-copy
cd my-working-copyThe clone leaves the original bare repository untouched and gives you a normal checkout where all Git commands work.
If a repository that *does* contain source files suddenly shows this error, check whether core.bare was incorrectly set to true:
git config --get core.bareIf it returns true but this is supposed to be a normal working repository, reset it:
git config core.bare falseYou can also open .git/config and change the bare = true line under [core] to bare = false. Run git status afterward to confirm the working tree is recognized again.
To run a single command against a bare repository while pointing at an external working tree, use the --work-tree option (place global options before the subcommand):
# Run status using a separate work tree
git --work-tree=/path/to/files status
# Checkout files into a specific directory
git --work-tree=/var/www/html checkout <branch>The equivalent environment-variable form for a single command:
GIT_WORK_TREE=/path/to/files git statusFor a server that should always associate a work tree with a repository, you can set core.worktree. Note that core.worktree is ignored while core.bare is true, so for a true push-to-deploy setup it is cleaner to keep the repo bare and pass GIT_WORK_TREE from a hook rather than mixing settings.
The standard push-to-deploy pattern uses a bare repository plus a post-receive hook:
#!/bin/bash
# .git/hooks/post-receive in the bare repo
git --work-tree=/var/www/mysite --git-dir=. checkout -fHere checkout -f overwrites the deploy directory with the pushed commit, which is the intended behavior for an automated deploy target that no one edits by hand. Do not point such a hook at a directory containing manual edits, since they would be discarded.
GIT_DIR and GIT_WORK_TREE override Git's automatic repository detection and can trigger this error if left set from a previous command or script. Check them:
echo "$GIT_DIR"
echo "$GIT_WORK_TREE"If they are set and shouldn't be, unset them:
unset GIT_DIR
unset GIT_WORK_TREEOr clear them for just one command:
env -u GIT_DIR -u GIT_WORK_TREE git statusIf you genuinely need a working copy from a bare repository, clone it (as in step 3) rather than restructuring the original directory. Cloning is safe, preserves the original bare repo as a backup, and checks out the correct default branch automatically:
git clone /path/to/bare-repo.git /path/to/working-repo
cd /path/to/working-repoOnly if you must convert a bare repo *in place* (for example, it is the single source of truth and disk space is tight) should you flip its configuration. Do this on a copy you can afford to lose, and detect the branch name dynamically instead of assuming master:
# Work on a COPY of the bare repo, not your only copy
cd /path/to/bare-repo.git
# Turn off bare mode and point the work tree at the current directory
git config core.bare false
git config core.worktree .
# Check out the actual default branch (do not hardcode master/main)
default_branch=$(git symbolic-ref --short HEAD)
git checkout "$default_branch"This leaves the Git internals in the current directory rather than in a .git subfolder, which is unusual but valid. Because this in-place conversion is easy to get into a half-broken state, the clone approach above is strongly recommended unless you have a specific reason not to use it.
### Why bare repositories exist
Bare repositories are intentionally created without a working tree for these cases:
- Central/shared repositories: When several developers push to one repository (GitHub, GitLab, or a company server), keeping it bare avoids conflicts between pushed history and any local edits.
- Backups and mirrors: A git clone --mirror or --bare is the natural format for a backup that you never edit directly.
- Push-to-deploy: A bare repo receives pushes and a hook checks the code out into a separate deploy directory.
### git worktree is a different feature
Despite the similar wording, Git's git worktree command is unrelated to the bare-repository error. It lets one repository have multiple linked working directories checked out to different branches at once:
# Add an additional linked working tree
git worktree add ../feature-branch feature-branch
# List and clean up
git worktree list
git worktree remove ../feature-branchThis is useful when you want to build or test one branch without disturbing your main checkout.
### CI/CD and container considerations
- Ensure the checkout uses a normal git clone (not --bare or --mirror) when later steps run git status, git add, or git checkout.
- Confirm the checkout step actually completed and that the working directory is the repository root, not a subdirectory or the .git folder.
- Avoid exporting GIT_DIR / GIT_WORK_TREE globally in pipeline environments unless every step expects them.
### Shell prompt integrations
Tools like oh-my-zsh, spaceship-prompt, and starship run git to display repo status. Inside a .git directory or a bare repo they may surface this error — that is expected, since there is no working tree to report on.
### Setting up a Git server
For a server-side repository, create it bare so clients can push to it without working-tree conflicts:
# On the server
git init --bare /srv/git/myproject.git
# Clients clone it normally
git clone user@server:/srv/git/myproject.gitwarning: refname 'feature' is ambiguous
How to fix 'warning: refname is ambiguous' in Git
error: The following untracked working tree files would be overwritten by checkout
Untracked working tree files would be overwritten by checkout
error: remote origin already exists
How to fix 'fatal: remote origin already exists' in Git
pathspec did not match any file(s) known to git
How to fix 'pathspec did not match any file(s) known to git' in Git
ssh: Could not resolve hostname github.com: Name or service not known
How to fix 'ssh: Could not resolve hostname github.com: Name or service not known' in Git