Releases: sasmaq/incrmit
Release list
v0.3.6
[0.3.6] - 2026-09-28
Security
- A state file can no longer point
undoat a file outside the project. It was
the one way incrmit wrote to a path no trusted input named: the config is
trusted like a Makefile, but a repository can commit.incrmit.state.toml,
and its recorded absolute paths sentundoto any file you can write that
held the recorded version.undonow writes only to files the config lists
and to that config. An absolute or../path is still undone when the config
lists it.
Changed
undoworks on the project whose config it is given, not the directory the
bump ran in. The state file recorded every file's absolute path and the
config's, andundoacted on those, so undo in a copy of a project reverted
the original, reported the change as though it were local, and popped the
copy's entry, and undo in a moved project failed looking for the config where
it used to be. Entries now record each path asincrmit.tomllists it,
resolved against the configundois given. Older state files still load,
with the absolute paths ignored.undoreverts only files the config lists at the version the bump wrote, and
otherwise refuses, naming the file, with nothing written. This also stops an
undo after the config was edited since the bump, which used to revert the
files and leave the edited config entries as they were.
Removed
- Releases no longer publish
checksums.txtandchecksums-macos.txt. GitHub
records a SHA-256 digest for every release asset and shows it on the release
page, so the files duplicated what is already there. Thechecksumsand
pkg-checksumsmake targets are gone with them.
v0.3.5
[0.3.5] - 2026-09-27
Security
- The config and the state file are no longer opened when they are not ordinary
files.incrmit.toml, the--outputthatdiscoverreads anignorelist
from, and.incrmit.state.tomlskipped the check that bump targets get, so a
named pipe at any of them hung the command with no output. That included
previewanddiscover --dry-run, the commands meant for a tree you do not
own. A repository can also commitincrmit.toml -> /dev/zero, which was read
without end. Each is now reported asnot a regular filewith exit1before
anything is written. A link to an ordinary file is still followed. - The config and the state file are capped at 16 MiB. The state file drops its
oldest entries rather than grow past the cap, so a project with thousands of
files keeps fewer than 20 bumps to undo instead of failing to read its own
history.
Fixed
- A bump whose state file cannot be read now fails before writing anything. The
state file used to be read last, so a bump could rewrite every target and the
config and then fail, leaving no entry forundoto find.--dry-runreads
it too and reports the same failure.
v0.3.4
[0.3.4] - 2026-09-26
Security
- The project lock no longer writes through a symbolic link.
.incrmit.lock
was opened following links and truncated to hold the lock's note, so a
repository that committed it as a link to a file outside the tree had that
file's contents replaced with two lines of lock text by the firstdiscover,
bump, orundoin the clone, and a dangling link created the file it named.
The lock file is now opened without following links. A link, a directory, or
a named pipe at that path is left as it is, named in a warning, and the run
continues unlocked. A regular file already there is used as the lock but
never rewritten: the note goes only into a lock file that is empty.
Fixed
- The warning for an unavailable project lock names the lock file once, rather
than repeating its path inside the OS error.
v0.3.3
[0.3.3] - 2026-09-25
Security
- Names and file contents no longer reach the terminal raw. A file in a scanned
tree could carry escape sequences in its name or on its version line, and
discover --dry-run— the command meant for trees you do not own — printed
them as they were, letting the file clear the screen, retitle the window,
plant a hyperlink, or write to the clipboard on terminals that allow it. All
output now passes through an escaping layer: a name with a control character,
a bidirectional override, or a byte that is not UTF-8 is shown Go-quoted
("invoice\u202efdp.exe"), and such characters in a context line appear as
escapes (\x1b[2J). Ordinary names and text print unchanged, and files are
still read, written, and recorded under their real names.
Fixed
-
incrmit discoveron Linux no longer writes a config that cannot be loaded
when a file name is not valid UTF-8. TOML cannot hold such a name, so the file
is now skipped with a warning. -
A filesystem error names the file once, rather than repeating its raw path
after the name (reading X: stat X: file name too long). -
incrmit discoverno longer slows to a crawl on minified files. Each
occurrence kept a copy of its whole line and recounted lines from the top of
the file, so a 620 KB one-line bundle holding twenty thousand versions took
seconds and allocated about 12 GB. The scan is now a single pass, and the
--dry-runcontext for a long line is clipped to 80 bytes on each side of the
version, with...marking each cut. -
discover --dry-runnumbers lines correctly in files with classic-Mac (\r)
line endings. Such a file was reported as one line, and its carriage returns
were printed to the terminal, which overprinted the output. A lone\rnow
ends a line, as it does in an editor, and a UTF-8 byte-order mark is left out
of the first line's context. -
A file that grows past the discovery size cap while it is being read is
skipped, as a file over the cap already was, rather than scanned up to the
cap. A cut falling mid-token could record1.2.34as1.2.3.
Documented
- What a bump keeps and what it gives up: line endings, a byte-order mark, and a
missing final newline are preserved exactly; UTF-16 files are not supported
and report no version; and because the new contents are renamed into place,
permission bits survive (a read-only file is still bumped) while setuid,
setgid, and sticky bits, hard links, ownership, and extended attributes do
not. See "What a bump keeps" inREADME.md. ignorepatterns match a metacharacter literally when it is bracketed
(v[*].txt); a configpathand--fileare always literal names.
v0.3.2
[0.3.2] - 2026-09-22
Fixed
- A version with a leading zero in one of its numeric components (
1.02.3) no
longer reports a successful bump while leaving the file untouched. The token
parsed as1.2.3, so the rewriter went looking for the text1.2.3, found
nothing, and wrote the file back unchanged —incrmit --patchprinted
1.2.3 -> 1.2.4over a file that still said1.02.3. Leading zeros are
rejected now, as semver requires, so the file reports "no semantic version
found" and says which file it is. - A version token ending in a hyphen (
1.2.3+0-) is rejected for the same
reason: semver permits it, but the scanner stops at the word boundary and
reads it back out of a file as1.2.3+0, so a config could pin a token no
bump could ever locate. --max-file-sizenow accepts the1234 bytesspelling thatincrmititself
prints for a limit that is not a whole number of KiB/MiB/GiB. The flag showed
a default the flag would not take back.
Added
- Fuzz targets over the version parser, the token scanner, the file rewriter,
the size parser, and config loading, withmake fuzzto run them locally and
a CI job that runs a bounded pass on every push. Seedoc/DEVELOPMENT.md
§12.1 for what each one proves; the three fixes above are what the first pass
found.
v0.3.1
v0.3.0
[0.3.0] - 2026-09-19
Fixed
- Broadened test coverage over paths that had none, so the behavior they
describe cannot regress unnoticed: reading a version from a file, splitting a
version token across the config's keys, semver precedence for prerelease
numbers too large for a 64-bit integer, drift detection following the version
most files hold rather than the first one listed, ignore patterns that trim to
nothing or outrun the path, an unreadable file being skipped bydiscover
instead of failing the scan, andundorefusing a journal whose recorded
version does not parse. Coverage rose from 92.9% to 95.8%.
Changed
- The build and release pipeline runs on current GitHub Actions:
checkout
v7.0.1,setup-gov7.0.0, andaction-gh-releasev3.0.3, each still pinned
to a commit SHA. The previous pins ran on the deprecated Node 20 runtime,
which GitHub had begun forcing onto Node 24 anyway. - Building
incrmitnow requires Go 1.27 or later, up from Go 1.26. Thego
directive ingo.modand the requirement documented inREADME.mdwere
raised together; CI already built with whateverstableresolves to, which is
Go 1.27. - CI lints with
golangci-lintv2.13.2, up from v2.12.2. A released
golangci-lintcan only typecheck the standard library of the Go it was built
with or older, so Go 1.27 becomingstablemade the older pin fail on Go's
owninternal/pollrather than on anything in this repository.
v0.2.1
[0.2.1] - 2026-08-18
Added
- An
incrmit previewcommand shows, for every file in the config, the version
it holds today alongside what a--patch,--minor, and--majorbump
would write — all three outcomes in one aligned table, without a--dry-run
per component. It is read-only: no target file, config, or bump history is
written. Thevprefix is carried into every projection, a prerelease or
build section is dropped exactly as a real bump would drop it, and a file
listed once per version it contains gets one row per version.- Rows whose version differs from the one most entries hold are marked
*
and explained under the table, so a file left behind by a partial bump is
visible at a glance. Only semver precedence counts as a difference, so
v1.2.3,1.2.3, and1.2.3+build.7are never marked against each other. --file/-fpreviews a single target without a config, and
--max-file-size/-sapplies as it does to a bump.
- Rows whose version differs from the one most entries hold are marked
v0.2.0
[0.2.0] - 2026-08-14
Added
- Semver prerelease and build metadata are now first-class:
1.2.3-rc.1,1.2.3+build.7, andv2.0.0-beta.1+exp.sha.5114f85are parsed,
recorded byincrmit discover, and rewritten as whole tokens. Aversion
pinned inincrmit.tomlmatches the full token, so a prerelease and the
release it names are never mistaken for each other, even in the same file.
A version welded into a longer hyphen-joined word keeps only its numbers, so
release filenames and download URLs still bump as expected
(incrmit-1.2.3-linux-amd64.tar.gz->incrmit-1.2.4-linux-amd64.tar.gz)
rather than having the filename read as a prerelease and rewritten away. incrmit.tomlrecords a running prerelease in its ownprereleasekey (and
build metadata inbuild) beside the numericversion.--prewrites the
key,--releaseand any component bump remove it, so the config reads as the
project's actual state. Because the config now says which suffix belongs to
the version, a prerelease is tracked correctly even where it sits inside a
release filename:--releaseturnsapp-1.2.3-rc.1.zipinto
app-1.2.3.zip, and a prerelease written into a download URL is found again
on the next step instead of being stranded at-rc.1. Configs that spell the
whole token inversion(version = "1.2.3-rc.1") keep working and are
migrated to the split form on the next write.- A
--release/-rflag promotes a prerelease to the release it names
(1.2.3-rc.1->1.2.3) without touching the numbers. Using it on a version
that has no prerelease, or alongside--preor a component flag, is a usage
error (exit2). - A
--pre <id>/-e <id>flag starts or advances a prerelease:
1.2.3->1.2.4-rc.1, then1.2.4-rc.1->1.2.4-rc.2. Naming a component
alongside it opens a new release line instead (--minor --pre rcgives
1.3.0-rc.1).
Fixed
- A bump no longer mangles a prerelease or build version. The token matcher
stopped at the numeric core, so1.2.3-rc.1bumped to1.2.4-rc.1and
1.2.3+build.7to1.2.4+build.7— both wrong under semver, and both leaving
a suffix attached to a version it no longer described. A--major,--minor,
or--patchbump now drops both sections (1.2.3-rc.1->1.2.4), matching
every other bump tool; use--releaseor--preto work within a prerelease.
v0.1.15
[0.1.15] - 2026-08-03
Added
- A
--max-file-size/-sflag sets the largest fileincrmitwill read.
Values are written as a byte count (1048576) or with a unit suffix (512KB,
32MiB,2G), and0means no limit.incrmit discover --max-file-sizeadjusts the 32 MiB cap that decides which
files a scan reads: lower it to keep a scan light on a tree full of large
generated files, or set0to scan everything.incrmit --max-file-sizeputs a cap on the files a bump reads. There is
still no cap by default, since targets are listed by hand; when one is set,
a target over the limit is reported (naming the file and the limit) and the
bump writes nothing at all.
Security
incrmit discoverno longer follows symlinks. Previously a link inside the
scanned tree pointing at a file elsewhere was read, its matched line shown in
--dry-runoutput, and — once recorded in the config — its contents copied into
the tree by the next bump. Scanning a checkout you did not author can no longer
reach outside the directory you pointed at.incrmit discovernow reads only regular files. A named pipe in the tree used
to hang the scan indefinitely (a read waits for a writer), and a link to an
endless device such as/dev/zeroread without limit until memory ran out.- A bump target that is not an ordinary file is now reported instead of hanging.
Naming a pipe inincrmit.tomlor passing one to--fileused to leave
incrmitwaiting forever with no output. A config entry is rejected up front
asconfig: target <path> is not a regular file, alongside the existing check
for a target that is a directory; a--filetarget is reported as
reading <path>: not a regular file. incrmit discovernow skips files larger than 32 MiB, so one very large file
in a tree can no longer drive the scan's memory use without bound. Version
strings live in small text files, and files listed in the config by hand are
unaffected.- Every published artifact now has a SHA-256 hash. The macOS
.pkginstallers
previously shipped with none, even thoughREADME.mddocumented verifying them;
their hashes are now published aschecksums-macos.txtalongside the existing
checksums.txt. - Release binaries are built with
-trimpath, so they no longer embed absolute
paths from the machine that built them and the same source produces the same
bytes anywhere. - GitHub Actions in both workflows are pinned to commit SHAs instead of movable
tags, workflow permissions default to read-only with write granted only to the
jobs that publish, andgovulnchecknow gates both CI and the release. Steps
that install a Go tool setGOPROXYandGOSUMDBexplicitly, so the
checksum verification that makes a pinned version immutable cannot be lost
to a change in the runner's defaults.
Fixed
- Documented that
incrmit.tomlis trusted input: a targetpathmay be
absolute or reach outside the config's directory with../, so review a config
before runningincrmitin a checkout you do not control. - Documented that a target which is a symlink is replaced by a regular file rather
than written through, leaving whatever it pointed at untouched.