KhueApps
Home/DevOps/Fix Git error: fatal: This operation must be run in a work tree

Fix Git error: fatal: This operation must be run in a work tree

Last updated: October 07, 2025

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

  1. Identify repo type
  • git rev-parse --is-bare-repository
  • git rev-parse --is-inside-work-tree
  1. Find the active .git
  • git rev-parse --git-dir
  • If you used env vars, check them: env | grep '^GIT_'
  1. Discover the work tree root (if any)
  • git rev-parse --show-toplevel

Solutions by scenario

  1. 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
  1. 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
  1. 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
  1. 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
  1. 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.

Series: Git

DevOps