Fossil

Unversioned Content
Login

"Unversioned content" or "unversioned files" are files stored in a Fossil repository without history, meaning it retains the newest version of each such file, and that alone.

Though it omits history, Fossil does sync unversioned content between repositories. In the event of a conflict during a sync, it retains the most recent version of each unversioned file, discarding older versions.

Unversioned files are useful for storing ephemeral content such as builds or frequently changing web pages. We store the download page of the self-hosting Fossil repository as unversioned content, for example.

Accessing Unversioned Files

Unversioned files are not a part of a check-out. Unversioned files are intended to be accessible as web pages using URLs of the form: "https://example.com/cgi-script/uv/FILENAME". In other words, the URI method "uv" (short for "unversioned") followed by the name of the unversioned file will retrieve the content of the file. The MIME type is inferred from the filename suffix.

The content of unversioned files can also be retrieved using the fossil unvers cat FILENAME command.

A list of all unversioned files on a server can be seen using the /uvlist URL. (example).

Syncing Unversioned Files

Unversioned content does not sync between repositories by default. One must request it via commands such as:

fossil sync -u
fossil clone -u URL local-repo-name
fossil unversioned sync

The fossil sync and fossil clone commands will synchronize unversioned content if and only if they're given the "-u" (or "--unversioned") command-line option. The fossil unversioned sync command synchronizes the unversioned content without synchronizing anything else.

Notice that the "-u" option does not work on fossil push or fossil pull. The "-u" option is only available on "sync" and "clone". A rough equivalent of an unversioned pull would be the fossil unversioned revert command. The "unversioned revert" command causes the unversioned content on the local repository to overwritten by the unversioned content found on the remote repository.

Beware that because unversioned file sync is an uncommonly dangerous capability — there being no history to revert to in the case of human error — even the all-powerful Fossil "setup" user does not get unversioned file sync capability by default. See this for the full details, but the short-and-sweet takeaway is that a user needs the "y" capability on the remote before they can sync unversioned content. Until then, you're allowed to add such files to your local repo, but they will not sync.

Implementation Details

(This section outlines the current implementation of unversioned files. This is not an interface spec and hence subject to change.)

Unversioned content is stored in the repository in the "unversioned" table:

CREATE TABLE unversioned(
  uvid INTEGER PRIMARY KEY AUTOINCREMENT,  -- unique ID for this file
  name TEXT UNIQUE,       -- Name of the file
  rcvid INTEGER,          -- From whence this file was received
  mtime DATETIME,         -- Last change (seconds since 1970)
  hash TEXT,              -- SHA1 or SHA3-256 hash of uncompressed content
  sz INTEGER,             -- Size of uncompressed content
  encoding INT,           -- 0: plaintext  1: zlib compressed
  content BLOB            -- File content
);

Fossil does not create the table ahead of need. If there are no unversioned files in the repository, the "unversioned" table will not exist. Consequently, one simple way to purge all unversioned content from a repository is to run:

fossil sql "DROP TABLE unversioned; VACUUM;"

Lacking history for unversioned files, Fossil does not attempt delta compression on them.

Fossil servers exchange unversioned content whole; it does not attempt to "diff" your local version against the remote and send only the changes. We point this out because one use-case for unversioned content is to send large, frequently-changing files. Appreciate the consequences before making each change.

There are two bandwidth-saving measures in "fossil uv sync". The first is the regular HTTP payload compression step, done on all syncs. The second is that Fossil sends hash exchanges to determine when it can avoid sending duplicate content over the wire unnecessarily. See the synchronization protocol documentation for further information.