Tucker McKnight <tmcknight@instructure.com> | Wed Jun 17 2026
Rough draft for cachine files instead of fetching from git show every time Instead of getting the commit by calling `git show` and `git blame` every time we want to see the contents of a file, save the contents of the file in a map called fileMap. The file's contents and git blame info are cached with a key of "filename-SHA". Next time we want to see the contents of the file, before calling `git show` and `git blame`, first check if the fileMap contains that filename/sha combo. If it doesn't, look at parent commits to see if the fileMap has the file cached for an earlier commit. However, if the commit modifies that file, then we know that the cache won't have what we're looking for, and we'll have to call `git show` and `git blame`. TODO: - performance test - see if it benefits from caching at the earliest possible commit, so that more commit SHAs will find the same cached contents - see if we should also cache at a higher-level commit
5 6 7 8 9 10
import childProcess from 'child_process'
import {minimatch} from 'minimatch'
import { type Repository} from './dataTypes.ts'
import cloneUrl from './vcses/git/helpers.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
import { getLocation} from './helpers.ts'5 6 7 8 9 10
import childProcess from 'child_process'
import {minimatch} from 'minimatch'
import { type Repository, type FileInfo } from './dataTypes.ts'
import cloneUrl from './vcses/git/helpers.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
import { getLocation} from './helpers.ts'136 137 138 139 140
}
let cachedRepos: Array<Repository> | null = null
const repos: (reposConfig: ReposConfiguration, outputDir: string, slugify: Function) => Promise<Array<Repository>> = async (reposConfig, outputDir, slugify) => {
if (cachedRepos !== null) { return cachedRepos }136 137 138 139 140 141 142 143 144
}
let cachedRepos: Array<Repository> | null = null
// A cached list of files that we have already found. Save things here
// when we read them from calling `git show`.
// The key for this map is a string like "filename-sha".
const fileMap: Map<string, FileInfo> = new Map()
const repos: (reposConfig: ReposConfiguration, outputDir: string, slugify: Function) => Promise<Array<Repository>> = async (reposConfig, outputDir, slugify) => {
if (cachedRepos !== null) { return cachedRepos }225 226 227 228 229 230 231 232 233 234 235 236 237
defaultBranch: reposConfig.repos[repoName].defaultBranch,
tags: tags,
files: async (filename: string, sha: string) => {
const gitShowCmd = `git -C ${repoLocation} show ${sha}:${filename}`
const fileContents = (await exec(gitShowCmd)).stdout
const blameLines = await getFileLastTouchInfo(filename, sha, repoLocation)
return {
contents: fileContents,
lastModified: new Date(), //TODO: make lastModified check the actual modification date
blameLines,
}
},
commits,
})225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
defaultBranch: reposConfig.repos[repoName].defaultBranch,
tags: tags,
files: async (filename: string, sha: string) => {
let key = `${filename}-${sha}`
// First, see if fileMap already contains this file/sha combination.
if (fileMap.has(key)) {
return fileMap.get(key)
}
else {
// If it didn't, look up the chain of commits that may have the same file contents.
let currentCommit = commits.get(commits.get(sha).parent)
while (currentCommit !== undefined) {
if (currentCommit.diffs.map(d => d.fileName).includes(filename)) {
break
}
if (fileMap.has(`${filename}-${currentCommit.hash}`)) {
// TODO: maybe cache here as well, so that we don't have to loop as many
// times next time?
return fileMap.get(`${filename}-${currentCommit.hash}`)
}
currentCommit = commits.get(currentCommit.parent)
}
}
const gitShowCmd = `git -C ${repoLocation} show ${sha}:${filename}`
const fileContents = (await exec(gitShowCmd)).stdout
const blameLines = await getFileLastTouchInfo(filename, sha, repoLocation)
const commit = {
contents: fileContents,
lastModified: new Date(), //TODO: make lastModified check the actual modification date
blameLines,
}
// TODO: cache it as deeply in the git history as it can be, so that as many other commits
// benefit from this as possible.
fileMap.set(key, commit)
return commit
},
commits,
})