Skip to main content

git-localhost-store

Protect your local git repositories from accidental deletion.

Problem

A stray rm -rf can destroy weeks of work if you haven't pushed to a remote. Local git repositories are fragile and ephemeral.

Solution

Every repository's objects live in a central store, indexed by working directory path. Delete the entire working directory and the commits are still there, recoverable by recreating the directory.

How It Works

When you git init or git clone (or git add in a fresh repo), hooks run git-localhost-store, which:

  1. Moves .git/ into a per-repo store under ~/.local/state/git-localhost-store/repos/<encoded-path>/.
  2. Replaces .git with a symbolic link to that store.

After the swap, .git is a symlink rather than a directory. Git follows it transparently. Naive readers (lazy.nvim, ad-hoc shell scripts, IDE plugins) that do open(repo + "/.git/HEAD") work unchanged, because the symlink resolves through the filesystem.

Path encoding

claude-code-slug names the store: every character that is not ASCII alphanumeric becomes exactly one -.

/home/you/projects/myrepo → -home-you-projects-myrepo

It is a dependency rather than a copy because the name has to survive the tool that wrote it: a store is named by this function, so a second implementation that disagrees anywhere doesn't fail, it strands a repository in a directory nobody looks in.

Installation

uv tool install git-localhost-store
git-localhost-store-install

The second command is the one that touches your system, and it is idempotent -- re-run it after upgrading, or after moving the venv. It creates the store root, writes the hook template, points init.templateDir at it, and aims one stable path (~/.local/share/git-localhost-store/bin/git-localhost-store) at the freshly installed relocator.

git allows exactly one init.templateDir. If yours is already set to something else, the installer says so and changes nothing; merge the hooks by hand.

Existing repositories keep their old hooks and are unaffected -- hooks are copied at init time, not read from the template afterwards. To convert one, run git-localhost-store in it.

Recovery

After rm -rf of a working directory:

mkdir ~/projects/myrepo && cd ~/projects/myrepo
git init
git-localhost-store   # adopts the surviving store, restores tracked files

Re-cloning instead: if the workdir had a remote, a plain git clone into the original path works directly -- the hook force-syncs remote-tracking refs and fast-forwards the local branch when it can. It refuses only when the store holds local commits that are not a fast-forward of the fresh clone. That refusal wants a human, not another rm -rf.

Commands

git-localhost-store [HOOK-NAME]

Convert the repository containing the current directory, or recover it if its store already exists. Idempotent, and a no-op when .git is already a symlink, or is a gitfile (worktree or submodule). Any other shape is an error: it asserts and exits non-zero rather than guess.

Hooks pass their own name as the argument; you don't.

git-localhost-store-install

See Installation.

Layout

~/.local/share/git-localhost-store/    # written by the installer
├── bin/git-localhost-store            # -> the installed console script
└── template-repo/hooks/               # git init template
    ├── shared                         # the hook body
    └── post-{index-change,commit,checkout}  # -> shared

~/.local/state/git-localhost-store/    # your repositories -- back this up
└── repos/<encoded-path>/              # one gitdir per workdir

Limitations

  • Protects commits and staged changes, not unstaged modifications.
  • Recovery requires recreating the directory at the exact original path.
  • Stores in the state directory can still be deleted by hand.
  • Not a substitute for a remote.
  • One worktree per store. git worktree add from the central gitdir still works; it is just not automated here.

Design Principles

  • Automatic -- works without user intervention.
  • Transparent to naive readers -- .git/HEAD resolves through the symlink as an ordinary file.
  • Deterministic -- the recovery path follows from the workdir path.
  • Explicit errors -- failures are visible. No || true.
  • Idempotent -- hooks and git-localhost-store are safe to re-run.

Release files for git-localhost-store 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for git-localhost-store 0.1.0
File Size Uploaded
git_localhost_store-0.1.0.tar.gz 57.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for git-localhost-store 0.1.0
File Interpreter ABI Platform
git_localhost_store-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 73.3 kB

Release files / git_localhost_store-0.1.0.tar.gz

Download URL git_localhost_store-0.1.0.tar.gz
Size 57.8 kB
Tags Source
SHA-256 checksum
How to use checksums
0e84ce4ddc6b5695a9b1d316ea39a0c0cba36efef6b3bdddbf099240340aa7a0
BLAKE2b-256 checksum
How to use checksums
c6d26f778249deb8a47cb2c6b1b2074717c8a33dc8dfd662961a5ec883c78746
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / git_localhost_store-0.1.0-py3-none-any.whl

Download URL git_localhost_store-0.1.0-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
341e2b5654e688fb2bdf9477d3df0518605e294b1e66b56c3203af29c137d6ad
BLAKE2b-256 checksum
How to use checksums
2243ec8b51929b7576e4e449e0a2d49088538675a73e88497c7f1e2988c02945
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.12.3 {"installer":{"name":"uv","version":"0.12.3","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page