Configuring safe.directory for shared checkouts Jump to heading

Since 2022, Git refuses to operate in a repository owned by a different user, failing with fatal: detected dubious ownership in repository. The check exists because a repository’s configuration can run commands — hooks, core.fsmonitor, core.sshCommand and others — and a repository owned by someone else could make your Git run their commands as you. The error appears most often in CI containers where the checkout is owned by one user and Git runs as another, on build servers with shared checkouts, and on mounted drives with unusual ownership. The common fix found online — safe.directory '*' — switches the protection off entirely. This page explains the check, fixes ownership where possible, adds narrow exceptions where not, and handles CI correctly, within Git configuration management at scale.

When to use this approach Jump to heading

  • Git fails with “detected dubious ownership in repository”.
  • CI jobs run Git in containers as a different user from the checkout’s owner.
  • Several users or services share one checkout on a server.
  • Someone has added safe.directory = * and you want to tighten it.

Step 1 — Understand what is being checked Jump to heading

Git compares the owner of the repository directory (and .git) with the current user. If they differ, and the directory is not listed in safe.directory, Git refuses to read the repository’s configuration.

stat -c '%U %n' . .git
id -un
git status
# fatal: detected dubious ownership in repository at '/srv/build/app'
# To add an exception for this directory, call:
#     git config --global --add safe.directory /srv/build/app
Why Git refuses a repository owned by someone elseAnother user owns a repository and sets a configuration option that runs a command. When you run Git there, Git would read that configuration and run the command as you. The ownership check stops Git before it reads the configuration, unless you have listed the directory as safe.other userrepositoryyou (git)sets core.fsmonitor = evil.shgit statusowner ≠ you → refusewithout the check, the command would run with your permissions

Step 2 — Prefer fixing ownership Jump to heading

The cleanest fix is to make the repository owned by the user who runs Git. That keeps the protection intact.

sudo chown -R builder:builder /srv/build/app
# In Dockerfiles, create the checkout as the runtime user
# USER builder
# RUN git clone https://git.example.com/org/app.git /home/builder/app

Step 3 — Add a narrow exception when ownership must differ Jump to heading

When a directory must be owned by someone else — a checkout mounted into a container, a deploy directory owned by a service account — list that exact path.

git config --global --add safe.directory /srv/build/app
git config --global --get-all safe.directory

safe.directory is only honoured in system, global and command-line configuration, never in a repository’s own configuration — otherwise the repository could declare itself safe.

⚠️ SAFETY WARNING: safe.directory = * disables the check for every repository. On a machine where other users can create repositories you might enter — shared servers, multi-tenant runners — that lets their repository configuration run commands as you. Use specific paths instead.

Step 4 — Handle CI containers Jump to heading

In container-based CI, the workspace is often mounted from the host with a different owner from the container’s user. Add the workspace path at the start of the job, or run the container as the workspace owner.

jobs:
  build:
    runs-on: ubuntu-latest
    container: { image: "node:20" }
    steps:
      - uses: actions/checkout@v4
      - run: git config --global --add safe.directory "$GITHUB_WORKSPACE"
      - run: git describe --tags

Ephemeral containers are single-tenant, so the risk the check guards against is low there; a path-specific entry still avoids training people to reach for the wildcard.

Dubious ownership error — what is the right fix?On your own machine with a mismatched owner, fix the ownership. In an ephemeral CI container, add the workspace path as safe at the start of the job. On a shared server where several users run Git in one checkout, give the checkout a dedicated owner and run Git as that user, or list the exact path for the accounts that need it.Where does the error happen?own machineFix ownershipchownephemeral CI containerList workspace pathjob-scoped configshared serverDedicated owneror exact paththe wildcard is never the answer on a shared machine

Step 5 — Handle shared checkouts on servers Jump to heading

When several people or services run Git in one checkout, give the checkout a dedicated owner and have everyone act through it, rather than each user listing it as safe.

sudo -u deploy git -C /srv/app pull --ff-only
# Or, if individual accounts must run Git there, list the exact path in each account's global config
sudo -u alice git config --global --add safe.directory /srv/app

Step 6 — Mounted drives and network shares Jump to heading

Filesystems such as FAT, exFAT or some network shares report ownership that does not match any local user, triggering the check on every repository there. List the specific repository paths, or the mount’s subdirectories with a trailing /* where your Git version supports it.

git config --global --add safe.directory '/mnt/usb/projects/*'      # repositories directly under projects

The trailing /* matches repositories under that directory, which is safer than a global wildcard but still broad; keep it to drives only you can write.

Step 7 — Audit for wildcards Jump to heading

Check team machines and runner images for the global wildcard and replace it with specific entries.

for scope in --system --global; do
  git config $scope --get-all safe.directory 2>/dev/null | grep -qx '\*' && echo "wildcard safe.directory in $scope config"
done

Fleet-wide checks of this kind are covered in auditing local Git configuration drift.

Ways to resolve the ownership checkFixing ownership keeps full protection. Listing an exact path trusts one directory. A path with a trailing star trusts every repository under it. A bare star trusts every repository on the machine. Protection decreases from left to right in that order.Protection keptUse whenchown to current userfullyou can change ownershipexact pathall other dirsmounted workspacepath/*outside that treeyour own removable drive* (wildcard)noneavoidchoose the narrowest option that works

Validation checklist Jump to heading

Frequently Asked Questions Jump to heading

Why did this start failing after a Git upgrade? Jump to heading

The ownership check was added in Git 2.35.2 and related releases as a security fix. Repositories that worked before fail when their owner differs from the user running Git.

Does the check apply to reading repositories with git -C? Jump to heading

Yes. Any Git command that opens the repository performs the check, whatever the working directory.

Is running as root an exception? Jump to heading

Root running Git in a repository owned by another user triggers the check too, with a special case for repositories owned by the user who ran sudo. Avoid running Git as root in other users’ repositories.