Skip to content

Latest commit

 

History

11 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

timefs

Mount a Git repository as a filesystem and browse its entire history like normal directories.

CI crates.io docs.rs License MSRV Platform Downloads

cd into a commit. cat a file as it existed then. diff -r two commits with plain Unix tools.


$ timefs mount ~/code/linux /mnt/linux &

$ cat /mnt/linux/at/v6.1/Makefile | head -3
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 1

$ cd /mnt/linux/at/HEAD~40
$ cat kernel/sched/core.c | wc -l
11834

# A commit diff, using nothing but diff:
$ diff -r /mnt/linux/at/HEAD~1 /mnt/linux/at/HEAD

Because every revision is just a directory, the entire Unix toolbox — grep, diff, find, rsync, your editor, ripgrep — works across Git history with zero new syntax to learn.

Why

Git history is trapped behind Git's own porcelain. Want the tree at HEAD~40? git checkout mutates your working copy, or you memorize git show <rev>:<path> one file at a time. timefs makes history a first-class filesystem: read-only, instant, and browsable with tools you already have.

  • Time-travel by cdat/HEAD~40/, at/v1.0/, at/main/, at/<sha>/.
  • Diff commits with diffdiff -r at/A at/B is a real commit diff.
  • Grep across a point in timerg TODO /mnt/repo/at/v2.0.
  • Never touches your repo — mounted strictly read-only; your working tree and object store are untouched.
  • Fast on huge repos — content-addressed caching, lazy materialization, nothing walked until you cd into it.

Install

# From crates.io
cargo install timefs

# From source
git clone https://github.com/itsbryanman/timefs
cd timefs
cargo install --path .

Requirements

  • Linux with FUSE 3 (sudo apt install fuse3 / sudo dnf install fuse3).
  • Rust 1.75+ to build from source.
  • macOS support is planned (requires macFUSE); see Limitations.

Usage

timefs mount <repo> <mountpoint> [options]
timefs unmount <mountpoint>

Common options:

Flag Effect
-f, --foreground Run in the foreground (default while stabilizing; great for debugging).
--allow-other Let other users access the mount (needs user_allow_other in /etc/fuse.conf).
--submodules <mode> placeholder (default) or recurse.
--lfs Serve real content for LFS objects present locally; otherwise show the pointer.
--ref-snapshot Freeze branch/tag resolution at mount time instead of tracking moving refs.
--cache-size <MB> Cap the in-memory object cache.
--uid <id> / --gid <id> Override owner of every node.
-v, -vv Increase log verbosity.

Filesystem layout

/mnt/repo/
├── now/                 # HEAD's tree — the repo as it is right now
├── at/                  # resolve ANY revision on access
│   ├── HEAD~40/
│   ├── v1.2.0/
│   ├── main/
│   └── a1b2c3d.../
├── commits/<full-sha>/  # hash-addressed snapshots
├── refs/                # browsable, enumerable
│   ├── heads/
│   ├── tags/
│   └── remotes/
└── history/<path>/      # every version of one file across commits

refs/ is the browsable index you can ls and tab-complete. at/, commits/, and history/ are resolvers: they accept an enormous set of names on access without pre-listing them, which is what lets cd at/HEAD~40 just work.

How it works

timefs is a read-only FUSE daemon in Rust. It reads Git objects directly through gix (no subprocess per read), maps Git trees to directories and blobs to files, and answers kernel filesystem requests on demand:

  • A lookup for HEAD~40 is fed straight to the revision parser.
  • A read streams blob bytes — large files stream rather than buffering.
  • Because a commit is an immutable snapshot, content-addressed nodes are cached with very long kernel TTLs, while moving refs (HEAD, branches) use short ones.

See docs/ARCHITECTURE.md and docs/FUSE_MAPPING.md for the full design.

Docs

Limitations

Honest and current:

  • Read-only by design. Every mutation returns EROFS. This is not a writable overlay and never will be.
  • Submodules default to a placeholder directory containing the pinned SHA; full recursion is opt-in and best-effort.
  • Git LFS shows the pointer file unless the object is present locally and --lfs is set. timefs never fetches over the network during a read.
  • Shallow clones can't show revisions they don't contain; those resolve to ENOENT with an explanatory log line.
  • Empty directories never appear — Git cannot represent them.
  • macOS is planned, not shipped; it depends on macFUSE.

See docs/LIMITATIONS.md for the complete list.

Development

cargo build
cargo test                     # unit + integration (needs fuse3 installed)
cargo test --test differential # verifies output byte-for-byte against `git`

The correctness oracle is Git itself: differential tests assert that cat $MNT/at/<rev>/<path> equals git show <rev>:<path> and that directory listings match git ls-tree. Contributions welcome — please read docs/ARCHITECTURE.md first.

License

Dual-licensed under either of

at your option.

About

a read-only FUSE filesystem that mounts a Git repository and lets you browse its history like normal directories.

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages