As I previously indicated, I have recently moved all of my programming projects (and a couple non-programming projects) to self-hosted Fossil repositories. I have previously used mainly Git for my projects, due to my usage of Github and Gitorious for project hosting, with the exception of GSRC, which uses Bazaar, the recommended version control system of the GNU project. I’ve also have had experience with Mercurial, Subversion and CVS, so I have at least some idea of how many version control systems work.
Since almost every project I work on consists of one sole developer, all of these disparate systems largely converge into similar workflows. I primarily switched over to Fossil for the easy self-hosting and integrated wiki and bug-tracking tools, but I quickly found myself at home working with it. Nevertheless, since there are some aspects of it that differ from other VCS’s, I thought I would give an introduction to it. This may be especially useful as a quick primer for people coming from Git, which is perhaps the most different from Fossil.
Since this is just an introduction, I will only cover the information
needed to get up and running into a normal, everyday workflow. As
such, I will not cover any of the special, corner cases or extra
options. In all cases, do check the built in help for each command
since many take optional arguments that I will not explain here
(fossil help [command]
).
The fossil command
Like most systems, Fossil consists of a single command, fossil
.
Unlike most systems, that single command encompasses a wide range of
functionality, from basic version control tasks to running a basic web
server. Nevertheless, its usage will quickly be familiar to you.
Setting up a repository
Creating a new repository
The first thing that we will want to do is to create a repository. As
one might expect, this is done via the fossil new
command. However
there’s a twist: you must specify the name of the repository.
$ fossil new foo.fossil
Now hang on. This has just created a file and it’s not even a hidden
one. Clutter!, you scream. It’s true: Fossil repositories consist of
a single file, which is, in fact, an SQLite
database (the developer of Fossil created SQLite as well). In the
beginning, I was not sure what to do with this file; I disliked having
it sitting among my source files. The recommendation that I’ve seen
and that I would pass on is to instead keep a directory somewhere that
contains all of your .fossil
files. This directory then, for
example, allows the easy back-up of all of your repositories.
So let’s now assume that we will create all Fossil repositories in the
~/fossils
directory:
$ fossil new ~/fossils/foo.fossil
project-id: c17896e4840ecb6d93bb8081f56430a2be8374fe
server-id: 39264b251712a44f63ba756e1b190f44ad6e5885
admin-user: brandon (initial password is "13b63a")
Notice that when the repository is created, a user (with your name) is automatically created and is assigned a password.
Cloning an existing repository
If you wish to clone a repository that already exists, you will not be
surprised to learn that you use the fossil clone
command. As with
fossil new
, you must specify the name of your repository:
$ fossil clone http://zeptodb.invergo.net ~/fossils/zeptodb.fossil
Round-trips: 2 Artifacts sent: 0 received: 510
Clone finished with 477 bytes sent, 869785 bytes received
Rebuilding repository meta-data...
100.0% complete...
project-id: 6a2f6abb93a52fa338a6ae020dc33342574c989e
server-id: 26274af3664a8d191d511c505a18f997d54bc169
admin-user: brandon (password is "c3a421")
If you already have a username and password on the remote repository, you may introduce it in the URL:
$ fossil clone http://user:pass@zeptodb.invergo.net ~/fossils/zeptodb.fossil
Opening the repository
This is a step that is, as far as I am aware, unique to Fossil. Now
that you have a repository on your system, you need to open it
somewhere. Essentially, you are checking out the contents of the
repository in a separate directory. So, first create a directory to
contain the project (I keep my projects in ~/Projects
):
$ mkdir -p Projects/foo
Due to the way Fossil handles branches, which is more akin to systems
like SVN, I also go ahead and create a trunk
directory to hold the
code. So, let’s do that, and then open the repository in there with
fossil open
:
$ mkdir Projects/foo/trunk
$ cd Projects/foo/trunk
$ fossil open ~/fossils/foo.fossil
The result is a directory under version control that is much closer to
what you are used to with other systems. The difference is that it is
linked to a local repository database elsewhere on the system. You
can actually use fossil close
to close the connection to the
database. This does not clear out the directory; all the files will
remain there. It will simply no longer be under version control. I
have not found the occasion to require this.
Configuring a repository
As I mentioned above, the fossil
command even offers basic web
server functionality. In fact, this is the most convenient way to
configure your repository. Simply run:
$ fossil ui
This will launch the web server and it will open a local web page for
your repository. Feel free to explore. For now, we’re just
interested in the Admin
section. First things first: go to the
Users
section, then click on your User ID and finally change your
password. Next, you’ll want to go to the Configuration
section to
set some basic information like your project name and description.
The Settings
section might also have some areas of interest if you
have special needs regarding command configuration; for me the
defaults are normally fine.
Fossil repositories are highly configurable and it is beyond the scope of this tutorial to go into any detail. I find that the defaults are generally sane. Have a look around the settings and read the documentation for more information.
Note that you may also set many settings with the fossil settings
command.
Working with files
Adding new files
Adding new files to the repository is simple: just use the fossil
add
command, which behaves exactly like any other system:
$ fossil add bar.c
ADDED bar.c
(Re)moving files
Moving or removing files works a bit differently than you might expect. Either one of these commands simply changes the references in the database, however they do not modify the actual file system. This means that you need to follow up the fossil commands with another command to do the actual action.
$ fossil mv bar.c baz.c
$ ls
bar.c
$ mv bar.c baz.c
$ fossil rm baz.c
$ ls
baz.c
$ rm baz.c
Checking the current status
Once you’ve added some files or made some changes, you’ll want to see
what the current status in the repository is. This is accomplished
with the fossil changes
command:
$ touch foo.c bar.c baz.c
$ fossil add *.c
$ fossil changes
ADDED bar.c
ADDED baz.c
ADDED foo.c
Viewing changes
You may view the changes on a file using either the fossil diff
or
the fossil gdiff
commands. The former uses an internal diff
mechanism, while the other allows you to select a graphical diff
application (set up in the Settings section of the web interface or
via the fossil settings
command). Normally, this compares a file
against its last checked-in version, however you may select other
versions using the --from
and --to
arguments.
Committing changes
Now that you’re done making changes, you want to commit them. This is
done with fossil commit
, which works much the same as in other
systems:
$ fossil commit -m 'first commit'
You can, of course, only commit a limited sub-set of changed files if you would like:
$ fossil commit -m 'first commit' foo.c
If you are working from a clone of a remote repository, and you have sufficient access rights on that repository, Fossil will by default behave in a similar manner to CVS by auto-syncing your changes with the remote server. Thus, you commits will automatically be pushed to the remote server. This may be turned off in the settings.
Reviewing commits
You can look at a log of past commits using the fossil timeline
command:
$ fossil timeline
22:22:16 [dd33da8b57] *CURRENT* first commit (user: brandon tags: trunk)
22:05:09 [9ec5208d2a] initial empty check-in (user: brandon tags: trunk)
Syncing your repository
Fossil supports the usual push
and pull
operations for
synchronizing your local repository with the remote upstream repo.
Additionally, there is the handy sync
command, which is
equivalent to running both a push
and a pull
at the same time.
Check-ins
(note: in Fossil, one primarily refers to "check-ins", where in other systems one might talk about "revisions" or "commits")
As with Git, Fossil check-ins are referred to by an SHA1 hash. For commands that require the specification of a particular check-in, you may refer to one by the first four or more characters of the hash.
Tags
You can add a tag to a check-in using the tag
command. Note that,
unlike in Git, you must explicitly specify the check-in by its hash.
So to add a tag called "v1.0":
$ fossil tag add v1.0 9ec520
You can then use that tag name in place of the hash of the check-in.
You can view a list of all existing tags via the tag list
command.
$ fossil tag list
v1.0
Finally, you can easily remove a tag from a check-in with tag
cancel
:
$ fossil tag cancel v1.0 9ec520
Some tags (actually, more precisely, "properties") are automatic. For example, the most recent check-in carries the tag "tip".
Branches and Forks
Here we need to be a bit more careful due to some differences in terminology between Fossil and other version control systems. In Fossil, forking in particular takes on a different meaning. Effectively, on a technical level, forking and branching are the same: they both result in multiple "leaf" commits, or, in other words, multiple parallel tips. The difference is in the intent. Branches are desirable and represent parallel development, such as on large new features that are not ready to be merged into the trunk yet. Forks on the other hand, arise when multiple developers are working on the same code base but have not merged their work yet.
Creating a branch
Branches are created with the branch new
command. Note that you
must specify a check-in as its basis:
$ fossil branch new experimental tip
This will create a new branch called "experimental" based on the current tip.
For Git users, the next step will be unfamiliar. In Git, branching is, as they say, cheap. You can create and switch between branches quickly and easily. In Fossil, you use a workflow more similar to that of, for example, Subversion, in which you keep your branches in separate directories:
$ cd ..
$ mkdir -p branches/experimental
$ cd branches/experimental
$ fossil open ~/fossils/foo.fossil
$ fossil checkout experimental
You may then proceed to edit files and commit; all check-ins will be added to the newly created "experimental" branch.
Merging
Merging a branch back into trunk is simple:
$ cd ../../trunk
$ fossil merge experimental
If the current branch has a fork, you can simply call the merge
command without specifying a version. This will attempt to resolve
the fork and merge the disparate tips.
Web interface
I will only briefly introduce some key features of the web interface. These features are also accessible from the command line, however it is far more convenient to use the web interface to interact with them.
Wiki
Your Fossil repository contains a built-in wiki that keeps all pages under version control. To create a new wiki page, simply go to the Wiki section of the page and click on "Create a new wiki page". The wiki syntax is mainly a reduced set of HTML, with some extra simplified formatting markup for common tasks.
For example, paragraphs are simply separated by line breaks. Lists are created by putting a ‘*’ (unordered) or ‘#’ (ordered) character at the start of the line, surrounded by two spaces on either side:
This is a list:
* item
* item
You can create hyperlinks using square brackets. Using this, you can link to other wiki pages by name:
[foo|Link to the Foo wiki page]
[foo]
[http://brandon.invergo.net|Brandon's Page]
You can use the <nowiki>
tag to turn off wiki formatting for a block
of text. Furthermore, the <verbatim>
tag works like a combination
of the HTML tag <pre>
and the <nowiki>
tag, for producing
pre-formatted text.
When you create a new repository, you should at least edit the wiki home page. This is a special page that is accessed via the "[project] wiki home page" link on the Wiki page. This allows you to edit the landing page that people see when they first visit your repository.
There is also another special type of wiki page called an Event. These wiki pages show up in the Timeline and can be used as a version-controlled project blog, for example to announce releases. In addition to adding textual information, you can add tags to the event and give it a special background color to make it stand out in the timeline.
Tickets
Fossil contains a built-in bug tracking system, which is found under the Tickets section of the web interface. There you will find a link to create a new ticket or to get a list of all tickets. The bug tracker’s basic functionality should be familiar to anyone who’s used such a system in the past so I will not go into detail.
Note that you can refer to check-ins in a bug report (and vice
versa) by specifying the check-in/bug number in brackets
(i.e. [9EC520]
).
Documentation
Fossil has a feature to allow any documentation files contained under
version control to be viewed from the web interface. Simply point
your browser to <webpage_root>/doc/<check-in>/<page>
. You can
specify any check-in, allowing you to see the documentation as it was
at different points in time. If the file is contained in a
sub-directory of the repository, include it in the URL after the
check-in ID (<webpage_root>/doc/<check-in>/<sub-directory>/<page>
)
Summary
As you can see, many of the familiar commands from other version control systems are available. In fact you could probably get up and running with Fossil rather quickly on your own. Nevertheless, hopefully this brief introduction will be useful to you as you become more comfortable with Fossil.
Further reading
I highly recommend reading through the documentation on the Fossil website. In particular, I recommend reading the detailed explanation of the concepts behind the system. I also suggest reading the section on Branching, Forking, Merging and Tagging for a more in-depth discussion on the topic.
Finally, a full-length book on Fossil is freely available and gives a nice introduction to the workflow and a more in-depth overview of the web interface.