@@ -5,7 +5,7 @@ import chalk from "chalk"
55import { execSync } from "node:child_process"
66import { createHash } from "node:crypto"
77import { readFileSync } from "node:fs"
8- import { relative } from "node:path"
8+ import { resolve } from "node:path"
99import remarkFrontmatter from "remark-frontmatter"
1010import remarkParse from "remark-parse"
1111import remarkParseFrontmatter from "remark-parse-frontmatter"
@@ -25,50 +25,51 @@ export interface GitMetadata {
2525 updatedOn ?: string
2626}
2727
28- function getRepoRoot ( ) : string {
29- return execSync ( "git rev-parse --show-toplevel" , {
30- encoding : "utf-8" ,
31- } ) . trim ( )
32- }
33-
3428/**
35- * Gets the last git commit metadata for a file.
36- * Returns undefined values if the file is not tracked by git or if git is
37- * unavailable.
29+ * Runs a single git log command to collect the last commit metadata for all
30+ * MDX files under srcDir. Returns a map keyed by absolute file path.
3831 */
39- export function getGitMetadata (
40- filePath : string ,
32+ export function buildGitMetadataMap (
33+ srcDir : string ,
4134 mode : PageTimestampMetadataMode ,
42- ) : GitMetadata {
35+ ) : Map < string , GitMetadata > {
36+ const map = new Map < string , GitMetadata > ( )
4337 if ( mode === "off" ) {
44- return { }
38+ return map
4539 }
4640
4741 try {
48- const repoRoot = getRepoRoot ( )
49- const relativePath = relative ( repoRoot , filePath )
50- const format = mode === "user-and-timestamp" ? "%cI%n%aN" : "%cI"
51- const result = execSync (
52- `git log -1 --format=${ format } -- "${ relativePath } "` ,
53- {
54- encoding : "utf-8" ,
55- stdio : [ "pipe" , "pipe" , "pipe" ] ,
56- } ,
57- ) . trim ( )
58-
59- if ( ! result ) {
60- return { }
61- }
62-
63- if ( mode === "user-and-timestamp" ) {
64- const [ updatedOn , updatedBy ] = result . split ( "\n" )
65- return { updatedBy, updatedOn}
42+ const repoRoot = execSync ( "git rev-parse --show-toplevel" , {
43+ encoding : "utf-8" ,
44+ } ) . trim ( )
45+
46+ const format = mode === "user-and-timestamp" ? "%cI%x09%aN" : "%cI"
47+ const output = execSync (
48+ `git log --format="COMMIT%x09${ format } " --name-only -- "${ srcDir } /**/*.mdx"` ,
49+ { encoding : "utf-8" , stdio : [ "pipe" , "pipe" , "pipe" ] } ,
50+ )
51+
52+ let currentMetadata : GitMetadata = { }
53+
54+ for ( const line of output . split ( "\n" ) ) {
55+ if ( line . startsWith ( "COMMIT\t" ) ) {
56+ const parts = line . split ( "\t" )
57+ currentMetadata =
58+ mode === "user-and-timestamp"
59+ ? { updatedBy : parts [ 2 ] , updatedOn : parts [ 1 ] }
60+ : { updatedOn : parts [ 1 ] }
61+ } else if ( line . trim ( ) ) {
62+ const absolutePath = resolve ( repoRoot , line . trim ( ) )
63+ if ( ! map . has ( absolutePath ) ) {
64+ map . set ( absolutePath , currentMetadata )
65+ }
66+ }
6667 }
67-
68- return { updatedOn : result }
6968 } catch {
70- return { }
69+ // git unavailable — return empty map
7170 }
71+
72+ return map
7273}
7374
7475interface PageCache {
@@ -81,6 +82,7 @@ interface PageCache {
8182
8283export class MarkdownFileReader {
8384 cachedFileCount = 0
85+ gitMetadataMap : Map < string , GitMetadata > = new Map ( )
8486 logWarnings = true
8587 private mdxCache : Record < string , PageCache > = { }
8688
@@ -189,7 +191,7 @@ export class MarkdownFileReader {
189191 const shouldFetchGitMetadata = ! this . enabled || ! existingCache
190192
191193 if ( shouldFetchGitMetadata ) {
192- const gitMetadata = getGitMetadata ( filepath , this . pageTimestampMetadata )
194+ const gitMetadata = this . gitMetadataMap . get ( filepath ) ?? { }
193195 if ( ! frontmatter . updatedOn && gitMetadata . updatedOn ) {
194196 frontmatter . updatedOn = gitMetadata . updatedOn
195197 }
0 commit comments