Repository navigation
Description
Is your feature request related to a problem?
Our team uses Sapling against GitHub-hosted git repos. In a native Sapling checkout (sl clone, which creates .sl/ and no .git), Nix doesn't recognize the repo:
nix build .resolves to apath:flake, because local repo detection inflakeref.cconly looks for.git.- When the flake's source is copied to the store (any build that uses
self), apath:flake copies the whole directory, including untracked files and build output. In a Sapling clone of our repo with a 1 GB untrackedtarget/, the source came to 1.1 GB, against 14 MB for the tracked files. Our realtarget/is several GB. self.rev,self.dirtyRevandself.lastModifiedare missing, so anything that stamps a build with its commit falls back to "unknown".
Running sl inside a git checkout ("dotgit" mode) avoids this. But native Sapling checkouts are the default sl clone produces, and the failure is silent and slow.
Proposed solution
Add a local-only sl input scheme (sl+file://…, type = "sl"), modeled on the existing Mercurial fetcher. It would shell out to sl, the same way mercurial.cc shells out to hg:
- Detection:
flakeref.ccmaps a directory containing.sltosl+file, the same way.gitmaps togit+file. - Source: only tracked files go into the store (
sl status --clean --modified --added --no-status --print0). Dirty trees followallow-dirty/warn-dirty. - Attributes:
rev,shortRev,dirtyRev,dirtyShortRev,lastModified, plus a lazily computedrevCount. In a git-backed Sapling repo the commit ID is the git SHA, so arevlocked from a Sapling checkout matchesgithub:/git+httpslocks of the same commit. - Write-back:
flake.lockwrites callsl add,--commit-lock-filecallssl commit, andnix flake init/newcallsl add. - Tests: functional tests that mirror
fetchMercurial.shandflakes/mercurial.sh.
Out of scope for a first PR: remote sl+https / sl+ssh fetching. Sapling remotes are usually git servers, which git+https and github: already handle. Git-only attributes (submodules, lfs, exportIgnore, verifyCommit) are also out.
Alternative solutions
- Document dotgit mode as the only supported Sapling setup. It works today, but users discover the problem only after a slow
path:copy. - Point
git+fileat.sl/store/git. That's the bare git store, so it doesn't see working-copy changes. - Reuse the Mercurial fetcher with
hgaliased tosl. Several commands it relies on behave differently in Sapling:branchdoesn't exist,{rev}is a virtual number, andarchiverefuses without an explicit file list.
Additional context
A working implementation with functional tests is on mikedodge04/nix-src@sapling-fetcher. Committed state is read through Sapling's bare Git store (.sl/store/git) with the existing GitRepo, so a locked sl+file input has the same store path and fingerprint as git+file at the same commit. We're happy to open a PR. Two questions first:
- Would you accept this in Determinate Nix, or would you rather it go to NixOS/nix first?
- Any preference on the scheme name (
slvssapling), or on keeping it behind an experimental feature?
Checklist
- checked latest Determinate Nix manual (source)
- checked open bug issues and pull requests for possible duplicates (no Sapling issues or PRs in DeterminateSystems/nix-src or NixOS/nix)
Activity
grahamc commentedon Oct 7, 2026
This is really neat, and I'm surprised by how brief the diff is! I'm inclined to go for it, but I'll talk to the team in the morning and get consensus.
p.s. If you can share any more information about how you're using Nix at work, I'd be glad to hear about it :)! graham at determinate.systems
mikedodge04 commentedon Oct 16, 2026
Hi @grahamc , thanks for the kind words! Just checking in: did the team reach a decision?
If it's a yes, I'm happy to open the PR against main whenever you're ready. The branch (mikedodge04/nix-src@sapling-fetcher) still merges cleanly onto today's 3.23.2. Since posting I've added one fix: a locked sl+file input now keeps revCount and lastModified from the lock file instead of recomputing them, as the git fetcher does.
Also worth knowing: upstream added InputScheme::localRepoURL() in NixOS#16507 (it ships in 2.36), which lets each scheme claim its own checkout directories. Once that reaches Determinate, .sl detection moves into the scheme and the flakeref.cc change goes away. I can do that in this PR or as a follow-up, whichever you prefer.