---
title: Git storage compaction
---

# Git storage compaction

## If your disk is filling up, start here

Two different things grow Omniscio's footprint on disk, and they take different fixes:

- **One working copy per session.** With session isolation on (see [edit-a-project.md](edit-a-project.md)), every isolated session gets its own full checkout. On a large project that pile can reach _hundreds of gigabytes_, because each copy carries its own dependencies. To see how much it is using right now, add up the repository rows on the **Git storage** card below, or ask any Omniscio session to measure it. To get the space back: the scheduled sweep runs from the **Dev Pipeline** panel's **Setup** tab, a manual pass is `/worktree-cleanup` (see [worktree-cleanup-skill.md](worktree-cleanup-skill.md)), and copies whose work never landed go through [orphan-worktree-archive.md](orphan-worktree-archive.md).
- **Git pack growth.** Inside each repository, git quietly accumulates loose objects and extra pack files that nothing removes on its own. That is what the rest of this page is about.

A third consumer is separate from both: Omniscio's own database, covered by [database-compaction.md](database-compaction.md). For the wider "my computer feels slow" question, start at [slow-computer.md](slow-computer.md).

## What it is

**Where:** Settings → Diagnostics → **Git storage**

Git quietly accumulates junk. Every fetch, every branch, every worktree leaves loose objects and
extra pack files behind, and nothing removes them on its own. On a busy repo this grows until git
itself gets slow — every command has to scan the pile — and it can eat tens of gigabytes.

The **Git storage** card lists every git repository Omniscio knows about with its real size on
disk, then compacts the ones you pick. On a badly-bloated store this routinely reclaims several
gigabytes and makes every git operation noticeably faster.

## Where to find it

### How to use it

1. Open Settings → Diagnostics and find **Git storage**.
2. Tick the repositories you want to compact. Each row shows its size on disk, pack-file count, and
   loose-object count, so you can see which ones are actually bloated.
3. Choose one of:
   - **Compact on next restart** — nothing happens now; it runs the next time you start Omniscio.
   - **Restart & compact now** — Omniscio closes and does it immediately.
4. On the next launch the startup screen shows live progress. When it finishes, the card reports
   what it reclaimed.

A scheduled compaction shows a **Scheduled for the next restart** line with a **Cancel** button, so
a pending request is never invisible.

## How it behaves

### Why it needs a restart

A full-strength compaction rewrites the repository's object store. It cannot safely run while
anything else is using that repository — and Omniscio itself is constantly running git in the
background for its sessions, worktrees, and branch tracking.

So instead of trying to hunt down and kill those processes, Omniscio does the compaction **during
its own startup**, before it opens its window and before any session resumes. At that exact moment
it has no git activity of its own, which is the quiet window the compaction needs. Nothing gets
killed, and nothing races.

### What to expect

- **How long depends on the repository.** A small one is done in seconds; a large, long-neglected
  one can take 5 to 30 minutes. The startup screen names the repository and the step it is on, and
  because a single step can run quietly for many minutes it keeps a quieter line underneath saying
  it is still working — so a long wait never looks stalled.
- **A long compaction is never reported as a failed start.** Omniscio's "opened to a blank screen"
  check does not count the time it spends compacting, so a slow run sends no crash report and puts
  no "blank screen" card in your inbox. If the dashboard really does stay blank afterwards, that is
  still reported.
- **You can stop it at any time.** The startup screen shows a **Skip and open now** button for as
  long as the compaction runs, with a line under it explaining what the tidy-up is and that stopping
  costs nothing. Pressing it stops the work immediately and opens Omniscio — whatever had already
  finished is kept. The button comes down with the run, so it never shows up on a normal startup and
  never lingers once the compaction has ended.
- **Your sessions are safe.** They are suspended when Omniscio closes and resume automatically
  afterwards.
- **Force-quitting during it is also safe**, though Skip is the better exit. Git writes the new data
  to a temporary file and only swaps it in at the very end, so an interrupted compaction changes
  nothing.
- **It never deletes your work.** It reorganizes how git stores what it has, and a compaction you
  schedule also removes data nothing uses any more (next section) — never anything a branch, recent
  history or open worktree still uses.
- **If it stops early, the card says why** — whether you skipped it or it ran out of time — and any
  repository it never reached is listed rather than quietly dropped.

### A compaction you schedule also removes data nothing uses

Git keeps everything it ever stored, including the leftovers of branches and work nothing points at
any more. A compaction **you** schedule from the card also clears those out:

- **What it keeps:** everything any branch, recent history entry or open worktree still uses —
  including local copies of files the remote (GitHub) also holds — and anything that was in use
  during the last two weeks.
- **Two weeks unused, then gone.** A run deletes data nothing has used for two weeks, and *sets
  aside* newer unused data with its own date; a later compaction you schedule deletes it once it has
  gone unused for two weeks. Git dates unused data by the file it is packed in, and a busy
  repository's files are re-dated every day, so there the first run mostly sets data aside and frees
  little. The card's result line says how much a run set aside.
- **Nothing is removed until the new copies are fully written**, so Skip, a crash or an error
  removes nothing — the card then says why this part was skipped.
- **Only when you schedule it.** A request that arrives without your mark — a headless write of the
  list alone, or a legacy entry — never deletes anything.
- It needs about twice the repository's size free, plus a gigabyte, while it works; with less, only
  this part is skipped and the rest of the compaction still runs.

### When it refuses (and says so)

Each of these is reported in plain English, and nothing is changed:

- The folder has been moved or deleted.
- The folder is not a git repository.
- The folder is a *linked worktree* rather than a main repository — compacting it would act on the
  parent repository instead, which is not what you asked for.
- The drive does not have enough free space. A compaction writes the new consolidated data before
  deleting the old, so it temporarily needs roughly one and a half times the repository's current
  size, plus a gigabyte of margin.

### On a git older than 2.53

Git 2.43 through 2.52 cannot combine the pack files of a *partial clone* (a repository that keeps
some of its files only on the server, as Omniscio's own checkout does). On such a git the compaction
skips that one step instead of failing: it still tidies references, removes unused data when you
scheduled it, and cleans up old worktree records, and the Git storage card says "Pack files were not
combined … Update git to 2.53 or newer." Update git, then schedule the compaction again. A full
clone is unaffected on any git, and so is any git 2.53 or newer. The background maintenance skips the
same step on such a git, and the app-closed recovery script stops before it changes anything.

### Does this replace the automatic maintenance?

No — it complements it. Omniscio already repacks git storage automatically in the background, but
that automatic version deliberately backs off whenever the machine is busy. On a heavily-loaded
machine it can therefore go days without getting a turn, and the store bloats anyway. This card is
the deliberate, user-driven version for exactly that situation: when you can see the store is large
and you want it dealt with now.

One thing did change on the automatic side: a background clean-up that starts and is then stopped
because the machine got busy — so it combined nothing at all — no longer counts as the machine's
turn for that store. It gets another try shortly after instead of waiting out its full next
interval. A clean-up the machine never started changes nothing; it still backs off exactly as
before.

### What it no longer does by itself

Omniscio used to escalate this clean-up on its own when a store stayed bloated. That escalation was
**removed**: it could not change what the background clean-up actually did, so it promised more than it
delivered — and a promise like that is worse than none. Today the card above is the way to ask for a
clean-up, and the everyday background clean-up keeps running on its own schedule, as it always did.

What you DO get automatically is that an automatic request is CAPPED rather than unbounded: a request
the card did not make — a legacy entry, or one written headlessly without the user flag — runs on a
one-minute budget instead of the long one, and the splash is released at that budget plus a minute.
A big store cannot be compacted in that minute, so the run is cut there and reported on the card as
having run out of time. The long run is the one you ask for on the card.

## For agents

- Schedule headlessly by writing the setting `repackReposOnNextStartup` (an array of absolute repo
  paths) via `PATCH /settings`, then restart the app. Read the outcome from `lastGitRepackResults`,
  dated by `lastGitRepackResultsAt` (written on every run); `lastGitRepackAt` is the separate
  "actually compacted something" clock, and a run that changed nothing leaves it untouched rather
  than clearing it. A request written this way alone reads as AUTOMATIC and gets the one-minute
  pre-window budget; also set `repackOnNextStartupRequestedByUser: true` (what the card does) for the
  long budget AND the dead-data step (`src/main/services/maintenance/git-dead-object-drop.ts`). Boot
  clears both together; a skipped or finished dead-data step leaves its note in the repo's
  `lastGitRepackResults` entry (`reason`, also set on a `compacted` result).
- A pending request is **always one that was asked for**: nothing in the app queues a run on its own
  initiative, so it never queues a compaction you did not ask for. A request that arrives without the
  user mark — a legacy entry, or a headless write of the list alone — still gets the shorter budget
  above. (A list you scheduled and then carried across in a settings export, a backup or a restore
  keeps the LONG budget: it travels with its mark.) (An
  automatic escalation used to escalate the git-store maintenance tier instead; it was removed on
  review, because it could not change what the tier did.)
- On a partial clone with git older than 2.53 the fold is SKIPPED, not failed: the result is
  `compacted` with the update-git note in `reason` (`src/main/services/maintenance/geometric-fold-support.ts`
  decides, from `git --version` and `git config --list`).
- Read the per-repo stats over IPC via the `git:store-repos` channel.
- Engine: `git-store-repack.ts`. Boot
  consume: `git-repack-on-startup.ts`.
- Rules that must hold: only the promisor-safe command set is ever used (never `git gc` or a full
  `repack -a -d`, which are the wrong tools on a partial clone), and the pending request is cleared
  before any work starts so a failure can never cause a restart loop. These are invariants R0–R7 of
  the repo's own `git-store-maintenance-contract.md` — a contributor-only file that ships nowhere.
  § The full-strength compaction — most importantly: only the promisor-safe command set (never
  `git gc` or a full `repack -a -d`, which are the wrong tools on a partial clone), and the pending
  request is cleared before any work starts so a failure can never cause a restart loop.

## Related

What Omniscio's own maintenance jobs do, and when they run, is covered by [Dev Pipeline Maintenance](dev-pipeline-maintenance.md).
