Moving from Git to Fossil
This article describes the procedure I used to convert my git repositories to Fossil. Git is a perfectly fine source code manager; it was designed for large projects that have hundreds of contributors, like the Linux kernel. But for small projects git is a bit of overkill, and there are number of things that I find annoying about it.
The command line interface can be very confusing and counter-intuitive. In fact, there’s even a git parody web site that generates random man pages that are just as obscure as the real thing.
The staging area adds extra complexity that I don’t need. I can understand why Linus would want to use it for the kernel, because it allows cherry-picking of contributor patches before a commit (among other things). But for small projects like mine, with no other contributors, it’s an extra step that just adds confusion. The terminology is inconsistent, too: the staging area is actually called an index, but if you want to do a diff between what’s in your work area and the index, you use
git diff --cached
instead of--index
like you’d expect.Heaven help you if you try to undo something in git that was a mistake. To address this, there are specialized web pages out there that cover all the possible undo commands, and of course none is intuitive. For example, to undo a
git add
, you would think something likegit remove
or maybegit subtract
, would make sense, but no: you have to do agit reset
.
Fossil is, in my opinion, more suitable for small projects than git, and has a number of attractive features:
It consists of a single executable that implements everything you’d need: a command line interface, a UI that lets you use a browser to examine repositories, and a server. This replaces all of the equivalent git commands, the cgit server, and the gitk repository browser.
It supports other non-git features, e.g., a wiki and tickets.
A repository consists of a single file (actually an SQLite file with the extension
.fossil
), separate from a checked-out copy of the respository’s files. This means that a repository can easily moved around, and you can have multiple checkouts of the same repository.Automatic syncing with a remote repository is enabled by default, so no need for an easily forgotten extra “push” step.
The user interface is well-designed and relatively easy to understand.
I already have a number of Git projects in local repositories. These have remote repositories on my own server, and mirrors on Github. So there are several steps in converting such a Git project into an equivalent Fossil project:
- Import a Git project into Fossil
- Copy the Fossil project to the server
- Install Fossil as a server
- Make a Github mirror
Import a Git project into Fossil
It’s helpful (but not necessary) to make a single directory
for storing your repository files. In this example,
we create a directory fossils
for this purpose.
mkdir ~/fossils
Then move to the directory of the git project, and export it. Note that I used “master” instead of “–all” to prevent problems later when pushing “ref” branches to Github:
cd ~/gits/myproject
git fast-export master | \
fossil import --git --rename-master trunk ~/fossils/myproject.fossil
Move to the fossils directory, create a checkout directory, and check out a copy of the project:
cd ~/fossils
mkdir myproject
cd myproject
fossil open ../myproject.fossil
For fun, run the UI to examine the project in a browser:
fossil ui
Try clicking on the Timeline link and then clicking on a check-in number.
This should show you a diff for that check-in. If your browser produces an error complaining
about an SQL injection attempt, try clearing the browser cookies for localhost
and reloading the page.
Copy the Fossil project to the server
Take a look at the document
How to Configure a Fossil Server,
and the Repository Prep section in particular. At a minimum, you’ll want make
some changes to your repository before uploading it. Do this by running fossil ui
on your repository, and then making the following changes:
- Change password for the Setup user (under Admin / Users).
- Make the repository private (under Admin / Security Audit).
- Change the Canonical Server URL (under Admin / Configuration). It is probably not obvious what this should be, so you can postpone changing this until you have Fossil running as a server; see below.
If you do make a repository private, anonymous users will no longer be able to log in. To re-enable this capability later, set the following privileges in Admin / Users:
- anonymous: hz (Hyperlinks + Download Zip)
- nobody: gjorz (Clone + Read Wiki + Check-Out + Read Ticket + Download Zip)
Log into the server as your normal user and create a directory for storing repositories, as you did for your local machine.
mkdir ~/fossils
On the local machine, copy the project repository file to the server:
scp ~/fossils/myproject.fossil user@myserver.example.com:fossils
Back on the server, check out a copy of the uploaded repository and examine it. This will ensure that when you install the fossil server later, it will be able to see this repository. This is similar to what you did earlier on the local machine:
cd ~/fossils
mkdir myproject
cd myproject
fossil open ../myproject.fossil
fossil info
fossil all info # should show same thing as as fossil info
Install Fossil as a server
I installed Fossil as a server behind an Apache reverse proxy on Ubuntu Server 22.04. I used the reverse proxy to ensure that Fossil would use SSL. I had previously tried running Fossil without the proxy, but there were two catches:
In order to use my server’s certbot certificates, Fossil needed to run as root.
But I wanted to run Fossil as my ordinary user, not root, so that it would be restricted to my personal repositories, and not have system-wide access.
So in order to use SSL and restrict Fossil to my personal repositories, I needed a reverse proxy.
(Note: run all of the following commands as root.)
First, create the file /etc/systemd/system/fossil.service
with
these contents, replacing USER with your actual user name, replacing
example.com
with your actual server name, and replacing /home/USER/fossils
with the actual location of your repository files.
[Unit]
Description=Fossil user server
After=network-online.target
[Service]
WorkingDirectory=/home/USER/fossils
ExecStart=/usr/local/bin/fossil server --baseurl https://example.com/fossil/ /
Restart=always
RestartSec=
User=USER
Group=USER
[Install]
WantedBy=multi-user.target
Make the file executable using:
chmod +x /etc/systemd/system/fossil.service
Start the fossil service and check its status:
systemctl enable fossil
systemctl daemon-reload
systemctl start fossil
systemctl status fossil
Enable the Apache proxy module if it is not already enabled:
a2enmod proxy_http
Tell Apache how to redirect the URL /fossil
from your base web site URL to
Fossil. Do this by adding a single line to the <VirtualHost *:443>
section of your Apache site configuration. If you used
Let’s Encrypt to obtain your SSL certificates, this configuration file might be at
/etc/apache2/sites-enabled/000-default-le-ssl.conf
. The line you
need to add looks like this:
ProxyPass /fossil/ http://127.0.0.1:8080/ upgrade=websocket
Restart Apache and check its status:
systemctl restart apache2
systemctl status apache2
If all went well, you should be able to visit the Fossil server by going to this URL in a browser:
https://www.example.com/fossil/
which should show you a list of your repositories. This assumes you have performed some actions on those repositories so that they’ll show up when you use the following command:
fossil all info
From the man page for fossil all:
Repositories are automatically added to the set of known repositories when one of the following commands are run against the repository: clone, info, pull, push, or sync. Even previously ignored repositories are added back to the list of repositories by these commands.
Make a Github Mirror
The official Fossil document on how to make a Github mirror is good, but I did things slightly differently, because I use ssh instead of https to update my Github projects, and because I use a dedicated mirrors directory outside of my fossils directory.
Here’s what I did to create a mirror for the myproject
repository.
(I performed these actions on my server, but you could also perform
them on your local machine if you don’t have a remote repository.)
On Github, create a blank Github repository myproject.mirror
; the .mirror
distinguishes
it from a normal repository that is updated from git. Do not add a README
file or a license; you want an entirely empty project.
On your server, create a mirror directory (if it has not already been created):
mkdir ~/mirrors
In a Fossil checkout of myproject
, run this command to create a git mirror
on your server (or local machine) and update the mirror on Github:
fossil git export ~/mirrors/myproject --autopush \
git@github.com:user/myproject.mirror.git
Note that I didn’t specify a password; that’s because Github has my ssh key, allowing me to push changes to it without a password.
In the future, the --autopush
option isn’t necessary to update the mirrors;
simply do thi:
fossil git export
Use this command to check on the status of the mirror:
fossil git status
Tweak your project
Now that you have your project on your server, it’s time to go back and fix the setting for its Canonical Server URL. Visit the Fossil server in your browser:
https://www.example.com/fossil/
Then click on the project you just uploaded. In Admin / Configuration, take a look at the suggested value for Canonical Server URL. Copy this value into the entry field, and click on the Apply Changes button at the bottom of the page.
Back on your local machine add the new remote repository to your local repository, so that the two will always remain in sync:
cd ~/fossils/myproject
fossil remote ssh://example.com/fossils/myproject.fossil
Check that the remote connection is working:
fossil update