Time Machine, a (mostly) dependency-free simple version control system written in C99.
Note: WIP, expect major breakage.
TODO: replace zlib?
If you don't like any of these decisions, you're free to fork or use something else.
(While tm is unlikely to come in contact with a network, there's no reason not to protect it from SaaS.)
Internals are similar to git, except where I thought I could get away with something simpler.
All text is UTF-8. All files are text files, except for objects, which are zlib-compressed text. All text files are newline-terminated.
As in git, objects are identified by 160-bit SHA-1 hashes. A "pointer" is the 40 byte hexadecimal representation of a hash, encoded in UTF-8.
.tm | index | objects | [aa-ff] | [hex SHA-1 hash] | refs | HEAD ...
The index file is a pointer to a tree object.
There are three types of objects: blobs, commits, and trees.
The first line of the object is the type of the object. Unlike in git, the size of the object is not stored in the object, and the object type is terminated with a newline instead of a NUL.
The SHA-1 hash is of the decompressed contents of the object, including the object type.
The path at which an object with hash
$HASH whose first two
Y will be stored is
A blob is just a flat array of bytes. tm doesn't care about its contents.
A commit is a tagged tree. More specifically, a commit encapsulates the following information:
The format of a commit is:
commit tree deadbeefdeadbeefdeadbeefdeadbeefdeadbeef parent cafebabecafebabecafebabecafebabecafebabe parent deafbeaddeafbeaddeafbeaddeafbeaddeafbead author J. Random Hacker <firstname.lastname@example.org> committer K. Random Hacker <email@example.com> date SECS This line will become the subject of the patch These lines will become the body of the patch. This is another line. It serves no purpose except demonstrating that the body can have multiple lines.
This commit tags the tree
has two parents:
Commits must have one tree, at least one parent, one committer, at least one author, one date, one subject line, and any number of body lines. These lines MUST occur in the order specified here.
SECS is the number of seconds since 1970-01-01 00:00 UTC at which the
The subject line MUST be less than 50 characters. The body MUST be hard-wrapped at 72 characters. There must be a blank line between the subject and the body.
A tree represents a directory. It contains a list of blobs or trees, each of which is associated with a name and a set of permissions.
The format of a tree is:
tree rwxrwxr-x deadbeefdeadbeefdeadbeefdeadbeefdeadbeef docs rw-rw-r-- 4242424242424242424242424242424242424242 README.md
This tree has two entries,
world-readable, world-executable, and group-writable.
world-readable, not executable, and group-writable.
Note that we can't tell from this whether
trees or blobs. We can get that information from the objects referenced.
(Though in this case, it's obvious that
docs is a tree and
is a blob.)
Refs are pointers to commits. Refs may be used anywhere an object is
required, and are equivalent to specifying
The HEAD ref will always exist, and points to the commit currently checked out. New commits are parented to HEAD.