# git: Use the real gitdir for checkpoints \(\#51563\) · gitcafe/zed

[View on GitCafe](https://git.cafe/gitcafe/zed/commit/1bca0c5a91014c98c1d24c0172edf83474d6cf77)

Repository: [gitcafe/zed](https://git.cafe/gitcafe/zed)

Visibility: public

Requested revision: 1bca0c5a91014c98c1d24c0172edf83474d6cf77

Requested commit: 1bca0c5a91014c98c1d24c0172edf83474d6cf77

Commit: 1bca0c5a91014c98c1d24c0172edf83474d6cf77

Tree: 6dd4ace7ed9b0b2f876bf08d7759bb2e59813bfe

Author: Stefan Junker

Committer: GitHub

## Message

```
git: Use the real gitdir for checkpoints (#51563)

## Summary

Zed's git checkpoint code was assuming that repository-local metadata
always lives under `<working-directory>/.git/...`.

That assumption breaks for repositories where `.git` is a file instead
of a directory, most notably:

- git submodules
- git worktrees

In those layouts, `.git` contains a `gitdir: ...` pointer to the real
git directory. When checkpoint creation or restore tries to build paths
like `.git/index-<uuid>.tmp` or `.git/info/exclude`, those path
operations fail with `Not a directory (os error 20)`.

In practice, that shows up as checkpoint failures in ACP threads for
worktrees and submodules.

## Root Cause

`GitBinary` tracked the repository working directory, but it did not
track the resolved git directory.

As a result, checkpoint-related helpers derived temporary index and
exclude paths from the working tree:

- temp index path creation
- copying the default index into the temp index
- exclude override handling

That works for a plain repository where `.git` is a directory, but not
when `.git` is a pointer file.

## Changes

- Thread the resolved git directory from `RealGitRepository::path()`
into `GitBinary`.
- Add a dedicated `git_directory` field to `GitBinary`.
- Use `git_directory` instead of `<working-directory>/.git` for:
  - temp index file paths
  - copying the default `index`
  - `info/exclude` override paths
- Keep the working directory unchanged for command execution; only
metadata path resolution changes.
- Add a regression test that verifies temp index files are created under
the real gitdir, not under `<working-directory>/.git`.

## Why this approach

The minimal correct fix is to distinguish between:

- the working directory used to run git commands, and
- the actual git directory used to store repository metadata

Git itself already makes that distinction, and
`git2::Repository::path()` gives us the resolved gitdir directly.
Reusing that value keeps the fix small and avoids special-casing
submodules or worktrees elsewhere.

## User-visible impact

Before this change, checkpoint operations could fail in repositories
where `.git` is not a directory, producing errors like:

    Not a directory (os error 20)

After this change, checkpoint-related git metadata is read and written
from the real gitdir, so ACP checkpoints work in submodules and
worktrees the same way they do in regular repositories.

## Testing

- `cargo fmt -p git`
- `cargo test -p git --lib`
- `cargo clippy -p git --lib --tests -- -D warnings`

Added regression coverage:

- `test_path_for_index_id_uses_real_git_directory`

If you want, I can also compress this into a more GitHub-PR-native
version with sections like `## Problem`, `## Fix`, and `## Validation`.

Release Notes
- Fixed `.git` handling when `.git` is a file instead of directory, e.g.
when using worktrees or submodules.
```

## Parents

- [d934ba6cea45f46df2eda92ef6a2d8db1e9778c5](https://git.cafe/gitcafe/zed/commit/d934ba6cea45f46df2eda92ef6a2d8db1e9778c5?format=markdown)

[Source at this commit](https://git.cafe/gitcafe/zed/tree/1bca0c5a91014c98c1d24c0172edf83474d6cf77?format=markdown)
