# git for MontaukOS Upstream [git/git](https://github.com/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) | ```bash 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**: 1. **`sanitize_stdfds()` opened `/dev/null`**, which MontaukOS does not have, so `xopen()` died before any command dispatched. That function guards against inheriting closed descriptors, which cannot happen on a system that spawns rather than forks; `patches/0002` makes it a no-op. 2. **Nothing git wrote with `write(2, ...)` ever appeared** -- which is why the fatal error was invisible. The libc's `read()`/`write()` passed fd 0/1/2 straight to `SYS_READ`/`SYS_FWRITE` as file handles, and the kernel hands out file handles starting at 0, so those numbers named real files. A program's third `open()` 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`, `show` - `branch`, `checkout`, `switch`, `restore`, `merge`, `reset`, `revert` - `tag`, `stash`, `cherry-pick`, `rebase` (the builtin, non-interactive path) - `cat-file`, `rev-parse`, `ls-files`, `ls-tree`, `hash-object`, `fsck` - `config`, `blame`, `grep`, `describe`, `bisect` - `clone`/`fetch`/`push` **against 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`, so `git commit` needs `-m` or `-F`, and interactive rebase and `git add -p` are out - the pager (harmless -- output goes straight to the terminal, and `DEFAULT_PAGER=cat` is compiled in anyway) - aliases that shell out (`!command`), `git submodule`, `difftool`, `mergetool`, `git gc` (it re-runs itself as `git 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/`) 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 you@example.com ``` 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, plus `libgitcompat.a` with the POSIX functions the libc does not carry. See `compat/README`. - `patches/` -- two patches: calling `montauk_startup()` from `main()`, and emptying `sanitize_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.