diff --git a/sphinx/builders/html/__init__.py b/sphinx/builders/html/__init__.py
index 06917232f6b..8f351b76a12 100644
--- a/sphinx/builders/html/__init__.py
+++ b/sphinx/builders/html/__init__.py
@@ -40,6 +40,7 @@
from sphinx.theming import HTMLThemeFactory
from sphinx.util import isurl, logging
from sphinx.util._timestamps import _format_rfc3339_microseconds
+from sphinx.util.console import bold
from sphinx.util.display import progress_message, status_iterator
from sphinx.util.docutils import new_document
from sphinx.util.fileutil import copy_asset
@@ -389,8 +390,9 @@ def math_renderer_name(self) -> str | None:
return None
def get_outdated_docs(self) -> Iterator[str]:
+ build_info_fname = self.outdir / '.buildinfo'
try:
- with open(path.join(self.outdir, '.buildinfo'), encoding="utf-8") as fp:
+ with open(build_info_fname, encoding="utf-8") as fp:
buildinfo = BuildInfo.load(fp)
if self.build_info != buildinfo:
@@ -405,6 +407,21 @@ def get_outdated_docs(self) -> Iterator[str]:
if self.templates:
template_mtime = int(self.templates.newest_template_mtime() * 10**6)
+ try:
+ old_mtime = _last_modified_time(build_info_fname)
+ except Exception:
+ pass
+ else:
+ # Let users know they have a newer template
+ if template_mtime > old_mtime:
+ logger.info(
+ bold("building [html]: ") +
+ __(
+ "template %s has been changed since the previous build, "
+ "all docs will be rebuilt"
+ ),
+ self.templates.newest_template_name(),
+ )
else:
template_mtime = 0
for docname in self.env.found_docs:
diff --git a/sphinx/jinja2glue.py b/sphinx/jinja2glue.py
index ec75c6d96cb..74321383455 100644
--- a/sphinx/jinja2glue.py
+++ b/sphinx/jinja2glue.py
@@ -204,8 +204,14 @@ def render_string(self, source: str, context: dict) -> str:
return self.environment.from_string(source).render(context)
def newest_template_mtime(self) -> float:
+ return self._newest_template_mtime_name()[0]
+
+ def newest_template_name(self) -> str:
+ return self._newest_template_mtime_name()[1]
+
+ def _newest_template_mtime_name(self) -> tuple[float, str]:
return max(
- os.stat(os.path.join(root, sfile)).st_mtime_ns / 10**9
+ (os.stat(os.path.join(root, sfile)).st_mtime_ns / 10**9, sfile)
for dirname in self.pathchain
for root, _dirs, files in os.walk(dirname)
for sfile in files