Skip to content

Work in memory

The same API drives a real checkout or a repository that exists only in RAM. The in-memory backend uses go-git's memfs and memory.Storage — nothing touches disk.

gitRepo, worktree, err := r.OpenInMemory(url, "main")

Why you'd want it

  • No cleanup. There are no temporary directories to create, track, or delete — and none left behind when a process dies mid-run.
  • Speed. All I/O stays in memory, which is markedly faster for small and medium repositories.
  • Security. Nothing sensitive is written to shared disk. That matters on CI runners and multi-tenant hosts, where a temp directory may outlive your job or be readable by others.

Typical uses: temporary analysis, code generation, and CI pipelines where filesystem artefacts are undesirable.

Choosing a backend

// explicitly in memory
gitRepo, worktree, err := r.OpenInMemory(url, "main")

// explicitly on disk
gitRepo, worktree, err := r.OpenLocal(path, "main")

// caller decides by value
gitRepo, worktree, err := r.Open(repo.InMemoryRepo, url, "main",
    repo.WithShallowClone(1),
    repo.WithSingleBranch("main"),
)

Open takes a RepoType so a program can select the backend from configuration or a flag without branching. SourceIs reports which one is in use.

Clone options

Option Effect
WithShallowClone(depth int) Fetch only the last depth commits
WithSingleBranch(branch string) Limit the fetch to one branch
WithNoTags() Skip fetching tags
WithRecurseSubmodules() Initialise submodules after cloning

These matter more in memory than on disk, because everything you fetch stays resident.

Mind the memory ceiling

A large repository — especially one with heavy binary history — can consume all available RAM. Past a few hundred megabytes, prefer a local shallow clone (WithShallowClone(1)) over an in-memory one.

In-memory repositories make excellent test fixtures

Because it is a real repository, code under test runs against real git behaviour — no mock to drift from reality — while staying hermetic and fast:

r, _ := repo.NewRepo(repo.Settings{FS: afero.NewMemMapFs()})
_, _, err := r.OpenInMemory(url, "main")

fs, _ := r.WorkFS()
_ = afero.WriteFile(fs, "main.go", []byte("package main"), 0o644)
_ = r.AddAll()
_, _ = r.Commit("initial", nil)

Combined with the worktree filesystem, an afero-based "commit-on-save" routine runs verbatim over an in-memory repository — the same code path as production. See testing for when to prefer this over a mock.