github.com/troglobit / digit

Display GIT, a web interface for git

Commit log
6f14311 ⎇ mainRefresh screenshots for the 1.1 interface Joachim Wiberg 25 days ago
a73851e 🏷 1.1Stop iOS Safari inflating code and diff text Joachim Wiberg 25 days ago
ff62e89 Serve /favicon.ico Joachim Wiberg 25 days ago
213b268 Frame the file views and unify the file-actions menu Joachim Wiberg 25 days ago
71cf00d Close the branch dropdown on outside click too Joachim Wiberg 25 days ago
5b981d2 Show tag and branch decorations next to commits Joachim Wiberg 25 days ago
04e6992 Drop stray leading blank line from rendered diffs Joachim Wiberg 25 days ago
6dfc258 Redesign the commit view for mobile and clarity Joachim Wiberg 25 days ago
d42bced Add TODO to proxy remote README images (camo-style) Joachim Wiberg 25 days ago
595dcb7 Collapse repo page tools behind a hamburger on mobile Joachim Wiberg 25 days ago

Digit — Can You Dig It?

License Release Build & Check Vulnerability Scan

Digit (display git) is a fast, simple web frontend to your git repositories, made to resemble other popular interfaces.

  • Browse repos, files, trees, and commits
  • Mirror-tree aware: repos nested host/org/repo.git group per org
  • File tree view with mode, size, and per-directory readmes
  • Blame view with per-commit line groups
  • Commit log with full diff output, and message search
  • Patch view, append .patch to any commit URL
  • Tarball and zip downloads of any branch or tag
  • Read-only clone over smart HTTP, with a GitHub-style clone menu
  • Atom and RSS commit feeds, per repo and site-wide
  • Tag and branch listing
  • Syntax highlighting, line anchors with visual range marks
  • Keyboard shortcuts for commit and log navigation (press ? for the list)
  • GitHub Markdown rendering, with emoji, tables, alerts, and inline images
  • Readme quick-links: license, contributing, code of conduct, security
  • Templated HTML (fully customizable)
  • Dark & Light mode, auto by default with a navbar toggle
  • Configurable navbar, per-repo upstream and website links
  • Built-in caching: ETag revalidation, immutable hash-pinned URLs

Screenshots

Repo overview
Repo overview
Tree view
Tree view
Visual line marks
Visual line marks
Repo viewer
Repo viewer

Configuring

Digit looks for config.yaml in the current directory, falling back to /etc/digit.yaml; use --config <path> to point elsewhere.

repo:
  scanPath: /srv/git
  readme:
    - README.md
    - README
  mainBranch:
    - main
    - master
  ignore:
    - foo
  unlisted:
    - private-repo
dirs:
  templates: ./templates
  static: ./static
meta:
  favicon: favicon.svg
  title: Digit
  description: Explore available Git repositories
  syntaxHighlight: default
features:
  blame: true
  archive: true
  feeds: true
  clone: false
  search: false
nav:
  home: https://example.com
  help: https://github.com/troglobit/digit
  links:
    - name: GitHub
      url: https://github.com/example
server:
  name: git.example.com
  ssh: git@git.example.com
  host: 127.0.0.1
  port: 3000
Field Description
repo.scanPath Directory containing repos, nested up to host/org/repo.git
repo.readme Readme filenames to look for (first match wins)
repo.mainBranch Branch names to try as default branch
repo.ignore Repos to exclude entirely (404); * globs one path segment
repo.unlisted Repos to hide from the index (still accessible by URL); globs too
dirs.templates Path to custom Go html/template files
dirs.static Path to custom static assets (CSS, images)
meta.syntaxHighlight Client-side syntax highlighting (highlight.js); empty = disabled
features.blame Blame view; disable to save CPU on large files (default on)
features.archive Tarball downloads; disable to save bandwidth (default on)
features.feeds Atom/RSS feeds: /atom, /repo/atom[/ref], rss alike (default on)
features.clone Read-only smart HTTP clone (default off)
features.search Log search, case-insensitive and verbatim (default off)
nav.home Navbar brand link, e.g. your homepage (default /)
nav.help Navbar help link (default: digit's project page)
nav.links Extra navbar links (name + url), right-aligned
server.name Public host name, for absolute feed links and clone URLs
server.ssh SSH clone prefix, e.g. git@git.example.com; adds SSH to the menu
server.host Listen address (default 127.0.0.1 — see reverse proxy below)
server.port Listen port (default 3000)

Mirrored repositories

Repos may live directly in scanPath or nested like a mirror tree, e.g. <host>/<org>/<repo>.git, and both styles can be mixed. Nested repos get URLs matching their path (/github.com/troglobit/mg/), the overview groups them per org, and every level has its own index page (/github.com/, /github.com/troglobit/). With more than 20 repos the front page lists orgs with repo counts instead of every repo.

To hide a whole org, glob it:

repo:
  ignore:
    - github.com/some-vendor/*

Per-repository metadata

The repo overview and summary pages show the classic gitweb description file, so set it in each repo:

$ echo "Fast init for Linux systems.  Cookies included." > /srv/git/finit.git/description

To link a repo to its upstream, e.g. the GitHub project it mirrors, or to its website, set the digit.upstream and digit.website keys in the repo's git config. They show up as upstream ↗ and website ↗ in the repo navigation:

$ git -C /srv/git/finit.git config digit.upstream https://github.com/troglobit/finit
$ git -C /srv/git/finit.git config digit.website https://troglobit.com/projects/finit/

Building

After cloning this repo, build a stand-alone binary with:

$ cd digit/
$ make

The Makefile is a thin wrapper around the Go toolchain (go build); make check vets and tests, make fmt formats. No external dependencies beyond the Go toolchain.

At runtime digit requires git to be installed on the server — all repository access shells out to git plumbing commands. This is the same requirement as Gogs, and what keeps CPU usage low: the git binary uses commit-graph and pack index optimizations that pure-Go git libraries lack.

Installation

make install installs the binary, a sample /etc/digit.yaml (an existing one is left untouched), and the bundled systemd service, which runs digit as a restricted git user. prefix, sysconfdir, unitdir, and DESTDIR are honored, for packaging:

$ sudo make install
$ sudo useradd --system --home /srv/git --shell /usr/sbin/nologin git

Point repo.scanPath in /etc/digit.yaml at your repos — they must be readable by the git user, but need not be owned by it: digit marks everything under scanPath as safe.directory for its own git commands, so mirrors synced by another user work out of the box, without tripping git's dubious-ownership check. Then:

$ sudo systemctl daemon-reload
$ sudo systemctl enable --now digit

Cloning

With features.clone enabled, every repo can be cloned read-only over smart HTTP — handy for an office-internal digit:

$ git clone https://git.example.com/finit

Digit proxies the two upload-pack endpoints to git http-backend; push is never routed, so repos cannot be written to. Set server.name and repo pages get a clone menu next to the branch selector, with copyable URLs and a tarball download, plus go-import meta tags so Go vanity imports work.

If the server also runs sshd with git access, set server.ssh to the user@host prefix and the menu offers SSH clone URLs too, built from each repo's real on-disk path.

Logging and crawlers

Under systemd digit detects the journal and drops its own timestamps. Under other init systems, e.g. Finit, start digit with -s/--syslog to log via syslog(3) instead of stderr. Rejected requests are logged with the client address:

client 192.0.2.7: GET /finit/nope: 404

which fail2ban can match to ban scanners and scrapers:

# /etc/fail2ban/filter.d/digit.conf
[Definition]
failregex = ^.*client <HOST>: .*: (404|500)
journalmatch = _SYSTEMD_UNIT=digit.service

Digit also serves a /robots.txt keeping well-behaved crawlers off the expensive endpoints (archive, blame, raw); override it by placing your own in dirs.static.

Running behind a reverse proxy

Digit listens on 127.0.0.1:3000 by default, made to sit behind a TLS-terminating reverse proxy. All generated links are root-relative — the listen address never leaks into any page — so no rewriting is needed. The one requirement is that digit is served at the root of its host: use a dedicated (sub)domain like git.example.com; mounting under a sub-path such as example.com/git/ is not supported.

With nginx:

server {
    listen 80;
    server_name git.example.com;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

With merecat httpd, using virtual hosts:

virtual-host = true

server https {
    port     = 443
    certfile = /etc/letsencrypt/live/example.com/fullchain.pem
    keyfile  = /etc/letsencrypt/live/example.com/privkey.pem

    proxy-pass "/**" {
        host    = "git.example.com"
        backend = "http://127.0.0.1:3000"
    }
}