feat: ports - git port

This commit is contained in:
2026-08-09 10:47:07 +02:00
parent cfb8d91442
commit 6f3cf99667
34 changed files with 2255 additions and 2 deletions
+143
View File
@@ -0,0 +1,143 @@
# 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/<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, 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.