git for MontaukOS
Upstream git/git, pinned at v2.39.5
(upstream/, submodule). Reports itself as 2.39.5-montauk.
Installs as a system program, not an app bundle:
| Path | What |
|---|---|
0:/os/git.elf |
the binary (~3 MB stripped) |
0:/os/git/share/git-core/templates |
git init skeleton |
0:/os/git/etc/gitconfig |
system config (not created by the install) |
make -C dev-vcs/git # build
make -C dev-vcs/git install # -> MontaukOS/programs/bin/os/
make ports from the MontaukOS tree does both (git is in the top-level
Makefile's SELF_INSTALL_PORTS).
Status
First run on hardware: git started, died at exit 128, printed nothing. Two
bugs, both outside git and both now fixed -- needs a retest:
sanitize_stdfds()opened/dev/null, which MontaukOS does not have, soxopen()died before any command dispatched. That function guards against inheriting closed descriptors, which cannot happen on a system that spawns rather than forks;patches/0002makes it a no-op.- Nothing git wrote with
write(2, ...)ever appeared -- which is why the fatal error was invisible. The libc'sread()/write()passed fd 0/1/2 straight toSYS_READ/SYS_FWRITEas file handles, and the kernel hands out file handles starting at 0, so those numbers named real files. A program's thirdopen()owned "stderr". Fixed in the OS: the kernel no longer allocates handles 0/1/2, and the libc routes them to the terminal.
Second run got as far as git init (works, repository created) and then hit
fatal: detected dubious ownership. That is git's safe.directory check
comparing lstat()'s st_uid against geteuid(); MontaukOS stores no
per-file owner, so it is false for every directory on the system. The port now
answers that check directly -- see compat/montauk-ownership.h, which also
records what has to change when the OS grows real ownership.
Confirmed working on hardware so far: startup, error output, git init, and
quoted arguments. The rest is still only what the build configuration
implies.
What should work
Everything git does inside one process and one filesystem:
init,add,rm,mv,status,diff,commit,log,showbranch,checkout,switch,restore,merge,reset,reverttag,stash,cherry-pick,rebase(the builtin, non-interactive path)cat-file,rev-parse,ls-files,ls-tree,hash-object,fsckconfig,blame,grep,describe,bisectclone/fetch/pushagainst a local path, e.g.git clone 0:/users/dan/repo
What does not work, and why
Anything that starts another process. MontaukOS spawns (SYS_SPAWN); it
has no fork(), no exec() and no pipe(), and a spawned process cannot
inherit a pipe for its stdio. Every git feature built on sub-processes fails
with ENOSYS rather than misbehaving:
- hooks (
pre-commit,commit-msg, ...) -- the samples are installed but never run $EDITOR, sogit commitneeds-mor-F, and interactive rebase andgit add -pare out- the pager (harmless -- output goes straight to the terminal, and
DEFAULT_PAGER=catis compiled in anyway) - aliases that shell out (
!command),git submodule,difftool,mergetool,git gc(it re-runs itself asgit repack)
Network transports. No http://, https://, git:// or ssh://. The
port is built NO_CURL NO_OPENSSL, and the socket shims fail: MontaukOS TCP
lives behind IPC handles rather than file descriptors, and DNS resolution is
inside the kernel with no userspace interface. Local paths are the transport.
Symlinks. The VFS cannot create them, so git behaves as if
core.symlinks=false -- a symlink in a tree checks out as a regular file
containing the link target.
File modes. Built NO_TRUSTABLE_FILEMODE, so the executable bit is not
read back from the filesystem; core.fileMode defaults to false.
Threads. NO_PTHREADS, so packing, delta search and git grep are
single-threaded. Correct, just slower.
mmap. NO_MMAP, so pack and index access reads into memory instead of
mapping. Large repositories will be heavier on RAM than on Linux.
Before the first commit
The environment MontaukOS hands a process is empty, so the port sets HOME
itself from the session user (0:/users/<name>) before git reads any config
-- that is what makes --global work. Set an identity:
git config --global user.name "Your Name"
git config --global user.email [email protected]
This is not optional. Left unset, git builds a fallback address from the
session user and the hostname -- and since gethostname() answers montauk,
with no domain in it, git marks the address bogus, appends .(none) and
refuses:
fatal: unable to auto-detect email address (got 'admin@montauk.(none)')
That is stock git behaviour on any host without a domain name, not something the port introduces.
Quoting
Arguments are split by the C runtime, not by a shell. crt1.c understands
'...' and "..." (added for this port), so
git commit -m "a message with spaces"
reaches git as three arguments. There is no escaping and no substitution -- a literal quote character cannot be passed.
How the port is put together
Makefile drives upstream's own build with the toolchain and a long list of
NO_* knobs; the header comment there explains the ones that are not
self-evident. Two mechanisms fill the gaps:
compat/-- headers MontaukOS has no equivalent of, pluslibgitcompat.awith the POSIX functions the libc does not carry. Seecompat/README.patches/-- two patches: callingmontauk_startup()frommain(), and emptyingsanitize_stdfds(), which cannot run without a/dev/null.
Everything else upstream needed was already reachable through git's own portability knobs, which is the reason this port is small.