diff options
Diffstat (limited to 'www/fossil-v-git.wiki')
| -rw-r--r-- | www/fossil-v-git.wiki | 984 |
1 files changed, 984 insertions, 0 deletions
diff --git a/www/fossil-v-git.wiki b/www/fossil-v-git.wiki new file mode 100644 index 0000000..7c64c7f --- /dev/null +++ b/www/fossil-v-git.wiki @@ -0,0 +1,984 @@ +<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 will inevitably +be biased in favor of Fossil purely 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. + +<table style="width: fit-content"> +<tr><th>GIT</th><th>FOSSIL</th><th>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 ↓</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 ↓</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 ↓</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 ↓</a></td> +</tr> +<tr> + <td>Bazaar-style development</td> + <td>Cathedral-style development</td> + <td><a href="#devorg">2.5.1 ↓</a></td> +</tr> +<tr> + <td>Designed for Linux kernel development</td> + <td>Designed for SQLite development</td> + <td><a href="#scale">2.5.2 ↓</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.3 ↓</a></td> +</tr> +<tr> + <td>One check-out per repository</td> + <td>Many check-outs per repository</td> + <td><a href="#checkouts">2.6 ↓</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 ↓</a></td> +</tr> +<tr> + <td>Commit first</td> + <td>Test first</td> + <td><a href="#testing">2.8 ↓</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 ↓</a></td> +</tr> +</table> + +<h3 id="features">2.1 Featureful</h3> + +Git provides file versioning services only, whereas Fossil adds +an integrated [./wikitheory.wiki | wiki], +[./bugtheory.wiki | ticketing & 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/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, to the point that it approximates +"[https://github.com/ | GitHub]-in-a-box." + +Even if you only want straight version control, Fossil has affordances +not available in Git. + +For instance, Fossil can do operations over all local repo clones and +check-out directories with a single command. You can say "<tt>fossil +all sync</tt>" on a laptop prior to taking it off the network hosting +those repos, as before going on a trip. It doesn't matter if those +repos are private and restricted to your company network or public +Internet-hosted repos, you get synced up with everything you need while +off-network. + +You get the same capability with several other Fossil +sub-commands as well, 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/rm|fossil rm], [/help/update|fossil update], +[/help/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. While you cannot undo a commit in Fossil +— [#history | on purpose!] — 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 rely on a +3rd-party service such as GitHub, Fossil is much easier to set up: +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 +depends only on common platform libraries in its default configuration. +To install one of [https://fossil-scm.org/home/uv/download.html | our +precompiled binaries], unpack the executable from the archive and put it +somewhere in your <tt>PATH</tt>. To uninstall it, delete the executable. + +This policy is particularly useful when running Fossil inside a +restrictive container, anything from [./chroot.md | classic chroot +jails] to modern [https://en.wikipedia.org/wiki/OS-level_virtualization +| OS-level virtualization mechanisms] such as +[https://en.wikipedia.org/wiki/Docker_(software) | Docker]. +Our [./containers.md | stock container image] is under 11 MB when +uncompressed and running because it contains nothing but a single +statically-linked binary. + +If you build a dynamically linked binary instead, a Linux +x86_64 build of Fossil drops to under 5 MB on-disk, stripped. +It will depend only on widespread +platform libraries with stable ABIs such as glibc, zlib, and openssl. + +Much the same is true on Windows, where our precompiled static binaries +are distributed inside a ZIP archive containing "<tt>fossil.exe</tt>" +and not a thing else, with a size on-par that of the Linux container +build. There is no "<tt>setup.exe</tt>" to run; just copy it into your +<tt>%PATH%</tt>. + +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. + +Git, by contrast, takes 25 MiB on Ubuntu 26.04 across 940 files. +That doesn't count platform facilities like the POSIX shell and script +interpreters its full feature set requires. A fairer comparison to +Fossil's single static binary container is the Docker Hardened Image for +[https://hub.docker.com/hardened-images/catalog/dhi/git |Git 2.x on +Alpine], which presently weighs in at 36.3 megs unpacked and 607 files, +if you count all the <tt>busybox</tt> symlinks which would otherwise be +separate binaries on a more traditional Linux system. Worst of all are +the "Git for Windows" packages where they end up needing to ship a large +yet nerfed Linux-like userland to support Git's many loosely coupled +pieces, approaching a hundred megs and thousands of files. + +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 relatively bare-bones 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], which wraps Git in enough +features to bring it to a rough (very rough) parity with Fossil. While +it is certainly ahead in some areas — automation comes to mind — it must +be noted that GitLab's own forums are on Discourse, not self-hosted as +with Fossil. You may then argue that Discourse is superior to the Fossil +forum feature, but this merely brings us back to another of Fossil's +advantages: when the posts are part of the repo, you can migrate your +entire project to another host merely by standing that repo back up on +other hardware. Choosing to assemble your project hosting from multiple +pieces requires each to have their own backups, their own management +processes, and their own migration strategies. + +Even then, these disparate services do not cooperate at the same level +as in Fossil, where the ability to have a forum post linking to a wiki +article linking to a trouble ticket linking to a commit falls out of the +model nearly for free. These are all internal links, mind, potentially +using nothing but repository artifact hashes, all backed by SQLite's +referential integrity. With something like GitLab, its "internal +references" are tacked on after the fact, not Git repo hashes at all, +and when it comes to external services like Discourse, history tells us +you're storing up tech debt which will come due at some future point in +the form of piles of broken links when one piece or the other needs +changing out. + +Furthermore, GitLab is far more resource hungry even in its +[https://docs.gitlab.com/omnibus/settings/memory_constrained_envs/ | +minimal configuration], hence more costly to run than the equivalent +Fossil setup. [https://hub.docker.com/r/gitlab/gitlab-ce/ | The +official GitLab Community Edition container] currently clocks in at +3.44 GiB, independent of add-ons like Discourse. You can expect it to +cost around 8× as much to host it on a cloud service. Even pared down +to the minimum, there remain the consequences from the difference in +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 example is that it is difficult to find the descendants +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 +going the other direction is difficult enough +that neither native Git nor the big "forge" facilities +like GitHub and GitLab provide this capability short of crawling the +[https://www.git-scm.com/docs/git-log|commit log]. In Fossil, +we can find descendants using a simple SQL query, which then allows +us to see [/timeline?df=release&y=ci|all check-ins since the last release], +as but one example. +Git lets you see "what came before," but 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 +[https://stackoverflow.com/q/3965676 | detached head +state] problem has caused grief for +[https://www.google.com/search?q=git+detached+head+state | +untold millions 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 come down to simple SQL queries 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. + +The ease of querying Fossil data using SQL means that status or +history information about the project under management is easier +to obtain, hence more likely to happen, giving its developers better +situational awareness. +Fossil reports tend to be more detailed and useful. +Compare [/timeline?c=6df7a853ec16865b|this Fossil timeline] +to +[https://github.com/drhsqlite/fossil-mirror/commits/master?after=f720c106d297ca1f61bccb30c5c191b88a626d01+34 | +its closest equivalent in the GitHub mirror]. Judge for yourself: which of those +reports is more useful to a developer trying to understand what happened? + +<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 +[./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 +[https://www.msys2.org/wiki/Home/|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. +[https://docs.gitlab.com/ee/install/install_methods.html#microsoft-windows | +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. + +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: + + * <b>Personal engagement:</b> SQLite's developers know each + other by name and work together daily on the project. + + * <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]. + + * <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 equivalents are its unique + [/help/bundle|bundle] and [/help/patch|patch] features, which require 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. + + * <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.] + + * <b>Sync over push:</b> Explicit pushes are uncommon in + Fossil-based projects: the default is to rely on + [/help/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]." + + * <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 send selected change sets to each other. + + * <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. + + * <b>Identical clones:</b> Fossil's autosync system tries to + keep each local clone identical to the repository it cloned + from. + +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. + +By contrast, "…[https://docs.github.com/en/get-started/quickstart/contributing-to-projects|forking is +at the core of social coding at GitHub]". As of June 2026, +[https://github.com/search?q=is:public|Github hosts 324 million distinct +software projects], most of which were created by forking a +previously-existing project. Since this is +[https://www.griddynamics.com/blog/number-software-developers-world | +~11× the number of developers in the world], it beggars belief that +most of these forks are still under active development. The vast bulk +of these must be abandoned one-off efforts. This is part of the nature +of bazaar style development. + +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. +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 over-correct 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 other's names. These thousands are responsible +for producing roughly 73× more code than is in SQLite. (32.0 +[https://en.wikipedia.org/wiki/Source_lines_of_code|MLOC] vs. 0.44 MLOC +according to [https://github.com/boyter/scc | scc].) 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 six programmers, and 62% 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. + +When choosing your DVCS, we think you should ask yourself whether the +scale of your software configuration management problems is closer to +those Linus Torvalds designed Git to cope with or whether your work's +scale is closer to that of SQLite, for which D. Richard Hipp designed +Fossil. 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. + +Fossil works well for projects several times the size of SQLite, +[https://core.tcl-lang.org/tcl/ | such as Tcl], with a repository over +twice the size and with many more core committers. + + +<h4 id="branches">2.5.3 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. + +While a common usage pattern in Git is to only synchronize +a single branch — <tt>git pull upstream feature/branch</tt> — instead +of all refs, Fossil does not give you a choice; it +syncs the entire DAG or nothing. 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's focus on individual branches +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: such extreme visibility does not scale +well. Contrast Fossil, which was written for the cathedral-style SQLite project +and its 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 an SQLite database +file which is normally stored outside the working checkout directory. You can +[/help/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] via +its worktree feature, tutorials continue to teach the style of having +one working directory only. Git can even fight you on this, as when +working with a forked repository; it is best to have independent clones +of the upstream and your fork, to allow separate "remote" lists and +such. This can result in two working directories but each having a +captive repo clone each, which isn't in the spirit of <tt>git +worktree</tt> at all. Yet, it beats the alternative, which then +highlights a gap in the model of diverging and re-converging forks. +Ideally, Git would let you create one of these forks as a worktree while +maintaining a strong separation between your fork and the upstream repo, +but it ends up being too much hassle to bother with. + +There are +[https://duckduckgo.com/?q=git+worktree+problem | several known +problems] with the single worktree style, ones 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 this incidental mess +is not a factor. + +Like Git, Fossil has an [/help/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/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/merge | fossil merge]</tt> is +currently 50 lines long, to which you want to add the ~800 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 approaching 1400 lines as of this writing, 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 +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 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]. That is +now technically implemented in the sense that <tt>git init +--object-format=sha256</tt> exists, but note well: this is not only an +optional setting, Git forge support is mixed, most notably +[https://github.com/GitoxideLabs/gitoxide/issues/281 | lacking in +GitHub], plus also BitBucket and others. This is doubtless because of +this warning in the latest ([https://git-scm.com/docs/git-init/2.54.0 | +as of this writing]) <tt>git init</tt> docs: + +<blockquote>Note: At present, there is no interoperability between +SHA-256 repositories and SHA-1 repositories.</blockquote> + +Although we are now in the <i>tenth year</i> of this situation, there +remains hope that Git will manage to make the transition without taking +the full decade: the +[https://www.deployhq.com/blog/git-3-0-on-the-horizon-what-git-users-need-to-know-about-the-next-major-release +| latest plan] is that Git 3.0 will finally <i>(finally!)</i> switch to +SHA256 by default, forcing the issue. Given the track record, we are +taking a "show me" stance on this claim. + +Always remember, attacks only get better, never worse. +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 <i>before</i> someone figures out how +to make use of the weaknesses in the old one. Fossil's solution is long +since [https://repology.org/project/fossil/versions | 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>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 MiB but the current <tt>fossil.exe</tt> + zip file for Windows is 2.24 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] — unified diff formatted output — for accepting 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. The + [./patchcmd.md | <tt>fossil patch</tt> command] + also solves these problems, but it is because it works like a Fossil + bundle, only for uncommitted changes; it doesn't use Larry Wall's + <tt>patch</tt> tool to apply unified diff output to the receiving + Fossil checkout.</p></li> +</ol></i></small> |
