Use the git -C flag instead of changing directories

c945a92bbe22b7562626d9667dd71b6050b79279

Tucker McKnight <tucker@pangolin.lan> | Sun Dec 07 2025

Use the git -C flag instead of changing directories

For some reason, when trying to generate the site in a git
post-receive hook, the `cd` command doesn't seem to be working.
Let's try it with git's built-in -C flag instead, which allows
you to specify the location of the git repo without actually
cd-ing into that directory.
js_templates/helpers/nav.ts:3
Before
2
3
4





5
6



7

export const NavHelper = (reposConfig: ReposConfiguration, slugify: Function, repoName: string, branchName: string) => {
  const reposPath = reposConfig.path || ""
⁣
⁣
⁣
⁣
⁣
  const rootPath = `${reposPath}/${slugify(repoName)}/branches`

⁣
⁣
⁣
  return {
    rootPath: () => {
After
2
3
4
5
6
7
8
9
10
11
12
13
14
15

export const NavHelper = (reposConfig: ReposConfiguration, slugify: Function, repoName: string, branchName: string) => {
  const reposPath = reposConfig.path || ""

  // These two aren't actually used by any pages, but they're in almost
  // every page URL. E.g. all of them start with 'repos/my-repo-name'
  // or 'repos/my-repo-name/branches.'
  const repoBasePath = `${reposPath}/${slugify(repoName)}`
  const rootBasePathBranches = `${repoBasePath}/branches`


  const currentBranchPath = `${rootBasePathBranches}/${slugify(branchName)}`

  return {
    rootPath: () => {
js_templates/helpers/nav.ts:15
Before
14
15
16
17
18


19
20
21
22
23
24
25
26
      }
    },
    repoHomePath: () => {
      return `${rootPath}/${slugify(reposConfig.repos[repoName].defaultBranch)}`
    },
⁣
⁣
    repoCurrentBranchHome: () => rootPath,
    repoCurrentBranchFiles: () => {
      return `${rootPath}/files`
    },
    repoCurrentBranchCommits: () => `${rootPath}/commits`,
    repoCurrentBranchBranches: () => `${rootPath}/branches`,
  }
}
After
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
      }
    },
    repoHomePath: () => {
      return `${rootBasePathBranches}/${slugify(reposConfig.repos[repoName].defaultBranch)}`
    },
    repoCurrentBranchHome: () => {
      return currentBranchPath
    },
    repoCurrentBranchFiles: () => {
      return `${currentBranchPath}/files`
    },
    repoCurrentBranchCommits: () => `${currentBranchPath}/commits`,
    repoCurrentBranchBranches: () => `${currentBranchPath}/branches`,
  }
}
main.ts:66
Before
65
66
67

68
69
70
71
72
73
74
75
76
77
78
        if (fsImport.existsSync(repoPath + ".git")) {
          // git repos are just in the repos folder, not in their subdir
          // create string of commands saying 'git fetch origin branch:branch' for each branch
⁣
          const fetchCommands = repoConfig.branchesToPull.map(branch => `git fetch origin ${branch}:${branch}`).join('; ')
          await exec(`(cd ${eleventyConfig.dir.output + reposPath + "/" + gitRepoName} && ${fetchCommands}; git update-server-info)`)
        } else {
          // If it is not there, do git clone
          // todo: does this work if the latest branch is not checked
          // out locally?
          const originalLocation = cwd + "/" + repoConfig.location
          await exec(`(cd ${eleventyConfig.dir.output + reposPath + "/"} && git clone ${originalLocation} ${gitRepoName} --bare)`)
          await exec(`(cd ${eleventyConfig.dir.output + reposPath + "/" + gitRepoName} && git update-server-info)`)
        }
        if (typeof repoConfig.artifactSteps !== 'undefined') {
          // make a temp directory for things to run in
After
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
        if (fsImport.existsSync(repoPath + ".git")) {
          // git repos are just in the repos folder, not in their subdir
          // create string of commands saying 'git fetch origin branch:branch' for each branch
          const location = eleventyConfig.dir.output + reposPath + "/" + gitRepoName
          const fetchCommands = repoConfig.branchesToPull.map(branch => `git -C ${location} fetch origin ${branch}:${branch}`).join('; ')
          await exec(`${fetchCommands} && git update-server-info`)
        } else {
          // If it is not there, do git clone
          // todo: does this work if the latest branch is not checked
          // out locally?
          const originalLocation = cwd + "/" + repoConfig.location
          await exec(`git clone ${originalLocation} ${eleventyConfig.dir.output + reposPath + "/" + gitRepoName} --bare`)
          await exec(`git -C ${eleventyConfig.dir.output + reposPath + "/" + gitRepoName} update-server-info`)
        }
        if (typeof repoConfig.artifactSteps !== 'undefined') {
          // make a temp directory for things to run in
main.ts:84
Before
83
84
85
86
87
88
          await exec(`mkdir ${tempDir}`)
          await exec(`git clone -s ${directories.output}${eleventyConfig.getFilter("slugify")(repoName)}.git ${tempDirRepoPath}`)
          for (let branch of repoConfig.branchesToPull) {
            await exec(`(cd ${tempDirRepoPath} && git checkout ${branch})`)
            for (let artifactStep of repoConfig.artifactSteps) {
              // Run the command for each step in each branch
              await exec(`(cd ${tempDirRepoPath} && ${artifactStep.command})`)
After
83
84
85
86
87
88
          await exec(`mkdir ${tempDir}`)
          await exec(`git clone -s ${directories.output}${eleventyConfig.getFilter("slugify")(repoName)}.git ${tempDirRepoPath}`)
          for (let branch of repoConfig.branchesToPull) {
            await exec(`git -C ${tempDirRepoPath} checkout ${branch}`)
            for (let artifactStep of repoConfig.artifactSteps) {
              // Run the command for each step in each branch
              await exec(`(cd ${tempDirRepoPath} && ${artifactStep.command})`)
main.ts:95
Before
94
95
96



97
98
          // delete the temp dirs
          await exec(`rm -r ${tempDir}`)
        }
⁣
⁣
⁣
      }
    }
  );
After
94
95
96
97
98
99
100
101
          // delete the temp dirs
          await exec(`rm -r ${tempDir}`)
        }

        const location = eleventyConfig.dir.output + reposPath + "/" + gitRepoName
        await exec(`git -C ${location} symbolic-ref HEAD refs/heads/${repoConfig.defaultBranch}`)
      }
    }
  );
main.ts:203
Before
202
203
204
205
206
207
208

  eleventyConfig.addAsyncFilter("getFileContents", async (repo: string, branch: string, filename: string) => {
    const location = getLocation(reposConfiguration, repo)
    const command = `git show ${branch}:${filename}`
    const res = await exec(`(cd ${location} && ${command})`)
    return res.stdout
  })
After
202
203
204
205
206
207
208

  eleventyConfig.addAsyncFilter("getFileContents", async (repo: string, branch: string, filename: string) => {
    const location = getLocation(reposConfiguration, repo)
    const command = `git -C ${location} show ${branch}:${filename}`
    const res = await exec(command)
    return res.stdout
  })
main.ts:222
Before
221
222
223
224
225
226
227
228

  eleventyConfig.addAsyncFilter("getReadMe", async (repoName: string, branchName: string) => {
    const location = getLocation(reposConfiguration, repoName)
    const command = `git show ${branchName}:README.md`
    try {
      const res = await exec(`(cd ${location} && ${command})`)
      return res.stdout
    } catch {
      return ""
After
221
222
223
224
225
226
227
228

  eleventyConfig.addAsyncFilter("getReadMe", async (repoName: string, branchName: string) => {
    const location = getLocation(reposConfiguration, repoName)
    const command = `git -C ${location} show ${branchName}:README.md`
    try {
      const res = await exec(command)
      return res.stdout
    } catch {
      return ""
src/repos.ts:42
Before
41
42
43
44
45
46

    const branches = await Promise.all(branchNames.map(async (branchName) => {
      const repoLocation = getLocation(reposConfig, repoName)
      const branchHeadRes = await exec(`(cd ${repoLocation} && git show-ref --branch ${branchName})`)
      const branchHead = branchHeadRes.stdout.split(" ")[0]
      return {
        name: branchName,
After
41
42
43
44
45
46

    const branches = await Promise.all(branchNames.map(async (branchName) => {
      const repoLocation = getLocation(reposConfig, repoName)
      const branchHeadRes = await exec(`git -C ${repoLocation} show-ref --branch ${branchName}`)
      const branchHead = branchHeadRes.stdout.split(" ")[0]
      return {
        name: branchName,
src/vcses/git/operations.ts:5
Before
4
5
6
7
8
9
10
11
import { type Repository } from '../../dataTypes.ts'

export const getFileList = async (branchName: string, repoLocation: string) => {
  const command = `git ls-tree -r --name-only ${branchName}`

  const result = await exec(`(cd ${repoLocation} && ${command})`)
  let files = result.stdout.split("\n").filter(item => item.length > 0 && item != ".")
  // TODO: this could be better. This is adding each sub-path of a file to a set, so that
  // we don't wind up with repeats, and then converting that back into an array. E.g. if
After
4
5
6
7
8
9
10
11
import { type Repository } from '../../dataTypes.ts'

export const getFileList = async (branchName: string, repoLocation: string) => {
  const command = `git -C ${repoLocation} ls-tree -r --name-only ${branchName}`

  const result = await exec(command)
  let files = result.stdout.split("\n").filter(item => item.length > 0 && item != ".")
  // TODO: this could be better. This is adding each sub-path of a file to a set, so that
  // we don't wind up with repeats, and then converting that back into an array. E.g. if
src/vcses/git/operations.ts:39
Before
38
39
40
41
42
43
44
45
46
47
}

export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise<void> => {
  const totalPatchesCountRes = await exec(`(cd ${repoLocation} && git rev-list --count ${branchName})`)
  const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
  let previousHash: null | string = null
  for (let i = 0; i < totalPatchesCount; i = i + 10) {
    const gitLogSubsetRes = await exec(`(cd ${repoLocation} && git log ${branchName} -p -n 10 --skip ${i})`)
    let gitLogSubset = gitLogSubsetRes.stdout.split("\n")
    do {
      const nextPatchStart = gitLogSubset.findIndex((line, index) => {
After
38
39
40
41
42
43
44
45
46
47
}

export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise<void> => {
  const totalPatchesCountRes = await exec(`git -C ${repoLocation} rev-list --count ${branchName}`)
  const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
  let previousHash: null | string = null
  for (let i = 0; i < totalPatchesCount; i = i + 10) {
    const gitLogSubsetRes = await exec(`git -C ${repoLocation} log ${branchName} -p -n 10 --skip ${i}`)
    let gitLogSubset = gitLogSubsetRes.stdout.split("\n")
    do {
      const nextPatchStart = gitLogSubset.findIndex((line, index) => {
src/vcses/git/operations.ts:99
Before
98
99
100
101
102
103
104

export const getFileLastTouchInfo = async (branch: string, filename: string, repoLocation: string) => {
  const regex = RegExp(".* [0-9]+ [0-9]+")
  const command = `git blame --porcelain ${branch} ${filename}`
  const res = await exec(`(cd ${repoLocation} && ${command})`)
  const output = res.stdout
  const outputLines = output.split("\n")
  const initialValue: Array<Array<string>> = [[outputLines[0]]]
After
98
99
100
101
102
103
104

export const getFileLastTouchInfo = async (branch: string, filename: string, repoLocation: string) => {
  const regex = RegExp(".* [0-9]+ [0-9]+")
  const command = `git -C ${repoLocation} blame --porcelain ${branch} ${filename}`
  const res = await exec(command)
  const output = res.stdout
  const outputLines = output.split("\n")
  const initialValue: Array<Array<string>> = [[outputLines[0]]]