blackhole://nilFM

source control under control

the state of git

git is an amazing piece of software for keeping your source code organized and your changes tracked and reversible. Created by Linus Torvalds, the mind behind the Linux kernel, it is the de facto source/version control software used almost everywhere in the industry now. One of the most beautiful things about it is that it is decentralized -- meaning it can be hosted anywhere, and you can copy/change the upstream repository at any time, with no side effects.

If you've heard of Git, you almost certainly heard it in the context of Github. To many people, the two terms are synonymous. Github just happens to be the most popular server used as an upstream source for software repositories. It was created from the ground up in 2008, and 10 years later was purchased by Microsoft. Why is Github so popular? Well, their web interface made many aspects of collaborating on and managing large software projects more convenient, and it made backing up your code more accessible. It blew BitBucket (created also in 2008 and purchased by Altassian in 2010) out of the water with its interface, ease of use, and features, and it still does. Gitlab, created in 2014, is a strong competitor in this space too, and aquired a lot of new business and users after Github was purchased by Microsoft. But Github still dominates.

I had been using Gitlab to host my projects since the Github buyout by Microsoft in 2018, but I realized that I didn't really trust Gitlab much more than Microsoft (granted, 99% of my personal code is public anyways, but it's more of a principles issue; update 2021-09-18: it turns out the flagship instance at gitlab.com has a number of ethical issues regarding privacy, accessibility, and software freedom) and the reliance of the web interface on Javascript is less than desirable. So the search for a more minimal and DIY solution began. Gogs, Gitea, and the like are pretty plug-n-play, but heavier than what I'm after and use Javascript for the frontend. SourceHut seems like a great platform, but the dependencies are a bit high for my server which shares duties as a general webserver. But, hmm, I seem to remember seeing a minimal self-hosted git interface on kernel.org and other places...

cgit to the rescue

Enter cgit -- an old-school web frontend for git repositories using the CGI protocols and written in C, it is dead-easy to setup, requires no Javascript to run, and (assuming you already have a machine to host your code) puts your projects back under your control.

I found this post (on a github.io page ironically) breaking down how to install and setup cgit on a Raspberry Pi running Alpine Linux, and it was easy enough to adapt it to my own setup on Void Linux.

(2021-10-26: I have now migrated to an Uberspace from my Void Linux VPS, but aside from changing the paths in the lighttpd configuration to reflect a user-scoped installation of cgit from source, the configuration is the same!)

On Void Linux, cgit is easily installable by the package manger:

# xbps-install cgit

And the configuration file at /etc/cgit/cgitrc is pretty straightforward. Here is my setup:

css=/cgit/nilfm.css
logo=/cgit/nilfm_blackHole_96.png
logo-link=https://nilfm.cc
favicon=/cgit/nilfm_blackHole_32.ico
head-include=/usr/share/webapps/cgit/head.html
virtual-root=/git
enable-git-config=1
enable-index-owner=0
enable-commit-graph=1
enable-index-links=1
enable-log-linecount=1
enable-log-filecount=1
#cache-size=512
robots=noindex, nofollow
root-title=nilFM — hack lab
root-desc=black hole server
remove-suffix=1
clone-prefix=https://hacklab.nilfm.cc
mimetype.gif=image/gif
mimetype.html=text/html
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml
about-filter=/usr/bin/lowmd
readme=:README.md
readme=:readme.md
readme=:README
readme=:readme
clone-prefix=https://hacklab.nilfm.cc
section=9
scan-path=/home/nilix/src/9/
section=etc
scan-path=/home/nilix/src/etc/
section=games
scan-path=/home/nilix/src/games/
section=web
scan-path=/home/nilix/src/web/

My custom CSS file is available here for reference. In addition to theming the cgit interface to match the rest of my site, it also includes some media query rules to make the interface mostly usable on mobile (combined with the head-include entry in the cgitrc which just sets the "viewport" meta property to "initial-scale=1"). The about-filter setting tells cgit how to parse README files for displaying them in the about tab of the repository. It points to a shell script which wraps lowdown like so: cat | lowdown to discard the filename argument that would otherwise be passed to it and break everything.

lowdown is vastly superior to the python script md2html which is included with the cgit distribution -- it's fast compiled C with no dependencies, makes no assumptions about CSS styling (letting me handle it myself), and properly handles image links in the markdown source.

My server uses lighttpd, so a quick few lines in /etc/lighttpd/lighttpd.conf expose the CGI interface and cleanup the URLs:

server.modules += ("mod_redirect",
  "mod_alias",
  "mod_cgi",
  "mod_fastcgi",
  "mod_rewrite",
  "mod_alias",)

var.webapps = "/usr/share/webapps/"
$HTTP["url"] =~ "^/cgit" {
  setenv.add-environment += ( "CGIT_CONFIG" => "/etc/cgit/cgitrc" )
  server.document-root = webapps
  server.indexfiles = ("cgit.cgi")
  cgi.assign = ("cgit.cgi" => "")
  mimetype.assign = ( ".css" => "text/css" )
}
url.rewrite += (
  "^/git(.*)$" => "/cgit/cgit.cgi$1",
)

If they aren't already set, give descriptions to each repo by editing the .git/description file in each.

using cgit

After migrating your repositories to the cgit server, anywhere downstream should change the remote url like so (from your local mirror):

git remote set-url origin https://your.srvr/git/reponame

If you clone directly from the cgit instance, the remote will already be set.

To push to the repo, you need ssh access. You will have to change the push remote like so (again, from the local mirror):

git remote set-url --push origin user@your.srvr:/absolute/path/to/the/repo

Then, when you push, you will be asked to supply your SSH password or key passphrase (unless you use a key with no passphrase of course). Worth noting is that with the default settings, cgit doesn't allow you to push to the branch marked HEAD on the server, which, if you keep main checked out on the server, makes it function kind of like a restricted branch on Github. As a shortcut, you can use rsync to push directly to main if you are sure you are the only one modifying the repository. But you will want to avoid this on projects you are collaborating on, and perhaps use a sudoers rule in /etc/sudoers to keep guests on your server from using it:

User_Alias GUESTS = alice, bob, charles
GUESTS ALL = !/usr/bin/rsync

Of course, it goes without saying that you will want to secure your repo directories with proper group permissions or access control lists to keep private repos private and write access given only to who it's meant for.

and ya done

That's really it. cgit lacks dedicated features for issue tracking or a documentation/wiki system, but if you really need them in a form more complex than a docs/ folder or BUGS file, you can either host separate services for them, or, more simply, use dedicated branches or repositories for these features. My cgit instance is hosted at nilfm.cc/git, as you might have guessed from looking at my configs above, and if the setup appeals to you, I encourage you to host an instance yourself!