SharePointVault ~/gotchas/tooling ⌕ Search 404 pages, error messages, scripts…Ctrl K ★ Star
M↓ README.mdM↓ git-rm-leaves-the-directory-so-tools-report-a-phantom-version.md
sharepoint-vault›gotchas›tooling›git-rm-leaves-the-directory-so-tools-report-a-phantom-version.mdhistoryedit on GitHub
● GOTCHAtooling· 2 min read

git rm -r leaves the directory behind, so a tool reading the filesystem reports a version nobody serves

applies to: any git-backed static host (GitHub Pages) with per-version foldersreviewed: 2026-09-23#tooling#git#github-pages#cdn#release

git rm -r <dir> deletes only tracked files; build leftovers that were never added (*.LICENSE.txt, .map, logs) keep the directory alive on disk. Anything that lists versions with readdirSync then offers a version the site does not serve — in our case a pin tool that would have pinned our tenant to a build that had just been removed. For a git-backed host, the published content is git ls-tree, never the working directory.

git rm -r <adresář> smaže jen sledované soubory; nesledované zbytky po buildu (*.LICENSE.txt, .map, logy) nechají adresář na disku stát. Nástroj, který verze vypisuje přes readdirSync, pak nabídne verzi, kterou web neservíruje – u nás by nástroj na piny připnul tenant na build, který jsme právě odstranili. U hostingu nad gitem je publikovaný obsah git ls-tree, nikdy pracovní adresář.

Symptom

You remove a version folder from the repo that backs the static host:

git rm -r cdn/app/2.4.0.1
git commit -m "remove superseded build" && git push

The site returns 404 for it, as intended. But your own tooling keeps naming it:

"app":"2.4.0.1"        # generator picking the newest version folder

ls explains it:

$ ls cdn/app/2.4.0.1
chunk.165_....js.LICENSE.txt
chunk.8731_....js.LICENSE.txt
...

Seven files that were never tracked (a .gitignore entry, or simply never added). git rm had nothing to say about them, so the directory survived — empty as far as the site is concerned, present as far as the filesystem is concerned.

Why it matters more than it looks

The mismatch is silent and it points the wrong way: the tool advertises more than exists. Ours picks "the highest version folder" as the pin target, so it was about to pin our own tenant to a build that had ceased to exist — we would have been testing something the CDN could no longer serve, while customers ran the real one.

The same shape bites size accounting: du -sh over the working directory counts untracked leftovers that never reach the host, so a repo that looks close to a hosting quota may be far from it (and vice versa).

Fix

Read the published content from git, not from disk.

const { execFileSync } = require('child_process');

function publishedVersions(repoDir, appFolder) {
  const out = execFileSync('git', ['-C', repoDir, 'ls-tree', '--name-only', '-d', 'HEAD:' + appFolder], { encoding: 'utf8' });
  return out.split('\n').map(s => s.trim()).filter(s => /^\d+(\.\d+){1,3}$/.test(s));
}

Two details worth keeping:

  • Fail closed. If git cannot be read, exit with an error instead of falling back to readdirSync — a tool that silently degrades to the wrong source is how the bug returns.
  • Compare versions numerically, per component. 1.10.0 is newer than 1.9.9; lexicographic sorting says the opposite.

And when you do remove a folder, clean the working copy too (rm -rf after the git rm), so the two views stop disagreeing at all.

Related

Was this helpful?ask or add your experience on GitHub →
Saved you an hour? A star on GitHub helps other SharePoint people find the vault.★ Star on GitHub
last reviewed: 2026-09-23last updated: 2026-09-24historyedit on GitHubview source