The Repository Filesystem

When it comes to organizing source code repositories, there are broad similarities — source code in src/, tests in test/ — but no universal standards. Recently I was thinking about this and wondered “What about UNIX?”

Most Linux distributions follow the Filesystem Hierarchy Standard to some extent. The directory names are short and familiar. The structure was even organized around how files change.

What would this look like applied to a project repository? Starting with the usual src/, test/, and doc/ directories, we could add UNIX-like paths:

  • bin/ for executable commands (binaries and scripts)
  • lib/ for shared libraries, such as shared functions for scripts
  • share/ for architecture-independent shared data, such as images
  • etc/ for local configuration
  • var/ for anything that changes
    • var/lib/ for data that persists over multiple executions
    • var/run/ for runtime data like PID files
    • var/log/ for log files
    • var/tmp/ for temporary files and cache
  • opt/ for self-contained directory hierarchies, such as Git submodules or embedded dependencies

This structure has some interesting and potentially useful consequences for how repositories are structured. Everything except var/ should be tracked by version control, and everything in var/ should be excluded from version control.

Since var/ is the only non-version-controlled directory, it is effectively the only “writable” destination for compilation. This means the files in bin/ and lib/ might be merely symlinks or scripts that point to generated files in var/lib/.

In a cloud or container environment, var/ or its subdirectories could be mounted from a separate filesystem.

The etc/ directory is tricky since a project may require temporary configuration files during development that should not be checked in. My thinking is that etc/ should be restricted to things that are normally “checked in” like default configuration values. Local-only config should be under var/. It’s not unheard of for *nix systems to have a var/etc/, so that could work.

Of course, there is no universal standard for *nix filesystems, and no universal agreement on how to implement the standards we have. But as with a lot of things in software, you could do worse than to follow in the footsteps of UNIX.