#3930·lapce

Source control lists the git directory's own files as changes when the git dir is outside the work tree

Author: DrPepperBiancoCreated Aug 20, 2026Updated Aug 20, 2026
LabelsC-bug

Lapce Version

0.4.6, built from master (c9e4c339)

System information

Windows 10 Enterprise LTSC 1809 (where it was observed in the panel); also confirmed against libgit2 on Windows 11 Pro (10.0.26200)

Describe the bug

When a repository keeps its git directory outside the work tree — the layout git init --separate-git-dir produces, where .git is a file containing gitdir: <path> — the source control panel lists the contents of that git directory as unversioned changes: config, HEAD, index, COMMIT_EDITMSG, object files, and any unrelated files that happen to sit next to it.

git status on the same repository is clean and reports only the real modifications. Only Lapce shows the extra entries.

Reproduction

bash
mkdir -p parent/work parent/gitdirs
cd parent/work
git init --separate-git-dir ../gitdirs/test.git
echo hello > file.txt && git add . && git commit -m init

Open parent/work in Lapce. The source control panel lists test.git/config, test.git/HEAD and so on, none of which are part of the repository.

Additional information

The cause is a difference between git and libgit2 in how the work tree is derived:

  • git derives the work tree from the location of the .git file
  • libgit2 reads core.worktree from the config and, when that is absent, falls back to the parent directory of the git directory

git init --separate-git-dir does not write core.worktree, so this is a state git itself creates and treats as complete. The fallback directory usually holds unrelated files — including the git directory itself — and that is what ends up in the panel.

Lapce reaches libgit2 through Repository::discover in lapce-proxy/src/dispatch.rs, without setting a work tree of its own.

The numbers below come from a small test program using the same binding Lapce depends on (git2 0.20.2, libgit2 1.9.0), run against the layout from the reproduction steps above:

Repository::discover("parent/work")
  workdir : parent/gitdirs/    <- parent of the git dir, not the work tree
  statuses: 28                 <- test.git/config, test.git/HEAD, objects, ...

For comparison, git -C parent/work rev-parse --show-toplevel reports parent/work and git status is clean — the repository has no modifications at this point at all, so every one of those 28 entries is spurious.

Setting core.worktree manually works around it, but that means writing to the config of a repository the editor only reads from — and repositories created with --separate-git-dir will keep showing up without it.

I have a fix ready and would be happy to open a PR: correcting the work tree on the repository handle after Repository::discover (nothing written to the config) resolves it, and leaves repositories whose work tree is already correct untouched.

This text has been written with the help of AI.