-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstaged.ts
More file actions
194 lines (188 loc) · 6.4 KB
/
staged.ts
File metadata and controls
194 lines (188 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/**
* @file "Ready for the next commit" helpers — `git diff --cached` over only the
* index. Excludes unstaged tracked-file edits and untracked paths; use
* `changed.ts` if you need the broader view.
*/
import { normalizePath } from '../paths/normalize'
import { ArrayPrototypeIncludes } from '../primordials/array'
import { getGitDiffSpawnArgs, innerDiff, innerDiffSync } from './_internal'
import { getCachedRealpath, getCwd, getPath } from './repo'
import type { GitDiffOptions } from './types'
/**
* Get staged files ready for commit (changes added with `git add`).
*
* Uses `git diff --cached --name-only` which returns only staged changes. Does
* NOT include: - Unstaged modifications (changes not added with `git add`) -
* Untracked files (new files not added to git)
*
* This is a focused check for what will be included in the next commit. Useful
* for validating changes before committing or running pre-commit hooks.
*
* @example
* ;```typescript
* // Get currently staged files
* const files = await getStagedFiles()
* // => ['src/foo.ts']
*
* // Stage more files
* await spawn('git', ['add', 'src/bar.ts'])
* const files = await getStagedFiles()
* // => ['src/foo.ts', 'src/bar.ts']
*
* // Get absolute paths
* const files = await getStagedFiles({ absolute: true })
* // => ['/path/to/repo/src/foo.ts', ...]
* ```
*
* @param options - Options controlling path format and filtering.
*
* @returns Promise resolving to array of staged file paths.
*/
export async function getStagedFiles(
options?: GitDiffOptions | undefined,
): Promise<string[]> {
const args = getGitDiffSpawnArgs(options?.cwd).staged
return await innerDiff(args, options)
}
/**
* Get staged files ready for commit (changes added with `git add`).
*
* Synchronous version of `getStagedFiles()`. Uses `git diff --cached
* --name-only` which returns only staged changes. Does NOT include: - Unstaged
* modifications (changes not added with `git add`) - Untracked files (new files
* not added to git)
*
* This is a focused check for what will be included in the next commit. Useful
* for validating changes before committing or running pre-commit hooks.
*
* @example
* ;```typescript
* // Get currently staged files
* const files = getStagedFilesSync()
* // => ['src/foo.ts']
*
* // Stage more files
* spawnSync('git', ['add', 'src/bar.ts'])
* const files = getStagedFilesSync()
* // => ['src/foo.ts', 'src/bar.ts']
*
* // Get absolute paths
* const files = getStagedFilesSync({ absolute: true })
* // => ['/path/to/repo/src/foo.ts', ...]
* ```
*
* @param options - Options controlling path format and filtering.
*
* @returns Array of staged file paths.
*/
export function getStagedFilesSync(
options?: GitDiffOptions | undefined,
): string[] {
const args = getGitDiffSpawnArgs(options?.cwd).staged
return innerDiffSync(args, options)
}
/**
* Check if a file or directory is staged for commit.
*
* Checks if the given pathname has changes staged with `git add` that will be
* included in the next commit. Does NOT include: - Unstaged modifications
* (changes not added with `git add`) - Untracked files (new files not in git)
*
* For directories, returns `true` if ANY file within the directory is staged.
*
* Symlinks in the pathname and cwd are automatically resolved using
* `fs.realpathSync()` before comparison.
*
* @example
* ;```typescript
* // Check if file is staged
* const staged = await isStaged('src/foo.ts')
* // => false
*
* // Stage the file
* await spawn('git', ['add', 'src/foo.ts'])
* const staged = await isStaged('src/foo.ts')
* // => true
*
* // Check directory
* const staged = await isStaged('src/')
* // => true (if any file in src/ is staged)
* ```
*
* @param pathname - File or directory path to check.
* @param options - Options for the git diff check.
*
* @returns Promise resolving to `true` if path is staged, `false` otherwise.
*/
export async function isStaged(
pathname: string,
options?: GitDiffOptions | undefined,
): Promise<boolean> {
const files = await getStagedFiles({
__proto__: null,
...options,
absolute: false,
})
const path = getPath()
// Resolve pathname to handle symlinks before computing relative path (using cache).
const resolvedPathname = getCachedRealpath(pathname)
// options.cwd-passed arm exercised when caller specifies cwd; default getCwd().
/* c8 ignore start */
const baseCwd = options?.cwd ? getCachedRealpath(options['cwd']) : getCwd()
/* c8 ignore stop */
const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))
return ArrayPrototypeIncludes(files, relativePath)
}
/**
* Check if a file or directory is staged for commit.
*
* Synchronous version of `isStaged()`. Checks if the given pathname has changes
* staged with `git add` that will be included in the next commit. Does NOT
* include: - Unstaged modifications (changes not added with `git add`) -
* Untracked files (new files not in git)
*
* For directories, returns `true` if ANY file within the directory is staged.
*
* Symlinks in the pathname and cwd are automatically resolved using
* `fs.realpathSync()` before comparison.
*
* @example
* ;```typescript
* // Check if file is staged
* const staged = isStagedSync('src/foo.ts')
* // => false
*
* // Stage the file
* spawnSync('git', ['add', 'src/foo.ts'])
* const staged = isStagedSync('src/foo.ts')
* // => true
*
* // Check directory
* const staged = isStagedSync('src/')
* // => true (if any file in src/ is staged)
* ```
*
* @param pathname - File or directory path to check.
* @param options - Options for the git diff check.
*
* @returns `true` if path is staged, `false` otherwise.
*/
export function isStagedSync(
pathname: string,
options?: GitDiffOptions | undefined,
): boolean {
const files = getStagedFilesSync({
__proto__: null,
...options,
absolute: false,
})
const path = getPath()
// Resolve pathname to handle symlinks before computing relative path (using cache).
const resolvedPathname = getCachedRealpath(pathname)
// options.cwd-passed arm exercised when caller specifies cwd; default getCwd().
/* c8 ignore start */
const baseCwd = options?.cwd ? getCachedRealpath(options['cwd']) : getCwd()
/* c8 ignore stop */
const relativePath = normalizePath(path.relative(baseCwd, resolvedPathname))
return ArrayPrototypeIncludes(files, relativePath)
}