| If you’ve read my earlier article on managing FreeBSD ports, you may have noticed that portsnap no longer works. Don’t panic — your system isn’t broken, it’s just evolving. From FreeBSD 15 onward, portsnap has been retired. The ports tree is now managed with Git (see official release notes). Think of it as moving from cassette tapes to streaming: same music, easier updates. This new workflow replaces both portsnap and Subversion. With Git, updates are faster, branching is simpler, and history is clear enough that even your future self will thank you. |
|
Background:
Portsnap is deprecated: FreeBSD 15 no longer supports portsnap. The ports tree is now distributed exclusively via Git.
SVN retired: Since 2021, the FreeBSD project has migrated all repositories (src, ports, docs) from Subversion to Git.
Unified workflow: Git provides a single, modern version control system for ports, source, and documentation.
Setting up ports:
Before we start, let’s make sure our ZFS is set up properly:
Let’s find out the dataset name:
root@f5:~ # zfs list /usr/ports NAME USED AVAIL REFER MOUNTPOINT zroot/usr/ports 96K 891G 96K /usr/ports
Now that we know the Dataset name, in our case, it is the default zroot. Let’s check the attributes:
root@f5:~ # zfs get all zroot/usr/ports NAME PROPERTY VALUE SOURCE zroot/usr/ports type filesystem - zroot/usr/ports compressratio 1.00x - zroot/usr/ports mounted yes - zroot/usr/ports recordsize 128K default zroot/usr/ports mountpoint /usr/ports inherited from zroot/usr zroot/usr/ports compression on inherited from zroot zroot/usr/ports atime off inherited from zroot ... (many defaults omitted)
The important bits here are compression, recordsize, and atime. The rest are defaults.
Before cloning, let’s tune ZFS for better performance /usr/ports:
- atime=off: stops extra metadata writes when files are read.
- recordsize=16K: ideal for many small files, reduces wasted space.
- compression=zstd-19: strong balance of speed and savings. Use
zstd-9if CPU is limited.
These settings will keep your ports tree lean and efficient.
root@f5:~ # zfs set atime=off zroot/usr/ports root@f5:~ # zfs set compression=zstd-19 zroot/usr/ports root@f5:~ # zfs set recordsize=16K zroot/usr/ports
Now we verify:
root@f5:~ # zfs get compression,recordsize,atime zroot/usr/ports NAME PROPERTY VALUE SOURCE zroot/usr/ports compression zstd-19 local zroot/usr/ports recordsize 16K local zroot/usr/ports atime off local
Workflow Impact
- Git pulls will be faster with compression and a small record size.
- Disk usage will shrink significantly (ports tree ~900 MB raw → ~300 MB compressed).
- Turning off
atimeavoids extra I/O during builds.
Back to ports…
Install Git
root@f5:~ # pkg install git
Ensure /usr/ports is empty before cloning.
root@f5:~ # rm -r /usr/ports/* rm: /usr/ports/*: No such file or directory root@f5:~ # rm -r /usr/ports/.git* rm: /usr/ports/.git*: No such file or directory
Clone the ports tree
This will take some time…
root@f5:~ # git clone https://git.freebsd.org/ports.git /usr/ports Cloning into '/usr/ports'... remote: Enumerating objects: 6745346, done. remote: Counting objects: 100% (936/936), done. remote: Compressing objects: 100% (120/120), done. remote: Total 6745346 (delta 923), reused 816 (delta 816), pack-reused 6744410 (from 1) Receiving objects: 100% (6745346/6745346), 1.50 GiB | 6.21 MiB/s, done. Resolving deltas: 100% (4084572/4084572), done. Updating files: 100% (168524/168524), done.
The full clone weighs in at 6,745,346 bytes — not much by modern standards, but enough to hold the entire ports tree. Imagine it as a library card: you’ve checked out the whole collection, and now you need to learn the new system for keeping it updated.
Updating and Managing Ports
To update the ports tree (like the old portsnap fetch update):
cd /usr/ports git pull --rebase
For convenience, create an alias or script so you only need one command. (~/.cshrc for tcsh, ~/.bashrc for bash, etc.):
alias portsupdate='cd /usr/ports && git pull --rebase'
Usage:
portsupdate
Option 2: Shell Function (more flexible)
For bash/zsh:
portsupdate() {
cd /usr/ports || return
git pull --rebase
}
This avoids leaving you stuck in /usr/ports after the update
Option 3: Script in /usr/local/bin
Create /usr/local/bin/portsupdate
#!/bin/sh cd /usr/ports || exit 1 exec git pull --rebase
Make it executable:
chmod +x /usr/local/bin/portsupdate
Now it behaves like a system command:
portsupdate
You can still use cdport from my old post, Managing FreeBSD Ports Before 15.x.
This is your Git‑era portsnap: a single command that updates the tree without clutter. Alias it as portsupdate or even portsnap if you want to preserve muscle memory continuity.
Benefits of Git-based Ports
- Speed: Updates are faster than portsnap snapshots.
- Transparency: Every commit is visible with diffs and history.
- Flexibility: ranching allows quarterly snapshots (like
2025Q4) alongsidemain. - Collaboration: Easier to fork, patch, and merge.
- Compression options: ZFS compression (
zstd-19) saves space with little cost.
Deduplication: The Tempting Mirage
Deduplication sounds cool — like a magic trick that saves space. But when you’re compiling ports, it’s more like asking your CPU to juggle while it’s already running a marathon.
Ports are packed with tiny, unique files, so dedup has almost nothing to “deduplicate.” Instead, it burns cycles comparing blocks while your compiler taps its foot impatiently.
Compression and recordsize tuning are the real heroes here. Dedup? It’s the party guest who eats all the snacks but doesn’t help clean up. And remember: after compiling, you’ll wipe the source tree anyway, so any “savings” vanish.
Let your CPU build ports, not audition for a hashing contest.
