🌳
pt0/deployF/staticSiteF/gitShaMiningAI.mts
1import { execSync } from 'child_process'
2import crypto from 'crypto'
4type MineOpts = {
5 cwd: string,
6 msgBase: string,
7 tgtShaPrefix: string,
8 gitEnv?: Record<string, string>,
9}
11const computeCommitSha = (treeSha: string, authorLine: string, committerLine: string, message: string) => {
12 const body = `tree ${treeSha}\n${authorLine}\n${committerLine}\n\n${message}\n`
13 const header = `commit ${Buffer.byteLength(body)}\0`
14 return crypto.createHash('sha1').update(header + body).digest('hex')
17export const commitMineShaPrefix = ({cwd, msgBase, tgtShaPrefix, gitEnv}: MineOpts): string => {
18 const env = gitEnv ? {...process.env, ...gitEnv} : undefined
19 const run = (cmd: string) => execSync(cmd, {cwd, stdio: 'pipe', encoding: 'utf8', env})
21 const treeSha = run('git write-tree').trim()
23 if (!tgtShaPrefix) {
24 const sha = run(`git commit-tree ${treeSha} -m "${msgBase} #0"`).trim()
25 run(`git update-ref HEAD ${sha}`)
26 return sha
27 }
29 // Resolve author/committer identity (env overrides > git config fallback)
30 const cfg = (k: string) => { try { return run(`git config ${k}`).trim() } catch { return '' } }
31 const authorName = gitEnv?.GIT_AUTHOR_NAME || gitEnv?.GIT_COMMITTER_NAME || cfg('user.name')
32 const authorEmail = gitEnv?.GIT_AUTHOR_EMAIL || gitEnv?.GIT_COMMITTER_EMAIL || cfg('user.email')
33 const committerName = gitEnv?.GIT_COMMITTER_NAME || authorName
34 const committerEmail = gitEnv?.GIT_COMMITTER_EMAIL || authorEmail
36 // Fix timestamp so JS-computed SHA matches the final git commit-tree call
37 const ts = Math.floor(Date.now() / 1000)
38 const tzOff = -new Date().getTimezoneOffset()
39 const tz = `${tzOff >= 0 ? '+' : '-'}${String(Math.floor(Math.abs(tzOff) / 60)).padStart(2, '0')}${String(Math.abs(tzOff) % 60).padStart(2, '0')}`
40 const gitDate = `${ts} ${tz}`
41 const authorLine = `author ${authorName} <${authorEmail}> ${ts} ${tz}`
42 const committerLine = `committer ${committerName} <${committerEmail}> ${ts} ${tz}`
44 // Mine: pure-JS SHA1 loop (~µs/iter), then single git commit-tree for the winner
45 let nonce = 0, sha = ''
46 for (; nonce < 1_000_000; nonce++) {
47 const candidate = computeCommitSha(treeSha, authorLine, committerLine, `${msgBase} #${nonce}`)
48 if (candidate.startsWith(tgtShaPrefix)) { sha = candidate; break }
49 }
50 if (!sha) throw new Error(`mining sha prefix "${tgtShaPrefix}" failed after 1M attempts`)
52 const commitEnv = {...process.env, ...gitEnv, GIT_AUTHOR_DATE: gitDate, GIT_COMMITTER_DATE: gitDate} as Record<string, string>
53 const created = execSync(`git commit-tree ${treeSha} -m "${msgBase} #${nonce}"`, {cwd, stdio: 'pipe', encoding: 'utf8', env: commitEnv as any}).trim()
54 if (created !== sha) throw new Error(`mining sha mismatch: JS=${sha.slice(0,12)} git=${created.slice(0,12)}`)
55 run(`git update-ref HEAD ${sha}`)
56 console.log(` mined sha prefix "${tgtShaPrefix}" after ${nonce + 1} attempt(s): ${sha.slice(0, 12)}`)
57 return sha