What this error means
Git is telling you the command you ran requires a working tree (checked-out files) but your current context is a bare repository or you pointed Git at only a .git directory. Commands like status, add, checkout, restore, stash, and merge need a work tree.
Common causes:
- Running inside a bare repo (core.bare=true)
- Running in .git or using GIT_DIR without GIT_WORK_TREE
- CI/hook contexts that only have the object database (no checkout)
- Using git --git-dir=... alone
Quick signal checks:
- git rev-parse --is-bare-repository → true means no work tree
- git rev-parse --is-inside-work-tree → true means you have a work tree
Quickstart: Fast fixes by situation
- You want a working copy from a bare repo: clone it
- git clone /path/to/bare.git /path/to/work
- You pointed at .git manually: also set a work tree
- git --git-dir=/repo/.git --work-tree=/repo status
- In CI or hooks: set both directory and work tree, or run with -C
- git -C /checkout/path status
- GIT_DIR=/srv/app.git GIT_WORK_TREE=/srv/app git checkout -f
- You’re accidentally in .git: cd to the repository root
- cd ..; git status
- GIT_DIR leaked into your shell: unset it
- unset GIT_DIR
Minimal working example (reproduce and fix)
# Reproduce the error
mkdir -p /tmp/demo && cd /tmp/demo
git init --bare bare.git
# This has no working tree
git --git-dir=/tmp/demo/bare.git status # => fatal: This operation must be run in a work tree
# Fix: obtain a working tree by cloning
git clone /tmp/demo/bare.git /tmp/demo/wt
cd /tmp/demo/wt && git status # Works (shows empty repo)
# Alternative: point Git at a work tree explicitly
git --git-dir=/tmp/demo/bare.git --work-tree=/tmp/demo/wt status # Works
Diagnose before you fix
- Identify repo type
- git rev-parse --is-bare-repository
- git rev-parse --is-inside-work-tree
- Find the active .git
- git rev-parse --git-dir
- If you used env vars, check them: env | grep '^GIT_'
- Discover the work tree root (if any)
- git rev-parse --show-toplevel
Solutions by scenario
- Local development (you need files on disk)
- If you have a bare repo: git clone /path/to/bare.git workdir
- If you ran a command with --git-dir only: add --work-tree
- git --git-dir=/path/proj/.git --work-tree=/path/proj status
- If you’re inside .git: cd .. then rerun your command
- CI/CD pipelines
- Prefer -C to run inside the checkout
- git -C "$WORKSPACE" fetch --tags --prune
- git -C "$WORKSPACE" status
- If your job only fetches objects (no checkout), either:
- Do a checkout: git -C "$WORKSPACE" checkout -f "$GIT_COMMIT"
- Or wire up both variables: GIT_DIR and GIT_WORK_TREE
- GIT_DIR=$PWD/repo.git GIT_WORK_TREE=$PWD/src git checkout -f "$GIT_COMMIT"
- Avoid using commands that require a work tree until one exists
- Server-side bare repos (deploy from hooks)
- post-receive example deploying to /srv/app
#!/usr/bin/env bash
set -euo pipefail
GIT_DIR=/srv/app.git
GIT_WORK_TREE=/srv/app
export GIT_DIR GIT_WORK_TREE
# Check out the latest to the deployment directory
git checkout -f
- Ensure /srv/app exists and the service user has permissions
- Don’t run git add/status in hooks without a work tree
- Multiple working directories for one repo
- Use git worktree from a non-bare repo to attach more work trees
cd /path/repo
git worktree add ../repo-feature feature-branch
- If you only have a bare repo, first create a non-bare checkout (clone), then run git worktree from there
- Misconfigured repository
- If core.bare=true but you really want a standard repo with a work tree:
- Caution: changing this toggles repo type
# Only do this if you understand the implications
cd /path/repo
git config core.bare false
# You may also need to set a work tree
git config core.worktree /path/repo
- Safer: create a fresh non-bare clone instead of flipping core.bare
Which commands require a work tree?
- Require a work tree: status, add, checkout/switch/restore, stash, merge, rebase, clean
- Do not require a work tree (ok in bare): fetch, push, ls-remote, show-ref, rev-parse, cat-file, update-ref, gc
Common pitfalls
- GIT_DIR leaking in shells or CI steps: unset GIT_DIR, or always pair it with GIT_WORK_TREE
- Running inside .git: most porcelain commands will fail; move to repo root
- Converting a production bare repo to non-bare: risky for shared servers; prefer cloning elsewhere
- Hooks assume a bare context: don’t use commands like git add in pre-receive/update/post-receive unless you set a work tree
- Using git worktree on a bare repo: run it from a non-bare checkout instead
Performance notes
- Prefer git -C <path> to repeated cd; it’s efficient and keeps env clean
- For CI, shallow clones reduce checkout cost without affecting the fix:
- git clone --depth=1 --no-tags <url> workdir
- git worktree is more space- and network-efficient than multiple clones when you need many checkouts of the same repo
- Avoid unnecessary status/clean scans on huge repos by using sparse-checkout when possible
FAQ
Q: Why do I get this error in post-receive? A: Server-side repos are typically bare. Either deploy by setting GIT_WORK_TREE or use a separate cloned working copy.
Q: How do I find my current work tree? A: Run git rev-parse --show-toplevel. If it fails, you’re not in a work tree.
Q: Can I make a bare repo behave like non-bare with core.worktree? A: Not while core.bare=true. You’d need to set core.bare=false (not recommended on shared servers). Prefer clone + worktree.
Q: I only set GIT_DIR; is that wrong? A: It’s incomplete for commands that need files. Set GIT_WORK_TREE too, or run in a checked-out directory with -C.