June 7, 2024

Let's dig Fossil

Fossil is a distributed version control system created by D. Richard Hipp, the same person who developed SQLite. Written in 2006, Fossil was designed to support the strict development process inspired by DO-178B, a standard used in aviation software development that emphasizes safety and reliability through thorough documentation and tracking of all changes.

DO-178B is a standard for developing safe and reliable aviation software. It requires thorough documentation and tracking of all changes. Fossil maintains a complete and unchangeable record of every modification made to the code, ensuring that every change is carefully recorded and cannot be altered. This feature makes it easier to review and verify that everything meets the high standards required for safety and reliability.

Additionally, Fossil serves as a software configuration management system, supporting bug tracking, wiki pages, and forum discussions. With its built-in web interface, all these features can be accessed from a web browser, making Fossil a comprehensive solution for managing software projects.

Fossil is written in C and SQL and is released under the BSD-2 license. It is a single, self-contained executable file that can run on any platform without needing to install any dependencies or libraries, unlike Git, which requires dependencies like autotools, curl, zlib, openssl, expat, and libiconv.

Fossil vs Git

Fossil and Git are both distributed version control systems, created around the same time, but they have different philosophies.

Git was built for the Linux Kernel project, specifically for the needs of Linus Torvalds. It is designed to be fast and efficient, making it highly effective for handling large projects with many contributors.

In contrast, Fossil was designed to support the SQLite development process among a small team of developers and to preserve the full history of the project. For example, Fossil does not include a rebase feature, as it goes against the philosophy of preserving history, hence the name “Fossil.”

Fossil is more opinionated than Git, enforcing a strict development process and taking a firm stance on preserving history. This makes Fossil less versatile but more focused.

Unique Features of Fossil

  1. Autosync and Manual Merge Mode: Fossil has a built-in autosync feature that automatically syncs your repository with a remote server. In Git, you need to manually push and pull changes.
  2. Show Descendants of a Check-in: Fossil can show all the descendants of a check-in, while Git can only show the ancestors.
  3. Operations on Multiple Repositories: Fossil supports operations on multiple repositories using the fossil all command.

Getting started with Fossil

First, some terminology:

  1. Check-in: A snapshot of the project at a particular point in time, containing the changes made since the last check-in.
  2. Artifact: A file or directory that is part of the project, such as a source code file or an image.
  3. Artifact ID: A unique identifier for an artifact, which is a SHA1 hash of the content.
  4. Manifest: A list of all the artifacts in a check-in, along with their artifact IDs.
  5. Repository: A database that stores all the check-ins, artifacts, and manifests for a project.
  6. Source Tree: The working directory of the project, containing the files and directories that make up the project.

Typical workflow

  • Use the fossil clone command to clone a repository.
  • Use the fossil new command to create a new repository.
  • Use the fossil open command to create a new source tree.
  • Use the fossil add , fossil rm and fossil mv commands to add, remove, and move files and directories in the source tree.
  • Use the fossil commit command to create a new check-in.
  • Use the fossil update command to merge in changes from other check-ins.
  • Use the fossil push and fossil pull commands to sync your repository with other repositories.

Branches can be created as part of a check-in, using the version of the current checkout directory as its basis.

fossil commit --branch my-new-branch-name

Alternatively, you can create a branch from an existing check-in using the fossil branch command.

Private branches

Fossil allows you to create private branches that are not visible to other users.

fossil commit --private

The --private option causes Fossil to put the check-in in a new branch named “private” that is not visible to other users. That branch will not participate in subsequent clone, sync, push, or pull operations. The branch will remain on the one local repository where it was created.

You can then publish the private changes by merging the private branch into the trunk.

fossil update trunk
fossil merge private
fossil commit

Removing content

If you accidentally push secrets or passwords, Fossil has a feature called “shunning” that allows you to remove a file from the repository’s history. Fossil will refuse to push or pull any shunned artifact.

Using fossil

To create a new repository, use the fossil new command:

➜ fossil new demo.fossil
project-id: df6c0e151fc09f5d6f15c45350ea141debff0139
server-id:  9439c66f3bf3bcad656c1096fe0f9f6a787dc886
admin-user: zain (initial password is "LS56oajNvM")

To open an existing repository, use the fossil open command in a directory where you want to work on the project:

➜  mkdir work-dir
➜  cd work-dir
➜  work-dir fossil open ../demo.fossil
project-name: <unnamed>
repository:   /Users/zain/mscc-demo/demo.fossil
local-root:   /Users/zain/mscc-demo/work-dir/
config-db:    /Users/zain/.config/fossil.db
project-code: df6c0e151fc09f5d6f15c45350ea141debff0139
checkout:     3354ab93dceafb3b0f104152457554478c465a61 2024-06-06 17:39:38 UTC
tags:         trunk
comment:      initial empty check-in (user: zain)
check-ins:    1

Add your files and commit it:

➜  work-dir vim english.py
➜  work-dir fossil add english.py
ADDED  english.py
➜  work-dir cp english.py french.py
➜  work-dir vim french.py
➜  work-dir fossil add french.py
ADDED  french.py
➜  work-dir fossil commit -m "Add french and english"
New_Version: 481c765ec93d225291e76e85803cf3b6925c5129235c63369722a6de68f0015a

Create a new branch and add a file to it. You can verify the current branch using fossil branch current command and switch branches using fossil checkout branch-name command.

➜  work-dir fossil branch new spanish trunk
New branch: 4197f4976f7e248b6ee4114ab82820429b1cd5b28c3d864e9131aa6423c5d442
➜  work-dir fossil branch current
trunk
➜  work-dir fossil checkout spanish
english.py
french.py
➜  work-dir ls
english.py french.py
➜  work-dir cp french.py spanish.py
➜  work-dir vim spanish.py
➜  work-dir fossil commit -m "Add spanish"
nothing has changed; use --allow-empty to override
➜  work-dir fossil add spanish.py
ADDED  spanish.py
➜  work-dir fossil commit -m "Add spanish"
New_Version: 9204d1a83fa40ecf8625d55a293efdf21655de86fa3a126df950074bdfe8fa1e

Merge the branch back to the trunk:

➜  work-dir fossil checkout trunk
english.py
french.py
➜  work-dir fossil merge spanish
ADDED spanish.py
 "fossil undo" is available to undo changes to the working checkout.
➜  work-dir ls
english.py french.py  spanish.py

You can view the timeline of the repository using the fossil timeline command and open the web interface using the fossil ui command.

➜  work-dir fossil timeline
=== 2024-06-06 ===
17:48:06 [9204d1a83f] Add spanish (user: zain tags: spanish)
17:46:36 [4197f4976f] Create new branch named "spanish" (user: zain tags: spanish)
17:44:26 [481c765ec9] *CURRENT* Add french (user: zain tags: trunk)
17:39:38 [3354ab93dc] initial empty check-in (user: zain tags: trunk)
+++ no more data (4) +++
➜  work-dir fossil ui

A preview of the web interface: Fossil web interface

Multiple-Checkout workflow

With Fossil, you can have multiple checkouts of the same repository on the same machine. This is useful when you want to work on different branches or features simultaneously.

➜  fossil clone https://example.com/repo /path/to/repo.fossil

➜  mkdir -p ~/src/my-project/trunk
➜  cd ~/src/my-project/trunk
➜  fossil open /path/to/repo.fossil    # implicitly opens “trunk”

➜  mkdir ../release
➜  cd ../release
➜  fossil open /path/to/repo.fossil release

➜  mkdir ../my-other-branch
➜  cd ../my-other-branch
➜  fossil open /path/to/repo.fossil my-other-branch

➜  mkdir ../scratch
➜  cd ../scratch
➜  fossil open /path/to/repo.fossil abcd1234

➜  mkdir ../test
➜  cd ../test
➜  fossil open /path/to/repo.fossil 2019-04-01

Now you can work on different branches or features in parallel without affecting each other. One each for:

  • trunk
  • release: latest public release
  • my-other-branch: a feature branch
  • scratch: a “scratch” directory for experiments
  • test: a directory for testing

The database

Fossil uses an SQLite database to store all the information about the project. You can verify the type of file using the file command:

➜ file demo.fossil
demo.fossil: SQLite 3.x database (Fossil repository), last written using SQLite version 3046000, file counter 22, database pages 56, cookie 0x28, schema 4, UTF-8, version-valid-for 22

You can explore the database using sqlite3 command:

➜ sqlite3 demo.fossil
SQLite version 3.43.2 2023-10-10 13:08:14
Enter ".help" for usage hints.
sqlite> .tables
attachment   config       mlink        rcvfrom      ticket
backlink     delta        orphan       reportfmt    ticketchng
blob         event        phantom      shun         unclustered
cherrypick   filename     plink        tag          unsent
concealed    leaf         private      tagxref      user
sqlite> select * from user;
1|zain|50f37eab2c7cd6ecdbef79786089472f49a41be7|s|||||1717695578||{}
2|anonymous|8BBD300363814C92|hz||||Anon|||{}
3|nobody||gjorz||||Nobody|||{}
4|developer||ei||||Dev|||{}
5|reader||kptw||||Reader|||{}
sqlite>

You can also use the fossil sql command to run SQL queries on the database.

Online hosting

Fossil repositories can be hosted online using services like Chiselapp. You can view the existing repositories on https://chiselapp.com/repositories.

Documentation

I would recommend reading the Fossil documentation to get a better understanding of how Fossil works and how to use it effectively.

Powered by Hugo & Kiss.