In-place editing

Version 0.6.1 Updated Sep 29, 2026

Pass --in-place to rewrite each selected file with the formatted result. The formatted output is written to a temporary file in the same directory as the target and then renamed over it, so the replacement is atomic on POSIX filesystems: a reader sees either the whole original file or the whole replacement, never a partial write. When the run fails before the rename — a full disk, a permission error, or a declined target — the original file is left byte-identical and any temporary file is removed on a best-effort basis, so the run can be retried safely. A run killed abruptly, by SIGKILL or a power loss, can leave a stale temporary file beside the target; the original is still intact, and the next run retries past the stale name rather than reusing it. Stale files are named <target>.mdtablefix-<pid>-<n>.tmp. Delete them once no run is in progress.

When an in-place rewrite fails, mdtablefix reports the full error chain on standard error: first the file context, naming the path as the run knows it — the path as given on the command line, or the relative path Git reported for a --git run — then the underlying cause beneath a Caused by: heading. Every failing file is reported this way, and the run then exits with a non-zero status. Scripts that match exact standard-error text should expect the chain and its multi-line form; matching the file name or the cause is more robust.

The original file mode is preserved. A freshly created temporary file does not inherit the target's permissions, so mdtablefix copies them to the temporary file before the rename: a file with mode 0640 still has mode 0640 afterwards. Because the replacement is a rename, it needs write permission on the containing directory rather than on the file itself, so a read-only file in a writable directory is replaced successfully, and the replacement takes over the read-only state rather than losing it.

Windows needs one step more than that. There, read-only is a file attribute, FILE_ATTRIBUTE_READONLY, and the rename cannot replace a destination that carries it. mdtablefix therefore clears that attribute on the destination through its directory capability immediately before the rename. The temporary file still carries the original read-only attribute, so the file that takes over the target's name is read-only as soon as the rename lands. If the swap does not complete, the original attribute is put back on a best-effort basis: a run interrupted between those two steps, or a restoration that itself fails, can leave the target's read-only attribute cleared. The contents are unaffected, because a swap that does not complete leaves the original file byte-identical.

Symbolic links are declined rather than replaced. The read follows the link, but the rename swaps the link entry itself, which would turn the symlink into a regular file while leaving the real file untouched. The run reports the declined link on standard error; rewrite the link's target directly instead. A link whose target resolves outside the file's directory is refused by the directory capability before the rewrite begins.

Two limitations apply. On Windows the replacement can fail if another process holds the destination open without delete sharing, because the rename cannot displace an open handle. Atomicity is also not durability: the new contents are flushed to storage before the rename, but the rename itself is not, so a power loss immediately afterwards can revert the directory entry to the original file.