Storage space
Keeping every version of everything costs disk space. Synck stores history as compactly as it safely can, but it never throws history away to save space. This page explains where the space goes and the few tools that manage it.
Why history grows
Each new version of a file is kept, and is never removed while history refers to it. That includes versions of files you have since deleted, because a deleted file is in the trash, not gone. A folder whose current files take 1 GB can therefore hold several gigabytes of history after a year of edits to large files.
Synck has no automatic retention policy: it never prunes old versions in the background. If a repository has grown too large, the options are honest ones: more disk, or a new repository for future work, with the old one kept as an archive.
How Synck saves space
Repositories created with synck init use chunked storage. Each stored
file is split into variable-size chunks of around 64 KiB, chosen by content, so
an insertion near the start of a file does not shift every boundary after it.
Each chunk is stored once, by its hash, and compressed with zstd when that
actually makes it smaller. When you save a new version of a large file that
differs only in places, most of its chunks are already stored, and only the
changed ones take new space. Appending a paragraph to a 10 MB file costs about
one chunk, not another 10 MB.
Microsoft Office files (.docx, .xlsx, .pptx) are ZIP packages, and a
small edit can shift much of a ZIP file. Synck chunks them along the package’s
internal entries, without unpacking or altering them, so that unchanged parts
of the document stay shared between versions.
None of this affects identity. A file’s hash is always the SHA-256 of its complete, original bytes. Chunking is purely a storage detail, and the original bytes are reassembled and verified on every read.
Two layouts
A repository records its layout as storage_mode in .synck/config.json:
storage_mode |
Where content lives | Good for |
|---|---|---|
CHUNKED |
Compressed chunks in .synck/object-store.sqlite3 |
Everyday work. The default for synck init |
WHOLE_FILE |
One plain file per version in .synck/objects/, named by the SHA-256 of its bytes |
Archives that should be checkable with nothing but shasum |
A whole-file repository is the simplest possible layout to inspect by hand, which makes it a natural format for exports. The cost is space: every version of a large file is stored in full. The layout never changes what a repository contains. Commit IDs, item IDs and file hashes are identical in both, and every command works with both. Inside .synck describes the files in detail.
To create a repository with whole-file storage, use synck init --storage-mode WHOLE_FILE.
Seeing what is stored
synck storage reports the content that history uses and anything that
nothing refers to:
$ synck storage
referenced_objects 4
referenced_bytes 378
unreachable_objects 0
unreachable_bytes 0
referenced covers every file version and message body that any commit refers
to, current or historical. unreachable covers content that no commit refers
to. That can only happen when a commit failed after its content had been
stored. The figures are logical sizes of file content. They do not include
compression, the database or file-system overhead, or your working files
themselves.
Removing unreferenced content
synck gc (garbage collection) deletes exactly the unreachable content:
$ synck gc
removed_objects 0
removed_bytes 0
gc never removes anything history refers to: not old versions, not files
in the trash, not the content of named versions. It only reclaims what failed
operations left behind. It runs only when you ask, so check synck storage
first to see whether there is anything to gain. A copy made with synck archive or synck repository import never contains unreachable content in the
first place.
Changing the layout
synck storage optimize converts a whole-file repository to chunked storage
in place:
$ synck storage optimize
storage optimized
It works with or without a checkout; for a repository without one, run it
inside the repository’s directory. Synck verifies the repository, stores every
object as chunks, verifies the chunks, and only then switches the layout and
removes the whole files. If it is interrupted before the switch, the whole
files are still in charge and running it again continues the conversion. If it
is interrupted after the switch, running it again removes the leftovers. On a
repository that is already chunked, it reports storage already optimized.
To go the other way, or to keep the original untouched, make a converted copy instead. The source is never changed:
$ synck archive ../launch-whole-file --storage-mode WHOLE_FILE
$ synck repository import launch-project launch-chunked --storage-mode CHUNKED