Skip to content
Open
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
08ad89f
fix(plugin-git): resolve git log file paths against repository root
mtfhx Feb 24, 2026
ee60c9e
fix(plugin-git): stabilize getGitRepoRoot path resolution
mtfhx Mar 2, 2026
79d56fb
Merge branch 'main' into plugin-git
mtfhx Mar 2, 2026
eeafcb8
perf(plugin-git): improve fallback warning
mtfhx Mar 2, 2026
aaa7746
refactor(plugin-git): refining the variable name
mtfhx Mar 2, 2026
bc24cb1
perf(plugin-git): cache git repo root lookups and clear cache onPrepared
mtfhx Mar 3, 2026
e3f22c1
Merge branch 'main' into plugin-git
Mister-Hope Mar 8, 2026
59f88e1
Merge branch 'main' into plugin-git
Mister-Hope Mar 10, 2026
19afa26
Merge branch 'main' into plugin-git
Mister-Hope Mar 11, 2026
366a4f5
Merge branch 'main' into plugin-git
mtfhx Mar 16, 2026
0fa382d
Merge branch 'main' into plugin-git
Mister-Hope Apr 1, 2026
b8fbd36
Merge branch 'main' into plugin-git
mtfhx Apr 9, 2026
12d2d17
Merge branch 'main' into plugin-git
mtfhx Apr 20, 2026
affa47c
Merge branch 'main' into plugin-git
mtfhx May 13, 2026
52e6a36
fix: try to fix commit link
mtfhx May 12, 2026
80fc507
Merge branch 'main' into plugin-git
Mister-Hope May 14, 2026
f29e845
Merge branch 'main' into plugin-git
Mister-Hope May 21, 2026
901b1ce
fix: only set submodule if there is actual repo url
Mister-Hope May 21, 2026
5616503
fix: handle git:// protocols
Mister-Hope May 21, 2026
6f707d3
fix: stricter remote check
Mister-Hope May 21, 2026
209247f
refactor: refine codes
Mister-Hope May 21, 2026
99fa0e4
refactor: complete jsdocs
Mister-Hope May 21, 2026
9f9b7d4
build: update deps
Mister-Hope May 21, 2026
fa93008
fix(plugin-git): only get commits in same git root
Mister-Hope May 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 68 additions & 2 deletions plugins/development/plugin-git/src/node/utils/getCommits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { spawn } from 'node:child_process'
import type { GitContributorInfo } from '../../shared/index.js'
import type { GitPluginOptions } from '../options.js'
import type { MergedRawCommit, RawCommit } from '../typings.js'
import { path } from 'vuepress/utils'
import { logger } from './logger.js'

const INFO_SPLITTER = '[|]'
Expand Down Expand Up @@ -77,6 +78,58 @@ const runGitLog = (args: string[], cwd: string): Promise<string> =>
})
})

/**
* Get git repository root directory for a given file path.
*
* This function runs `git rev-parse --show-toplevel` in the directory of the
* target file to determine the top-level directory of the git repository.
*
* @param filePath - File path (relative or absolute) whose repository root is requested
* @param cwd - Current working directory
* @returns Promise that resolves to normalized git root path, or null if not in a git repository
*/
const getGitRepoRoot = (
filePath: string,
cwd: string,
): Promise<string | null> =>
new Promise((resolve) => {
const absFilePath = path.isAbsolute(filePath)
? filePath
: path.resolve(cwd, filePath)
const dir = path.dirname(absFilePath)
const gitProcess = spawn('git', ['rev-parse', '--show-toplevel'], {
cwd: dir,
stdio: ['ignore', 'pipe', 'pipe'],
})

let stdoutData = ''
let stderrData = ''

gitProcess.stdout.on('data', (chunk: Buffer) => {
stdoutData += chunk.toString('utf-8')
})

gitProcess.stderr.on('data', (chunk: Buffer) => {
stderrData += chunk.toString('utf-8')
})

gitProcess.on('error', (error) => {
logger.error(`Failed to spawn git rev-parse: ${error.message}`)
resolve(null)
})

gitProcess.on('close', (code) => {
if (code === 0) {
resolve(path.normalize(stdoutData.trim()))
} else {
logger.error(
Comment thread
Mister-Hope marked this conversation as resolved.
Outdated
`git rev-parse failed (code=${code}): ${stderrData.trim()}`,
)
resolve(null)
Comment thread
Mister-Hope marked this conversation as resolved.
Outdated
}
})
})

/**
* Get raw commits for a specific file
*
Expand All @@ -96,18 +149,31 @@ export const getRawCommits = async (
options: GitPluginOptions,
): Promise<RawCommit[]> => {
const format = getGitLogFormat(options)
const gitRoot = await getGitRepoRoot(filepath, cwd)

Comment on lines 157 to 159
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getGitRepoRoot() is executed for every file in getRawCommits(), which adds an extra git spawn per file and can noticeably slow down builds on large sites (especially since getCommits() runs for every page). Consider memoizing repo roots by directory (e.g. a Map keyed by dir/cwd) or computing the repo root once per getCommits() call and reusing it for all filepaths.

Copilot uses AI. Check for mistakes.
try {
let _filepath = filepath
Comment thread
Mister-Hope marked this conversation as resolved.
Outdated
if (gitRoot) {
// Resolve to absolute path first, then convert to repo-relative path
const absFilePath = path.isAbsolute(_filepath)
? _filepath
: path.resolve(cwd, _filepath)

_filepath = path.relative(gitRoot, absFilePath)
} else {
logger.warn('Get git repo root error!')
Comment thread
Mister-Hope marked this conversation as resolved.
Outdated
}

const stdout = await runGitLog(
[
'--max-count=-1',
`--format=${format}${COMMIT_SPLITTER}`,
'--date=unix',
'--follow',
'--',
filepath,
_filepath,
],
cwd,
gitRoot || cwd,
Comment on lines 157 to +198
Copy link

Copilot AI Mar 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getCommits() can now fetch commit histories from different git roots within a single call (because getGitRepoRoot() is computed per filepath). However, mergeRawCommits() still merges commits solely by hash, which assumes all commits come from the same repository. If filepaths ever span multiple repos (e.g. via gitInclude pointing outside a submodule), identical hashes across repos could be merged incorrectly. Consider either enforcing that all filepaths resolve to the same gitRoot (and warn/skip otherwise), or include the repo identity (e.g. gitRoot) in the merge key / raw commit data so merges remain correct across repos.

Copilot uses AI. Check for mistakes.
)

return stdout
Expand Down
Loading