Guide · Aug 18, 2026

Sitemap lastmod from Git Commit Dates: Why It Backfires on Static Sites

If your site has a database, lastmod is easy: read each row's updated_at and you're done. Static sites don't have that, so the standard advice is to use the next best thing — each file's last commit date, pulled straight from git log. Every tool that solves this for static sites works that way, and it's reasonable advice that quietly fails in a specific, common situation.

What actually happens on a real repo

Here's the failure, measured on this site. FreeToolDev is 80 hand-written HTML pages in a Git repo, published over about six weeks. Taking each file's last commit date gives this distribution:

Ninety-four percent of the site claims to have changed on a single day. Nothing about that is true — those pages were written across six weeks and most haven't been touched since. What happened on July 31st was that a new tool was added to the site, and adding it meant appending one link to the footer of every page. Eighty files, one line each, one commit. Every file's "last modified" date reset simultaneously.

Any repo-wide edit does this. Adding an analytics snippet, renaming a CSS class, bumping a copyright year, running a formatter, adding a nav item, fixing a typo in a shared template. On a static site these all mean touching every file, because there's no template layer doing it for you at request time — that's the tradeoff you accepted when you chose static. Each one of those commits flattens your entire date distribution.

Why a flat distribution is worse than no dates at all

Google's treatment of lastmod is a trust decision, and Gary Illyes has described it as binary: either the dates hold up when checked against the pages, or the tag is disregarded across the sitemap. There's no partial credit and no per-URL grading. Guidance from Google in July 2026 went further — a site emitting unintentionally wrong dates was told it's better off without lastmod entirely.

Identical dates are the specific thing that fails this check, and it's easy to see why from the crawler's side. A sitemap saying every page changed on the same day is indistinguishable from a script that stamps the current date on everything, which is exactly what a lot of sitemap generators do. The crawler has its own record of when it last saw each page and what was on it. It compares, finds seventy-five pages that claim to have changed and haven't meaningfully, and draws the obvious conclusion.

The consequence is the part that stings. lastmod is one of the few fields Google says it genuinely uses — as a signal for scheduling crawls of URLs it has already discovered. priority and changefreq, the two fields people spend far more time tuning, are ignored. So the tag that could actually get your updated pages recrawled sooner is the one a naive Git-based implementation disables. And the failure is silent: no Search Console error, no warning in any validator that only checks the spec. The dates are perfectly well-formed. They're just not believed.

The fix: ignore commits that didn't change the content

The commit date isn't wrong as a data source — the problem is treating every commit that touched a file as a content change. A footer link and a rewritten paragraph are the same event to git log and completely different events to a crawler.

So walk each file's history backwards and skip commits that only touched boilerplate, taking the date of the first commit that represents a real change. In practice that means examining the diff for each commit rather than just reading its date:

  1. For a file, list its commits newest-first.
  2. For each commit, look at the changed lines in that file only.
  3. If every changed line matches a boilerplate pattern — a footer link, a nav entry, a script tag, a formatting-only whitespace change — skip that commit and move to the next one back.
  4. The date of the first commit that survives this filter is that file's real lastmod.

Applied to the 75-files-on-one-day case above, the same repo produced 13 distinct dates spread across five weeks, with the largest single day accounting for 28% of URLs instead of 94%. Same repository, same Git history — the only difference is not counting a footer edit as a modification.

What counts as boilerplate is specific to your site, which is why this can't be a drop-in library. Start by looking at what your last few site-wide commits actually changed; those diffs are your filter rules. If you can't express the distinction in code, a simpler version works too: record the date manually in each page's front matter or a small JSON file, and generate lastmod from that instead of from Git at all. Tedious, but it can't be wrong, and it stays correct through any refactor.

The rule that keeps it working afterward

Getting the dates right once is easy compared to keeping them right. One deploy that resets everything undoes it, and you may not find out for months, because nothing reports this.

The rule worth adopting: only edits that change what a reader sees update lastmod. Rewrote a section, added an FAQ, corrected a fact — update it. Added a footer link, adjusted spacing, changed a class name — leave every date alone. If you regenerate your sitemap on every build, make sure that regeneration preserves existing dates rather than recomputing them from scratch, or you'll rebuild the flat distribution on the very next deploy.

Two things are worth checking as you go. A date in the future is always a bug — it usually means a timezone conversion pushed a late-evening timestamp past midnight. And if your build can't produce a date you'd defend, leave the field out for that URL; a missing lastmod costs you a scheduling hint on one page, while a distrusted one costs you the tag across the whole file.

Check what you're actually publishing

The quickest way to know where you stand is to look at your own sitemap's date distribution — if one day accounts for most of your URLs, you have this problem regardless of how the file was generated. FreeToolDev's Bulk Sitemap Validator flags exactly that: identical dates across a sitemap, heavy clustering on a single day, dates in the future, and URLs missing lastmod while others have it — alongside the usual structural checks. Paste in your sitemap.xml and it runs entirely in your browser, with nothing uploaded. If you're still assembling the file, the sitemap generator builds one from a pasted URL list, and this post covers where it needs to live on GitHub Pages, Netlify, and Vercel.