UNPKG

2.65 kBJavaScriptView Raw
1import fs from 'node:fs/promises'
2import path from 'node:path'
3
4import debug from 'debug'
5import normalize from 'normalize-path'
6
7import { execGit } from './execGit.js'
8import { readFile } from './file.js'
9
10const debugLog = debug('lint-staged:resolveGitRepo')
11
12/**
13 * Resolve path to the .git directory, with special handling for
14 * submodules and worktrees
15 */
16const resolveGitConfigDir = async (gitDir) => {
17 // Get the real path in case it's a symlink
18 const defaultDir = normalize(await fs.realpath(path.join(gitDir, '.git')))
19 const stats = await fs.lstat(defaultDir)
20 // If .git is a directory, use it
21 if (stats.isDirectory()) return defaultDir
22 // Otherwise .git is a file containing path to real location
23 const file = (await readFile(defaultDir)).toString()
24 return path.resolve(gitDir, file.replace(/^gitdir: /, '')).trim()
25}
26
27// exported for test
28export const determineGitDir = (cwd, relativeDir) => {
29 // if relative dir and cwd have different endings normalize it
30 // this happens under windows, where normalize is unable to normalize git's output
31 if (relativeDir && relativeDir.endsWith(path.sep)) {
32 relativeDir = relativeDir.slice(0, -1)
33 }
34 if (relativeDir) {
35 // the current working dir is inside the git top-level directory
36 return normalize(cwd.substring(0, cwd.lastIndexOf(relativeDir)))
37 } else {
38 // the current working dir is the top-level git directory
39 return normalize(cwd)
40 }
41}
42
43/**
44 * Resolve git directory and possible submodule paths
45 */
46export const resolveGitRepo = async (cwd = process.cwd()) => {
47 try {
48 debugLog('Resolving git repo from `%s`', cwd)
49
50 // Unset GIT_DIR before running any git operations in case it's pointing to an incorrect location
51 debugLog('Unset GIT_DIR (was `%s`)', process.env.GIT_DIR)
52 delete process.env.GIT_DIR
53 debugLog('Unset GIT_WORK_TREE (was `%s`)', process.env.GIT_WORK_TREE)
54 delete process.env.GIT_WORK_TREE
55
56 // read the path of the current directory relative to the top-level directory
57 // don't read the toplevel directly, it will lead to an posix conform path on non posix systems (cygwin)
58 const gitRel = normalize(await execGit(['rev-parse', '--show-prefix'], { cwd }))
59 const gitDir = determineGitDir(normalize(cwd), gitRel)
60 const gitConfigDir = normalize(await resolveGitConfigDir(gitDir))
61
62 debugLog('Resolved git directory to be `%s`', gitDir)
63 debugLog('Resolved git config directory to be `%s`', gitConfigDir)
64
65 return { gitDir, gitConfigDir }
66 } catch (error) {
67 debugLog('Failed to resolve git repo with error:', error)
68 return { error, gitDir: null, gitConfigDir: null }
69 }
70}