I have most of my repositories hosted on GitHub and Sourcehut using Git. I also tried Mercurial on Sourcehut. My general impressions are:
-
Git is the most popular option and the de-facto standard if you want any collaboration happening. At the same time this is the least user-friendly option for the workflow I have. Currently I'm trying legit that offers a better UI.
-
Mercurial is very similar to Git, the most advantageous feature to me is the ability to have multiple "detached heads" ("bookmarks" in Mercurial). Mercurial is a literal DAG where you can visit different leafs ("heads") without any problems. It also has a somewhat nicer user interface. But it is too similar to Git and doesn't have enough benefits to switch.
I usually have these cases for VCS:
-
Personal repositories where I'm the only committer.
-
Repositories with rare contributions where the code is a library that can be useful to others.
-
Work.
I think that for cases (2) and (3) I will still have to use Git because of GitHub (or whatever the Git forge with "pull request workflow" is the most popular right now). But for personal things it makes sense to use something I host on my own server.
Both Git and Mercurial are somewhat expensive in terms of hosting because Git is a relatively large program with many files and ad-hoc binaries, and Mercurial is a Python application. I think that Fossil is a viable alternative. It is a somewhat unconventional VCS, but it is a very powerful package with version control, wiki, tickets and a powerful history view all in a single binary with a single SQLite database as a storage.
Local Fossil setup
First setup a local repository with fossil init
and follow any advice on setting up a server you find useful. I have made the repository completely private, changed the password for the default user and set up a project name and such things.
Later this local repository will be copied to the server.
Remote Fossil setup
It's time to set up the infrastructure on the server, run all commands as root
.
Install Fossil:
pkg_add fossil
# choose plain, non-static option
Create a user, set up a directory with repositories:
mkdir /var/fossil
useradd -c "Fossil User" -d /var/fossil -s /sbin/nologin -L daemon _fossil
chown _fossil:_fossil /var/fossil/
From the client, copy the initialized database to the server:
scp scripts.fossil alice@greenfork.me:~
On the server, copy and change permissions for the database:
mv /home/alice/scripts.fossil /var/fossil
chown _fossil:_fossil scripts.fossil
Add /etc/rc.d/fossil
service:
#!/bin/ksh
daemon="/usr/local/bin/fossil"
daemon_user="_fossil"
daemon_flags="server /var/fossil --errorlog /var/fossil/errorlog \
--localhost --repolist --port 1736 --https"
daemon_logger="daemon.info"
. /etc/rc.d/rc.subr
# This service may have erroneous process name, as in ps(1), it must
# be the same as "$daemon $daemon_flags", otherwise rc will fail to
# start it. If this is a problem, the option below may help.
pexp="$daemon server /var/fossil .*"
rc_reload=NO
rc_bg=YES
rc_cmd $1
-
Since we are running through a proxy, options
--localhost
and--https
must be specified. -
The command in ps(1) is mangled and is not exactly like the one specified in
daemon_flags
, so we use thepexp
hack to not confuse rc(8).
Start it and enable:
rcctl start fossil
rcctl enable fossil
Expose to the internet
Use the Setup Mycorrhiza on OpenBSD article in order to expose this service to the internet, right now it only runs locally.
Make sure to ignore any overriding of Content-Security-Policy
in relayd.conf(5), let Fossil serve its own header. If you have Referrer-Policy
set to no-referrer
, submitting forms will not work, the value should be changed to same-origin
as the next most secure header.
Security audit
Follow to Admin -> Security-Audit and go through any recommendations present there. If there are any problems, be sure to also check /test_env
for any suspicious values.
Connect local and remote
We can now add the default remote to our local repository and synchronize them:
fossil remote https://grfork@fossil.greenfork.me/scripts
fossil sync
Make sure to set grfork@
to your username.
And that's it! You should have a working Fossil server.
Bonus: create another repository
Now, when we have a working repository, we can use it to create another one. The already created repository will serve as a template for a new one. The only thing left to do is to set a password for the admin user since it is not transferred from a template. And to set proper Unix permissions.
fossil init --template /var/fossil/scripts.fossil --admin-user grfork \
--project-name "dotfiles" --project-desc "Personal dot files" \
/var/fossil/dotfiles.fossil
fossil user password grfork ******** --repository /var/fossil/dotfiles.fossil
chown _fossil:_fossil /var/fossil/dotfiles.fossil
Now you can access it in the list of all repositories and you are ready to clone it:
fossil clone https://grfork@fossil.greenfork.me/dotfiles