<title>Fossil Versus Git</title>

<h2>1.0 Don't Stress!</h2>

The feature sets of Fossil and [http://git-scm.com | Git] overlap in
many ways. Both are
[https://en.wikipedia.org/wiki/Distributed_version_control | distributed
version control systems] which store a tree of check-in objects to a
local repository clone. In both systems, the local clone starts out as a
full copy of the remote parent. New content gets added to the local
clone and then later optionally pushed up to the remote, and changes to
the remote can be pulled down to the local clone at will. Both systems
offer diffing, patching, branching, merging, cherry-picking, bisecting,
private branches, a stash, etc.

Fossil has inbound and outbound Git conversion features, so if you start
out using one DVCS and later decide you like the other better, you can
easily [./inout.wiki | move your version-controlled file content].¹

In this document, we set all of that similarity and interoperability
aside and focus on the important differences between the two, especially
those that impact the user experience.

Keep in mind that you are reading this on a Fossil website, and though
we try to be fair, the information here
might be biased in favor of Fossil, if only because we spend most of our
time using Fossil, not Git.  Ask around for second opinions from
people who have used <em>both</em> Fossil and Git.

If you want a more practical, less philosophical guide to moving from
Git to Fossil, see our [./gitusers.md | Git to Fossil Translation Guide].


<h2>2.0 Differences Between Fossil And Git</h2>

Differences between Fossil and Git are summarized by the following table,
with further description in the text that follows.

<blockquote><table border=1 cellpadding=5 align=center>
<tr><th width="49%">GIT</th><th width="49%">FOSSIL</th><th width="2%">more</th></tr>
<tr>
    <td>File versioning only</td>
    <td>VCS, tickets, wiki, docs, notes, forum, chat, UI,
    [https://en.wikipedia.org/wiki/Role-based_access_control|RBAC]</td>
    <td><a href="#features">2.1&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>A federation of many small programs</td>
    <td>One self-contained, stand-alone executable</td>
    <td><a href="#selfcontained">2.2&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Custom key/value data store</td>
    <td>[https://sqlite.org/mostdeployed.html|The most used SQL database in the world]</td>
    <td><a href="#durable">2.3&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Runs natively on POSIX systems</td>
    <td>Runs natively on both POSIX and Windows</td>
    <td><a href="#portable">2.4&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Bazaar-style development</td>
    <td>Cathedral-style development</td>
    <td><a href="#devorg">2.5.1&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Designed for Linux kernel development</td>
    <td>Designed for SQLite development</td>
    <td><a href="#scale">2.5.2&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Many contributors</td>
    <td>Select contributors</td>
    <td><a href="#contrib">2.5.3&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Focus on individual branches</td>
    <td>Focus on the entire tree of changes</td>
    <td><a href="#branches">2.5.4&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>One check-out per repository</td>
    <td>Many check-outs per repository</td>
    <td><a href="#checkouts">2.6&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Remembers what you should have done</td>
    <td>Remembers what you actually did</td>
    <td><a href="#history">2.7&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>Commit first</td>
    <td>Test first</td>
    <td><a href="#testing">2.8&nbsp;&darr;</a></td>
</tr>
<tr>
    <td>SHA-1 or SHA-2</td>
    <td>SHA-1 and/or SHA-3, in the same repository</td>
    <td><a href="#hash">2.9&nbsp;&darr;</a></td>
</tr>
</table></blockquote>

<h3 id="features">2.1 Featureful</h3>

Git provides file versioning services only, whereas Fossil adds
an integrated [./wikitheory.wiki | wiki],
[./bugtheory.wiki | ticketing &amp; bug tracking],
[./embeddeddoc.wiki | embedded documentation], 
[./event.wiki | technical notes], a [./forum.wiki | web forum],
and a [./chat.md | chat service],
all within a single nicely-designed [./customskin.md|skinnable] web
[/help?cmd=ui|UI],
protected by [./caps/ | a fine-grained role-based
access control system].
These additional capabilities are available for Git as 3rd-party
add-ons, but with Fossil they are integrated into
the design.  One way to describe Fossil is that it is
"[https://github.com/ | GitHub]-in-a-box."

Fossil can do operations over all local repo clones and check-out
directories with a single command. For example, Fossil lets you say
"<tt>fossil all sync</tt>" on a laptop prior to taking it off the network
hosting those repos. You can sync up to all of the private repos on your
company network plus those public Internet-hosted repos you use. Whether
going out for a working lunch or on a transoceanic airplane trip, one
command gets you in sync. This works with several other Fossil
sub-commands, such as "<tt>fossil all changes</tt>" to get a list of files
that you forgot to commit prior to the end of your working day, across
all repos.

Whenever Fossil is told to modify the local checkout in some destructive
way ([/help?cmd=rm|fossil rm], [/help?cmd=update|fossil update],
[/help?cmd=revert|fossil revert], etc.) Fossil remembers the prior state
and is able to return the check-out directory to that state with a
<tt>fossil undo</tt> command. You cannot undo a commit in Fossil
([#history | on purpose!]) but as long as the change remains confined to
the local check-out directory only, Fossil makes undo
[https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things|easier than in
Git].

For developers who choose to self-host projects (rather than using a
3rd-party service such as GitHub) Fossil is much easier to set up, since
the stand-alone Fossil executable together with a [./server/any/cgi.md|2-line CGI script]
suffice to instantiate a full-featured developer website.  To accomplish
the same using Git requires locating, installing, configuring, integrating,
and managing a wide assortment of separate tools.  Standing up a developer
website using Fossil can be done in minutes, whereas doing the same using
Git requires hours or days.

Fossil is small, complete, and self-contained.  If you clone
[https://github.com/git/git|Git's self-hosting repository], you get just
Git's source code.  If you clone Fossil's self-hosting repository, you
get the entire Fossil website — source code, documentation, ticket
history, and so forth.² That means you get a copy of this very article
and all of its historical versions, plus the same for all of the other
public content on this site.


<h3 id="selfcontained" name="selfcontained">2.2 Self Contained</h3>

Git is actually a collection of many small tools, each doing one small
part of the job, which can be recombined (by experts) to perform
powerful operations. Git has a lot of complexity and many dependencies,
so that most people end up installing it via some kind of package
manager, simply because the creation of complicated binary packages is
best delegated to people skilled in their creation. Normal Git users are
not expected to build Git from source and install it themselves.

Fossil is a single self-contained stand-alone executable which by default
depends only on common platform libraries.  You can statically link
to get an executable with no external dependencies at all &mdash; a useful
feature for running inside a restrictive 
[https://en.wikipedia.org/wiki/Chroot|chroot jail].

The precompiled Fossil binaries are delivered as just a single
executable.  The precompiled Windows deliveries are just a ZIP archive
containing only "<tt>fossil.exe</tt>".  There is no "<tt>setup.exe</tt>"
to run.  Linux and Mac precompiled binaries are a tarball containing
just the "<tt>fossil</tt>" executable.  To install, just put the
executable on your PATH.  To uninstall, just delete the executable.
To upgrade (or downgrade) simply replace the executable.

A typical Fossil executable is between 5 and 7 megabytes uncompressed
(as of 2020-12-12),
assuming that the executable is statically linked against OpenSSL.  

Fossil is easy to build from sources. Just run
"<tt>./configure && make</tt>" on POSIX systems and
"<tt>nmake /f Makefile.msc</tt>" on Windows.

Contrast a basic installation of Git, which takes up about
15&nbsp;MiB on Debian 10 across 230 files, not counting the contents of
<tt>/usr/share/doc</tt> or <tt>/usr/share/locale</tt>. If you need to
deploy to any platform where you cannot count facilities like the POSIX
shell, Perl interpreter, and Tcl/Tk platform needed to fully use Git
as part of the base platform, the full footprint of a Git installation
extends to more like 45&nbsp;MiB and thousands of files. This complicates
several common scenarios: Git for Windows, chrooted Git servers,
Docker images...

Some say that Git more closely adheres to the Unix philosophy,
summarized as "many small tools, loosely joined," but we have many
examples of other successful Unix software that violates that principle
to good effect, from Apache to Python to ZFS. We can infer from that
that this is not an absolute principle of good software design.
Sometimes "many features, tightly-coupled" works better. What actually
matters is effectiveness and efficiency. We believe Fossil achieves
this.

The above size comparisons aren't apples-to-apples anyway. We've
compared the size of Fossil with all of its [#features | many built-in
features] to a fairly minimal Git installation. You must add a lot
of third-party
software to Git to give it a Fossil-equivalent feature set. Consider
[https://about.gitlab.com/|GitLab], a third-party extension to Git
wrapping it in many features, making it roughly Fossil-equivalent,
though [https://docs.gitlab.com/ee/install/requirements.html|much more
resource hungry] and hence more costly to run than the equivalent
Fossil setup. GitLab's basic requirements are easy to accept when you're dedicating
a local rack server or blade to it, since its minimum requirements are
more or less a description of the smallest
thing you could call a "server" these days, but when you go to host that
in the cloud, you can expect to pay about 8 times as much to comfortably host
GitLab as for Fossil.³ This difference is largely due to basic
technology choices: Ruby and PostgreSQL vs C and SQLite.

The Fossil project itself is [./selfhost.wiki|hosted on a small and
inexpensive VPS].  A bare-bones $5/month VPS or a
spare Raspberry Pi is sufficient to run a full-up project
site, complete with tickets, wiki, chat, and forum, in addition to
being a code repository.

<h3 id="durable" name="database">2.3 Query Language</h3>

The baseline data structures for Fossil and Git are the same, modulo
formatting details. Both systems manage a
[https://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic
graph] (DAG) of [https://en.wikipedia.org/wiki/Merkle_tree | Merkle
tree] structured check-in objects.
Check-ins are identified by a cryptographic hash of the check-in
contents, and each check-in refers to its parent via the parent's hash.

The difference is that Git stores its objects as individual files in the
<tt>.git</tt> folder or compressed into bespoke key/value
[https://git-scm.com/book/en/v2/Git-Internals-Packfiles|pack-files],
whereas Fossil stores its objects in a [https://www.sqlite.org/|SQLite]
database file which provides ACID transactions and a high-level query
language.
This difference is more than an implementation detail. It has important
practical consequences.

One notable consequence is that it is difficult to find the descendents
of check-ins in Git.
One can easily locate the ancestors of a particular Git check-in
by following the pointers embedded in the check-in object, but it is
difficult to go the other direction and locate the descendants of a
check-in.  It is so difficult, in fact, that neither native Git nor
GitHub provide this capability short of crawling the
[https://www.git-scm.com/docs/git-log|commit log].  With Fossil,
on the other hand, finding descendents is a simple SQL query.
It is common in Fossil to ask to see
[/timeline?df=release&y=ci|all check-ins since the last release].
Git lets you see "what came before".  Fossil makes it just as
easy to also see "what came after".

Leaf check-ins in Git that lack a "ref" become "detached," making them
difficult to locate and subject to garbage collection. This
[http://gitfaq.org/articles/what-is-a-detached-head.html|detached head
state] problem has caused grief for
[https://www.google.com/search?q=git+detached+head+state | many
of Git users]. With
Fossil, detached heads are simply impossible because we can always find
our way back into the Merkle tree using one or more of the relations
in the SQL database.

The SQL query capabilities of Fossil make it easier to track the
changes for one particular file within a project.  For example,
you can easily find
[/finfo/www/fossil-v-git.wiki|the complete edit history of this one document],
or even 
[/finfo/www/fossil-v-git.wiki?ubg|the same history color-coded by committer],
Both questions are simple SQL query in Fossil, with procedural code
only being used to format the result for display.
The same result could be obtained from Git, but because the data is
in a key/value store, much more procedural code has to be written to
walk the data and compute the result. And since that is a lot more
work, the question is seldom asked.

The ease of querying Fossil data using SQL means that status or
history information about the project under management is easier
to obtain.  And being easier means that it is more likely to happen.
Fossil reports tend to be more detailed and useful.
Consider the [/timeline?c=6df7a853ec16865b|this Fossil timeline] 
compared to its
[https://github.com/drhsqlite/fossil-mirror/commits/master?after=f720c106d297ca1f61bccb30c5c191b88a626d01+34|its
closest equivalent in GitHub].  Judge for yourself: Which of those
reports is more useful to a developer trying to understand what happened?

The bottom line is that even though Fossil and Git are built around
the same low-level data structure, the use of SQL
to query this data makes the data more accessible in Fossil, resulting
in more detailed information being available to the user.  This
improves situational awareness and makes working on the project
easier.

<h3 id="portable">2.4 Portable</h3>

Fossil is largely written in ISO C, almost purely conforming to the
original 1989 standard. We make very little use of
[https://en.wikipedia.org/wiki/C99|C99], and we do not knowingly make
any use of
[https://en.wikipedia.org/wiki/C11_(C_standard_revision)|C11]. Fossil
does call POSIX and Windows APIs where necessary, but it's about
as portable as you can ask given that ISO C doesn't define all of the
facilities Fossil needs to do its thing. (Network sockets, file locking,
etc.) There are certainly well-known platforms Fossil hasn't been ported
to yet, but that's most likely due to lack of interest rather than
inherent difficulties in doing the port. We believe the most stringent
limit on its portability is that it assumes at least a 32-bit CPU and
several megs of flat-addressed memory.⁴ Fossil isn't quite as
[https://www.sqlite.org/custombuild.html|portable as SQLite], but it's
close.

Over half of the C code in Fossil is actually an embedded copy of the
current version of SQLite. Much of what is Fossil-specific after you set
SQLite itself aside is SQL code calling into SQLite. The number of lines
of SQL code in Fossil isn't large by percentage, but since SQL is such
an expressive, declarative language, it has an outsized contribution to
Fossil's user-visible functionality.

Fossil isn't entirely C and SQL code. Its web UI [./javascript.md |
uses JavaScript where
necessary]. The server-side
UI scripting uses a custom minimal
[https://en.wikipedia.org/wiki/Tcl|Tcl] dialect called
[https://fossil-scm.org/xfer/doc/trunk/www/th1.md|TH1], which is
embedded into Fossil itself. Fossil's build system and test suite are
largely based on Tcl.⁵ All of this is quite portable.

About half of Git's code is POSIX C, and about a third is POSIX shell
code. This is largely why the so-called "Git for Windows" distributions
(both [https://git-scm.com/download/win|first-party] and
[https://gitforwindows.org/|third-party]) are actually an
[http://mingw.org/wiki/msys|MSYS POSIX portability environment] bundled
with all of the Git stuff, because it would be too painful to port Git
natively to Windows. Git is a foreign citizen on Windows, speaking to it
only through a translator.⁶

While Fossil does lean toward POSIX norms when given a choice — LF-only
line endings are treated as first-class citizens over CR+LF, for example
— the Windows build of Fossil is truly native.

The third-party extensions to Git tend to follow this same pattern.
[http://mingw.org/wiki/msys|GitLab isn't portable to Windows at all],
for example. For that matter, GitLab isn't even officially supported on
macOS, the BSDs, or uncommon Linuxes! We have many users who regularly
build and run Fossil on all of these systems.


<h3 id="vs-linux">2.5 Linux vs. SQLite</h3>

Fossil and Git promote different development styles because each one was
specifically designed to support the creator's main software
development project: [https://en.wikipedia.org/wiki/Linus_Torvalds|Linus
Torvalds] designed Git to support development of
[https://www.kernel.org/|the Linux kernel], and
[https://en.wikipedia.org/wiki/D._Richard_Hipp|D. Richard Hipp] designed
Fossil to support the development of [https://sqlite.org/|SQLite].
Both projects must rank high on any objective list of "most
important FOSS projects," yet these two projects are almost entirely unlike
one another, so it is natural that the DVCSes created to support these
projects also differ in many ways.

In the following sections, we will explain how four key differences
between the Linux and SQLite software development projects dictated the
design of each DVCS's low-friction usage path.

When deciding between these two DVCSes, you should ask yourself, "Is my
project more like Linux or more like SQLite?"


<h4 id="devorg">2.5.1 Development Organization</h4>

Eric S. Raymond's seminal essay-turned-book
"[https://en.wikipedia.org/wiki/The_Cathedral_and_the_Bazaar|The
Cathedral and the Bazaar]" details the two major development
organization styles found in
[https://en.wikipedia.org/wiki/Free_and_open-source_software|FOSS]
projects. As it happens, Linux and SQLite fall on opposite sides of this
dichotomy. Differing development organization styles dictate a different
design and low-friction usage path in the tools created to support each
project.

Git promotes the Linux kernel's bazaar development style, in which a
loosely-associated mass of developers contribute their work through
[https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows#_dictator_and_lieutenants_workflow|a
hierarchy of lieutenants] who manage and clean up these contributions
for consideration by Linus Torvalds, who has the power to cherry-pick
individual contributions into his version of the Linux kernel. Git
allows an anonymous developer to rebase and push specific locally-named
private branches, so that a Git repo clone often isn't really a clone at
all: it may have an arbitrary number of differences relative to the
repository it originally cloned from. Git encourages siloed development.
Select work in a developer's local repository may remain private
indefinitely.

The Git preference for siloed development has been strongly adopted by Github,
who say
"[https://guides.github.com/activities/forking|Forking is at the core of social coding at GitHub]".
As a result, as of January 2021,
[https://github.com/search?q=is:public|Github hosts 43 million distinct software projects],
most of them created as a results of Git/Github forking and very many
of them discontinued.

All of this is exactly what one wants when doing bazaar-style
development.

Fossil's normal mode of operation differs on every one of these points,
with the specific designed-in goal of promoting SQLite's cathedral
development model:

<ul>
    <li><p><b>Personal engagement:</b> SQLite's developers know each
    other by name and work together daily on the project.</p></li>

    <li><p><b>Trust over hierarchy:</b> SQLite's developers check
    changes into their local repository, and these are immediately and
    automatically synchronized up to the central repository; there is no
    "[https://git-scm.com/book/en/v2/Distributed-Git-Distributed-Workflows#_dictator_and_lieutenants_workflow|dictator
    and lieutenants]" hierarchy as with Linux kernel contributions.  D.
    Richard Hipp rarely overrides decisions made by those he has trusted
    with commit access on his repositories. Fossil allows you to give
    [./caps/admin-v-setup.md|some users] more power over what
    they can do with the repository, but Fossil [./caps/index.md#ucap |
    only loosely supports] the enforcement of a development organization's
    social and power hierarchies. Fossil is a great fit for
    [https://en.wikipedia.org/wiki/Flat_organization|flat
    organizations].</p></li>

    <li><p><b>No easy drive-by contributions:</b> Git
    [https://www.git-scm.com/docs/git-request-pull|pull requests] offer
    a low-friction path to accepting
    [https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by
    contributions]. Fossil's closest equivalent is its unique
    [/help?cmd=bundle|bundle] feature, which requires higher engagement
    than firing off a PR.⁷ This difference comes directly from the
    initial designed purpose for each tool: the SQLite project doesn't
    accept outside contributions from previously-unknown developers, but
    the Linux kernel does.</p></li>

    <li><p><b>No rebasing:</b> When your local repo clone syncs changes
    up to its parent, those changes are sent exactly as they were
    committed locally. [#history|There is no rebasing mechanism in
    Fossil, on purpose.]</p></li>

    <li><p><b>Sync over push:</b> Explicit pushes are uncommon in
    Fossil-based projects: the default is to rely on
    [/help?cmd=autosync|autosync mode] instead, in which each commit
    syncs immediately to its parent repository. This is a mode so you
    can turn it off temporarily when needed, such as when working
    offline. Fossil is still a truly distributed version control system;
    it's just that its starting default is to assume you're rarely out
    of communication with the parent repo.
    <br><br>
    This is not merely a reflection of modern always-connected computing
    environments. It is a conscious decision in direct support of
    SQLite's cathedral development model: we don't want developers going
    dark, then showing up weeks later with a massive bolus of changes
    for us to integrate all at once.
    [https://en.wikipedia.org/wiki/Jim_McCarthy_(author)|Jim McCarthy]
    put it well in his book on software project management,
    <i>[https://www.amazon.com/dp/0735623198/|Dynamics of Software
    Development]</i>: "[https://www.youtube.com/watch?v=oY6BCHqEbyc|Beware
    of a guy in a room]."</p></li>

    <li><p><b>Branch names sync:</b> Unlike in Git, branch names in
    Fossil are not purely local labels. They sync along with everything
    else, so everyone sees the same set of branch names. Fossil's design
    choice here is a direct reflection of the Linux vs. SQLite project
    outlook: SQLite's developers collaborate closely on a single
    coherent project, whereas Linux's developers go off on tangents and
    occasionally sync changes up with each other.</p></li>

    <li><p><b>Private branches are rare:</b>
    [/doc/trunk/www/private.wiki|Private branches exist in Fossil], but
    they're normally used to handle rare exception cases, whereas in
    many Git projects, they're part of the straight-line development
    process.</p></li>

    <li><p><b>Identical clones:</b> Fossil's autosync system tries to
    keep each local clone identical to the repository it cloned
    from.</p></li>
</ul>

Where Git encourages siloed development, Fossil fights against it.
Fossil places a lot of emphasis on synchronizing everyone's work and on
reporting on the state of the project and the work of its developers, so
that everyone — especially the project leader — can maintain a better
mental picture of what is happening, leading to better situational
awareness.

You can think about this difference in terms of
[https://en.wikipedia.org/wiki/Feedback | feedback loop size], which we
know from the mathematics of
[https://en.wikipedia.org/wiki/Control_theory | control theory] to
directly affect the speed at which any system can safely make changes.
The larger the feedback loop, the slower the whole system must run in
order to avoid loss of control. The same concept shows up in other
contexts, such as in the [https://en.wikipedia.org/wiki/OODA_loop | OODA
loop] concept originally developed to explain the success of the US F-86
Sabre fighter aircraft over the on-paper superior MiG-15, then later
applied in other contexts, such as business process management.
Committing your changes to private branches in order to delay a public
push to the parent repo increases the size of your collaborators'
control loops, either causing them to slow their work in order to safely
react to your work, or to overcorrect in response to each change.

Each DVCS can be used in the opposite style, but doing so works against
their low-friction paths.


<h4 id="scale">2.5.2 Scale</h4>

The Linux kernel has a far bigger developer community than that of
SQLite: there are thousands and thousands of contributors to Linux, most
of whom do not know each others names. These thousands are responsible
for producing roughly 89⨉ more code than is in SQLite. (10.7
[https://en.wikipedia.org/wiki/Source_lines_of_code|MLOC] vs. 0.12 MLOC
according to [https://dwheeler.com/sloccount/|SLOCCount].) The Linux
kernel and its development process were already uncommonly large back in
2005 when Git was designed, specifically to support the consequences of
having such a large set of developers working on such a large code base.

95% of the code in SQLite comes from just four programmers, and 64% of
it is from the lead developer alone. The SQLite developers know each
other well and interact daily. Fossil was designed for this development
model.

We think you should ask yourself whether you have Linus Torvalds scale
software configuration management problems or D. Richard Hipp scale
problems when choosing your DVCS. An
[https://en.wikipedia.org/wiki/Impact_wrench|automotive air impact
wrench] running at 8000 RPM driving an M8 socket-cap bolt at 16 cm/s is
not the best way to hang a picture on the living room wall.


<h4 id="contrib">2.5.3 Accepting Contributions</h4>

As of this writing, Git has received about 4.5 times as many commits as
Fossil resulting in about 2.5 times as many lines of source code. The line
count excludes tests and in-tree third-party dependencies. It does not
exclude the default GUI for each, since it's integral for Fossil, so we
count the size of <tt>gitk</tt> in this.

It is obvious that Git is bigger in part because of its first-mover
advantage, which resulted in a larger user community, which results in
more contributions. But is that the <i>only</i> reason? We believe there
are other relevant differences that also play into this which fall out
of the "Linux vs. SQLite" framing: licensing, community structure, and
how we react to
[https://www.jonobacon.com/2012/07/25/building-strong-community-structural-integrity/|drive-by
contributions]. In brief, it's harder to get a new feature into Fossil
than into Git.

A larger feature set is not necessarily a good thing. Git's command line
interface is famously arcane. Masters of the arcane are able to do
wizardly things, but only by studying their art deeply for years. This
strikes us as a good thing only in cases where use of the tool itself is
the primary point of that user's work.

Almost no one uses a DVCS for its own sake; very few people get paid
specifically in order to drive a DVCS. We use DVCSes as a tool to
support some other effort, so we do not necessarily want the DVCS with
the most features. We want a DVCS with easily internalized behavior so
we can thoroughly master it despite spending only a small fraction of
our working time thinking about the DVCS. We want to pick the tool up,
use it quickly, and then set it aside in order to get back to our actual
job as quickly as possible.

Professional software developers in particular are prone to focusing on
feature set sizes when choosing tools because this is sometimes a highly
important consideration. They spend all day, every day, in their
favorite text editors, and time they spend learning all of the arcana of
their favorite programming languages is well-spent. Skills with these
tools are direct productivity drivers, which in turn directly drives how
much money a developer can make. (Or how much idle time they can afford
to take, which amounts to the same thing.) But if you are a professional
software developer, we want you to ask yourself a question: "How do I
get paid more by mastering arcane features of my DVCS?" Unless you have
a good answer to that, you probably do not want to be choosing a DVCS
based on how many arcane features it has.

The argument is similar for other types of users: if you are a hobbyist,
how much time do you want to spend mastering your DVCS instead of on
the hobby supported by use of that DVCS?

There is some minimal set of features required to achieve the purposes
that drive our selection of a DVCS, but there is a level beyond which
more features only slow us down while we're learning the tool, since we
must plow through documentation on features we're not likely to ever
use. When the number of features grows to the point where people of
normal motivation cannot spend the time to master them all, the tool
becomes <i>less</i> productive to use.

The core developers of the Fossil project achieve a balance between feature
set size and ease of use by
carefully choosing which users to give commit bits to, then in being
choosy about which of the contributed feature branches to merge down to
trunk. We say "no" to a lot of feature proposals.

The end result is that Fossil more closely adheres to
[https://en.wikipedia.org/wiki/Principle_of_least_astonishment|the
principle of least astonishment] than Git does.


<h4 id="branches">2.5.4 Individual Branches vs. The Entire Change History</h4>

Both Fossil and Git store history as a directed acyclic graph (DAG)
of changes, but Git tends to focus more on individual branches of
the DAG, whereas Fossil puts more emphasis on the entire DAG.

For example, the default behavior in Git is to only synchronize
a single branch, whereas with Fossil the only sync option is to
sync the entire DAG.  Git commands,
GitHub, and GitLab tend to show only a single branch at
a time, whereas Fossil usually shows all parallel branches at
once.  Git has commands like "rebase" that help keep all relevant
changes on a single branch, whereas Fossil encourages a style of
many concurrent branches constantly springing into existence,
undergoing active development in parallel for a few days or weeks, then
merging back into the main line and disappearing.

This difference in emphasis arises from the different purposes of
the two systems.  Git focuses on individual branches, because that
is exactly what you want for a highly-distributed bazaar-style project
such as Linux.  Linus Torvalds does not want to see every check-in
by every contributor to Linux, as such extreme visibility does not scale
well.  But Fossil was written for the cathedral-style SQLite project
with just a handful of active committers.  Seeing all
changes on all branches all at once helps keep the whole team
up-to-date with what everybody else is doing, resulting in a more 
tightly focused and cohesive implementation.


<h3 id="checkouts">2.6 One vs. Many Check-outs per Repository</h3>

Because Git commingles the repository data with the initial checkout of
that repository, the default mode of operation in Git is to stick to that
single work/repo tree, even when that's a shortsighted way of working.

Fossil doesn't work that way. A Fossil repository is a SQLite database
file which is normally stored outside the working checkout directory. You can
[/help?cmd=open | open] a Fossil repository any number of times into
any number of working directories. A common usage pattern is to have one
working directory per active working branch, so that switching branches
is done with a <tt>cd</tt> command rather than by checking out the
branches successively in a single working directory.

Fossil does allow you to switch branches within a working checkout
directory, and this is also often done. It is simply that there is no
inherent penalty to either choice in Fossil as there is in Git. The
standard advice is to use a switch-in-place workflow in Fossil when
the disturbance from switching branches is small, and to use multiple
checkouts when you have long-lived working branches that are different
enough that switching in place is disruptive.

While you can [./gitusers.md#worktree | use Git in the Fossil style],
Git's default tie between working directory and
repository means the standard method for working with a Git repo is to
have one working directory only. Most Git tutorials teach this style, so
it is how most people learn to use Git. Because relatively few people
use Git with multiple working directories per repository, there are
[https://duckduckgo.com/?q=git+worktree+problem | several known
problems] with that way of working, problems which don't happen in Fossil because of
the clear [./ckout-workflows.md | separation] between a Fossil repository and
each working directory.

This distinction matters because switching branches inside a single working directory loses local context
on each switch.

For instance, in any software project where the runnable program must be
built from source files, you invalidate build objects on each switch,
artificially increasing the time required to switch versions. Most obviously, this
affects software written in statically-compiled programming languages
such as C, Java, and Haskell, but it can even affect programs written in
dynamic languages like JavaScript. A typical
[https://en.wikipedia.org/wiki/Single-page_application | SPA] build
process involves several passes: [http://browserify.org/ | Browserify] to convert
[https://nodejs.org/ | Node] packages so they'll run in a web browser,
[https://sass-lang.com | SASS] to CSS translation,
transpilation of [https://www.typescriptlang.org | Typescript] to JavaScript,
[https://github.com/mishoo/UglifyJS | uglification], etc.
Once all that processing work is done for a given input
file in a given working directory, why re-do that work just to switch
versions? If most of the files that differ between versions don't change
very often, you can save substantial time by switching branches with
<tt>cd</tt> rather than swapping versions in-place within a working
checkout directory.

For another example, you might have an active long-running test grinding
away in a working directory, then get a call from a customer requiring
that you switch to a stable branch to answer questions in terms of the
version that customer is running. You don't want to stop the test in
order to switch your lone working directory to the stable branch.

Disk space is cheap. Having several working directories, each with its
own local state, makes switching versions cheap and fast. Plus,
<tt>cd</tt> is faster to type than <tt>git checkout</tt> or <tt>fossil
update</tt>.


<h3 id="history">2.7 What you should have done vs. What you actually did</h3>

Git puts a lot of emphasis on maintaining
a "clean" check-in history.  Extraneous and experimental branches by
individual developers often never make it into the main repository.
Branches may be rebased before being pushed to make
it appear as if development had been linear, or "squashed" to make it
appear that multiple commits were made as a single commit.
There are [https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History |
other history rewriting mechanisms in Git] as well. Git strives to record what
the development of a project should have looked like had there been no
mistakes.

Fossil, in contrast, puts more emphasis on recording exactly what happened,
including all of the messy errors, dead-ends, experimental branches, and
so forth.  One might argue that this
makes the history of a Fossil project "messy," but another point of view
is that this makes the history "accurate."  In actual practice, the
superior reporting tools available in Fossil mean that the added "mess"
is not a factor.

Like Git, Fossil has an [/help?cmd=amend|amend command] for modifying
prior commits, but unlike in Git, this works not by replacing data in
the repository, but by adding a correction record to the repository that
affects how later Fossil operations present the corrected data. The old
information is still there in the repository, it is just overridden from
the amendment point forward.

Fossil lacks almost every other history rewriting mechanism listed on
the Git documentation page linked above. [./rebaseharm.md | There is no
rebase] in Fossil, on purpose, thus no way to reorder or copy commits
around in the commit hash tree. There is no commit squashing, dropping,
or interactive patch-based cherry-picking of commit elements in Fossil.
There is nothing like Git's <tt>filter-branch</tt> in Fossil.

The lone exception is deleting commits. Fossil has two methods for doing
that, both of which have stringent limitations, on purpose.

The first is [/doc/trunk/www/shunning.wiki | shunning]. See that
document for details, but briefly, you only get mandatory compliance
for shun requests within a single repository. Shun requests do not
propagate automatically between repository clones. A Fossil repository
administrator can <i>cooperatively</i> pull another repo's shun requests
across a sync boundary, so that two admins can get together and agree to
shun certain committed artifacts, but a person cannot force their local
shun requests into another repo without having admin-level control over
the receiving repo as well. Fossil's shun feature isn't for fixing up
everyday bad commits, it's for dealing with extreme situations: public
commits of secret material, ticket/wiki/forum spam, law enforcement
takedown demands, etc.

There is also the experimental [/help?cmd=purge | <tt>purge</tt>
command], which differs from shunning in ways that aren't especially
important in the context of this document. At a 30000 foot level, you
can think of purging as useful only when you've turned off Fossil's
autosync feature and want to pluck artifacts out of its hash tree before
they get pushed. In that sense, it's approximately the same as
<tt>git rebase -i, drop</tt>. However, given that Fossil defaults to
having autosync enabled [#devorg | for good reason], the purge command
isn't very useful in practice: once a commit has been pushed into
another repo, shunning is more useful if you need to delete it from
history.

If these accommodations strike you as incoherent with respect to
Fossil's philosophy of durable, unchanging commits, realize that if
shunning and purging were removed from Fossil, you could still remove
artifacts from the repository with SQL <tt>DELETE</tt> statements; the
repository database file is, after all, directly modifiable, being
writable by your user. Where the Fossil philosophy really takes hold is
in making it difficult to violate the integrity of the hash tree.
It's somewhat tangential, but the document [./blockchain.md | "Is Fossil
a Blockchain?"] touches on this and related topics.

One commentator characterized Git as recording history according to
the victors, whereas Fossil records history as it actually happened.


<h3 id="testing">2.8 Test Before Commit</h3>

One of the things that falls out of Git's default separation of commit
from push is that there are several Git sub-commands that jump straight
to the commit step before a change could possibly be tested. Fossil, by
contrast, makes the equivalent change to the local working check-out
only, requiring a separate check-in step to commit the change. This
design difference falls naturally out of Fossil's default-enabled
autosync feature and its philosophy of [#history | not offering history
rewriting features].

The prime example in Git is rebasing: the change happens to the local
repository immediately if successful, even though you haven't tested the
change yet. It's possible to argue for such a design in a tool like Git
since it lacks an autosync feature, because you can still test the
change before pushing local changes to the parent repo, but in the
meantime you've made a durable change to your local Git repository. You
must do something drastic like <tt>git reset --hard</tt> to revert that
rebase or rewrite history before pushing it if the rebase causes a
problem. If you push your rebased local repo up to the parent without
testing first, you cannot fix it without violating
[https://www.atlassian.com/git/tutorials/merging-vs-rebasing#the-golden-rule-of-rebasing
| the golden rule of rebasing].

Lesser examples are the Git <tt>merge</tt>, <tt>cherry-pick</tt>, and
<tt>revert</tt> commands, all of which apply work from one branch onto
another, and all of which commit their change to the local repository
immediately without giving you
an opportunity to test the change first unless you give the
<tt>--no-commit</tt> option. Otherwise, you're back in the same boat:
reset the local repository or rewrite history to fix things, then maybe
retry.

Fossil cannot sensibly work that way because of its default-enabled
autosync feature and its purposeful paucity of commands for modifying
commits, as discussed in [#history | the prior section].

Instead of jumping straight to the commit step, Fossil
applies the proposed merge to the local working directory only,
requiring a separate check-in step before the change is committed to the
repository. This gives you a chance to test the change first,
either manually or by running your software's automatic tests. (Ideally,
both!) Thus, Fossil doesn't need rebase, squashing,
<tt>reset --hard</tt>, or other Git commit mutating mechanisms.

Because Fossil requires an explicit commit for a merge, it has the nice
side benefit that it makes you give an explicit commit <i>message</i>
for each merge, whereas Git writes that commit message itself by default
unless you give the optional <tt>--edit</tt> flag to override it.

We don't look at this difference as a workaround in Fossil for autosync,
but instead as a test-first philosophical difference:
<tt>fossil commit</tt> is a <i>commitment</i>. When every commit is
pushed to the parent repo by default, it encourages a working style in
which every commit is tested first. It encourages thinking before
acting. We believe this is an inherently good thing.

Incidentally, this is a good example of Git's messy command design.
These three commands:

<pre>
    $ git merge HASH 
    $ git cherry-pick HASH 
    $ git revert HASH
</pre>

...are all the same command in Fossil:

<pre>
    $ fossil merge HASH
    $ fossil merge --cherrypick HASH
    $ fossil merge --backout HASH
</pre>

If you think about it, they're all the same function: apply work done on
one branch to another. All that changes between these commands is how
much work gets applied — just one check-in or a whole branch — and the
merge direction.  This is the sort of thing we mean when we point out
that Fossil's command interface is simpler than Git's: there are fewer
concepts to keep track of in your mental model of Fossil's internal
operation.

Fossil's implementation of the feature is also simpler to describe. The
brief online help for <tt>[/help?cmd=merge | fossil merge]</tt> is
currently 41 lines long, to which you want to add the 600 lines of
[./branching.wiki | the branching document]. The equivalent
documentation in Git is the aggregation of the man pages for the above
three commands, which is over 1000 lines, much of it mutually redundant.
(e.g.  Git's <tt>--edit</tt> and <tt>--no-commit</tt> options get
described three times, each time differently.) Fossil's
documentation is not only more concise, it gives a nice split of brief
online help and full online documentation.


<h3 id="hash">2.9 Hash Algorithm: SHA-3 vs SHA-2 vs SHA-1</h3>

Fossil started out using 160-bit SHA-1 hashes to identify check-ins,
just as in Git. That changed in early 2017 when news of the
[https://shattered.io/|SHAttered attack] broke, demonstrating that SHA-1
collisions were now practical to create. Two weeks later, the creator of
Fossil delivered a new release allowing a clean migration to
[https://en.wikipedia.org/wiki/SHA-3|256-bit SHA-3] with
[./hashpolicy.wiki|full backwards compatibility] to old SHA-1 based
repositories.

In October 2019, after the last of the major binary
package repos offering Fossil upgraded to Fossil 2.<i>x</i>,
we switched the default hash mode so that from
Fossil 2.10 forward, the conversion to SHA-3 is fully automatic.
This not
only solves the SHAttered problem, it should prevent a reoccurrence of
similar problems for the foreseeable future.

Meanwhile, the Git community took until August 2018 to publish
[https://git-scm.com/docs/hash-function-transition/|their first plan]
for solving the same problem by moving to SHA-256, a variant of the
[https://en.wikipedia.org/wiki/SHA-2 | older SHA-2 algorithm].  As of
this writing in February 2020, that plan hasn't been implemented, as far
as this author is aware, but there is now
[https://lwn.net/ml/git/20200113124729.3684846-1-sandals@crustytoothpaste.net/
| a competing SHA-256 based plan] which requires complete repository
conversion from SHA-1 to SHA-256, breaking all public hashes in the
repo. One way to characterize such a massive upheaval in Git terms is a
whole-project rebase, which violates
[https://blog.axosoft.com/golden-rule-of-rebasing-in-git/ | Git's own
Golden Rule of Rebasing].

Regardless of the eventual implementation details, we fully expect Git
to move off SHA-1 eventually and for the changes to take years more to
percolate through the community.

Almost three years after Fossil solved this problem, the
[https://sha-mbles.github.io/ | SHAmbles attack] was published, further
weakening the case for continuing to use SHA-1.

The practical impact of attacks like SHAttered and SHAmbles on the
Git and Fossil Merkle trees isn't clear, but you want to have your repositories
moved over to a stronger hash algorithm before someone figures out how
to make use of the weaknesses in the old one. Fossil has had this covered
for years now, so that the solution is now almost universally deployed.

<hr/>

<h3>Asides and Digressions</h3>

<i><small><ol>
    <li><p>[./mirrorlimitations.md|Many
    things are lost] in making a Git mirror of a Fossil repo due to
    limitations of Git relative to Fossil. GitHub adds some of these
    missing features to stock
    Git, but because they're not part of Git proper,
    [./mirrortogithub.md|exporting a Fossil repository to GitHub] will
    still not include them; Fossil tickets do not become GitHub issues,
    for example.

    <li><p>The <tt>fossil-scm.org</tt> web site is actually hosted in
    several parts, so that it is not strictly true that "everything" on
    it is in the self-hosting Fossil project repo. The web forum is
    hosted as [https://fossil-scm.org/forum/|a separate Fossil repo]
    from the [https://fossil-scm.org/home/|main Fossil self-hosting
    repo] for administration reasons, and the Download page content
    isn't normally synchronized with a "<tt>fossil clone</tt>" command unless
    you add the "-u" option.  (See "[./aboutdownload.wiki|How the
    Download Page Works]" for details.)
    Chat history is deliberately not synced as
    chat messages are intended to be ephemeral.
    There may also be some purely
    static elements of the web site served via D. Richard Hipp's own
    lightweight web server,
    <tt>[https://sqlite.org/althttpd/|althttpd]</tt>,
    which is configured as a front end to Fossil running in CGI mode on
    these sites.

    <li><p>That estimate is based on pricing at Digital Ocean in
    mid-2019: Fossil will run just fine on the smallest instance they
    offer, at US $5/month, but the closest match to GitLab's minimum
    requirements among Digital Ocean's offerings currently costs
    $40/month.

    <li><p>This means you can give up waiting for Fossil to be ported to
    the PDP-11, but we remain hopeful that someone may eventually port
    it to [https://en.wikipedia.org/wiki/Z/OS|z/OS].

    <li><p>"Why is there all this Tcl in and around Fossil?" you may
    ask. It is because D. Richard Hipp is a long-time Tcl user and
    contributor. SQLite started out as an embedded database for Tcl
    specifically. ([https://sqlite.org/tclsqlite.html | [Reference]])
    When he then created Fossil to manage the development of SQLite, it
    was natural for him to use Tcl-based tools for its scripting, build
    system, test system, etc. It came full circle in 2011 when
    [https://www.reddit.com/r/programming/comments/fwrx5/tcl_and_tk_move_away_from_cvs_to_fossil/
    | the Tcl and Tk projects moved from CVS to Fossil].

    <li><p>A minority of the pieces of the Git core software suite are
    written in other languages, primarily Perl, Python, and Tcl. (e.g.
    <tt>git-send-mail</tt>, <tt>git-p4</tt>, and <tt>gitk</tt>,
    respectively.)  Although these interpreters are quite portable, they
    aren't installed by default everywhere, and on some platforms you
    can't count on them at all. (Not just Windows, but also the BSDs and
    many other non-Linux platforms.) This expands the dependency
    footprint of Git considerably. It is why the current Git for Windows
    distribution is 44.7&nbsp;MiB but the current <tt>fossil.exe</tt>
    zip file for Windows is 2.24&nbsp;MiB. Fossil is much smaller
    despite using a roughly similar amount of high-level scripting code
    because its interpreters are compact and built into Fossil itself.

    <li><p>Both Fossil and Git support
    [https://en.wikipedia.org/wiki/Patch_(Unix)|<tt>patch(1)</tt>
    files], a common way to allow drive-by contributions, but it's a
    lossy contribution path for both systems. Unlike Git PRs and Fossil
    bundles, patch files collapse multiple checkins together, they don't
    include check-in comments, and they cannot encode changes made above
    the individual file content layer: you lose branching decisions,
    tag changes, file renames, and more when using patch files.</p></li>
</ol></i></small>
