git-chopstick-core 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -6
- package/dist/git/exec.js.map +1 -1
- package/dist/lib/fatal-error.d.ts +1 -1
- package/dist/lib/fatal-error.js +1 -1
- package/dist/lib/fatal-error.js.map +1 -1
- package/dist/lib/progress/from-process.js.map +1 -1
- package/dist/lib/progress/index.d.ts +5 -5
- package/dist/lib/progress/index.js +5 -5
- package/dist/lib/progress/index.js.map +1 -1
- package/dist/lib/status-parser.js +0 -12
- package/dist/lib/status-parser.js.map +1 -1
- package/package.json +38 -8
- package/src/git/add.ts +0 -16
- package/src/git/apply.ts +0 -154
- package/src/git/authentication.ts +0 -20
- package/src/git/branch.ts +0 -206
- package/src/git/checkout-index.ts +0 -40
- package/src/git/checkout.ts +0 -235
- package/src/git/cherry-pick.ts +0 -504
- package/src/git/clean.ts +0 -9
- package/src/git/clone.ts +0 -86
- package/src/git/coerce-to-buffer.ts +0 -4
- package/src/git/coerce-to-string.ts +0 -4
- package/src/git/commit.ts +0 -136
- package/src/git/config.ts +0 -392
- package/src/git/core.ts +0 -625
- package/src/git/create-tail-stream.ts +0 -36
- package/src/git/credential.ts +0 -83
- package/src/git/description.ts +0 -33
- package/src/git/diff-check.ts +0 -27
- package/src/git/diff-index.ts +0 -116
- package/src/git/diff.ts +0 -880
- package/src/git/environment.ts +0 -116
- package/src/git/exec.ts +0 -285
- package/src/git/fetch.ts +0 -141
- package/src/git/for-each-ref.ts +0 -160
- package/src/git/format-patch.ts +0 -17
- package/src/git/git-delimiter-parser.ts +0 -95
- package/src/git/gitignore.ts +0 -157
- package/src/git/index.ts +0 -46
- package/src/git/init.ts +0 -11
- package/src/git/interpret-trailers.ts +0 -176
- package/src/git/lfs.ts +0 -100
- package/src/git/log.ts +0 -376
- package/src/git/merge-tree.ts +0 -42
- package/src/git/merge.ts +0 -154
- package/src/git/multi-operation-terminal-output.ts +0 -68
- package/src/git/pull.ts +0 -130
- package/src/git/push-terminal-chunk.ts +0 -41
- package/src/git/push.ts +0 -119
- package/src/git/rebase.ts +0 -627
- package/src/git/reflog.ts +0 -127
- package/src/git/refs.ts +0 -63
- package/src/git/remote.ts +0 -143
- package/src/git/reorder.ts +0 -153
- package/src/git/reset.ts +0 -101
- package/src/git/rev-list.ts +0 -201
- package/src/git/rev-parse.ts +0 -92
- package/src/git/revert.ts +0 -55
- package/src/git/rm.ts +0 -31
- package/src/git/show.ts +0 -88
- package/src/git/spawn.ts +0 -38
- package/src/git/squash.ts +0 -173
- package/src/git/stage.ts +0 -97
- package/src/git/stash.ts +0 -302
- package/src/git/status.ts +0 -502
- package/src/git/submodule.ts +0 -212
- package/src/git/tag.ts +0 -134
- package/src/git/update-index.ts +0 -169
- package/src/git/update-ref.ts +0 -50
- package/src/git/var.ts +0 -42
- package/src/git/worktree-include.ts +0 -146
- package/src/git/worktree.ts +0 -219
- package/src/index.ts +0 -11
- package/src/lib/api.ts +0 -7
- package/src/lib/diff-parser.ts +0 -249
- package/src/lib/directory-exists.ts +0 -10
- package/src/lib/errno-exception.ts +0 -12
- package/src/lib/fatal-error.ts +0 -23
- package/src/lib/feature-flag.ts +0 -29
- package/src/lib/file-system.ts +0 -7
- package/src/lib/get-old-path.ts +0 -11
- package/src/lib/git/environment.ts +0 -14
- package/src/lib/git-perf.ts +0 -3
- package/src/lib/helpers/default-branch.ts +0 -3
- package/src/lib/helpers/path.ts +0 -5
- package/src/lib/hooks/with-hooks-env.ts +0 -7
- package/src/lib/merge.ts +0 -3
- package/src/lib/noop.ts +0 -1
- package/src/lib/patch-formatter.ts +0 -18
- package/src/lib/path-exists.ts +0 -7
- package/src/lib/progress/from-process.ts +0 -10
- package/src/lib/progress/index.ts +0 -43
- package/src/lib/progress/revert.ts +0 -17
- package/src/lib/rebase.ts +0 -3
- package/src/lib/remove-remote-prefix.ts +0 -4
- package/src/lib/resolve-git-proxy.ts +0 -3
- package/src/lib/round.ts +0 -4
- package/src/lib/split-buffer.ts +0 -14
- package/src/lib/status-parser.ts +0 -188
- package/src/lib/stores/helpers/find-default-remote.ts +0 -3
- package/src/lib/trampoline/trampoline-environment.ts +0 -8
- package/src/models/branch.ts +0 -78
- package/src/models/cherry-pick.ts +0 -12
- package/src/models/clone-options.ts +0 -6
- package/src/models/commit-identity.ts +0 -35
- package/src/models/commit.ts +0 -44
- package/src/models/computed-action.ts +0 -6
- package/src/models/diff/diff-data.ts +0 -78
- package/src/models/diff/diff-line.ts +0 -36
- package/src/models/diff/diff-selection.ts +0 -165
- package/src/models/diff/image-diff.ts +0 -6
- package/src/models/diff/image.ts +0 -8
- package/src/models/diff/index.ts +0 -6
- package/src/models/diff/raw-diff.ts +0 -41
- package/src/models/git-author.ts +0 -16
- package/src/models/index.ts +0 -36
- package/src/models/manual-conflict-resolution.ts +0 -4
- package/src/models/merge.ts +0 -6
- package/src/models/multi-commit-operation.ts +0 -6
- package/src/models/progress.ts +0 -67
- package/src/models/rebase.ts +0 -20
- package/src/models/remote.ts +0 -10
- package/src/models/repository.ts +0 -16
- package/src/models/stash-entry.ts +0 -25
- package/src/models/status.ts +0 -275
- package/src/models/submodule.ts +0 -13
- package/src/models/worktree.ts +0 -11
package/src/git/commit.ts
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { git, HookCallbackOptions, parseCommitSHA } from './core.js'
|
|
2
|
-
import { stageFiles } from './update-index.js'
|
|
3
|
-
import { Repository } from '../models/repository.js'
|
|
4
|
-
import { WorkingDirectoryFileChange } from '../models/status.js'
|
|
5
|
-
import { unstageAll } from './reset.js'
|
|
6
|
-
import { ManualConflictResolution } from '../models/manual-conflict-resolution.js'
|
|
7
|
-
import { stageManualConflictResolution } from './stage.js'
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* @param repository repository to execute merge in
|
|
11
|
-
* @param message commit message
|
|
12
|
-
* @param files files to commit
|
|
13
|
-
* @returns the commit SHA
|
|
14
|
-
*/
|
|
15
|
-
export async function createCommit(
|
|
16
|
-
repository: Repository,
|
|
17
|
-
message: string,
|
|
18
|
-
files: ReadonlyArray<WorkingDirectoryFileChange>,
|
|
19
|
-
options?: {
|
|
20
|
-
amend?: boolean
|
|
21
|
-
noVerify?: boolean
|
|
22
|
-
signOff?: boolean
|
|
23
|
-
allowEmpty?: boolean
|
|
24
|
-
} & HookCallbackOptions
|
|
25
|
-
): Promise<string> {
|
|
26
|
-
// Clear the staging area, our diffs reflect the difference between the
|
|
27
|
-
// working directory and the last commit (if any) so our commits should
|
|
28
|
-
// do the same thing.
|
|
29
|
-
await unstageAll(repository)
|
|
30
|
-
|
|
31
|
-
await stageFiles(repository, files)
|
|
32
|
-
|
|
33
|
-
const args = ['-F', '-']
|
|
34
|
-
|
|
35
|
-
if (options?.amend) {
|
|
36
|
-
args.push('--amend')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (options?.noVerify) {
|
|
40
|
-
args.push('--no-verify')
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (options?.signOff) {
|
|
44
|
-
args.push('--signoff')
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (options?.allowEmpty) {
|
|
48
|
-
args.push('--allow-empty')
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const result = await git(
|
|
52
|
-
['commit', ...args],
|
|
53
|
-
repository.path,
|
|
54
|
-
'createCommit',
|
|
55
|
-
{
|
|
56
|
-
stdin: message,
|
|
57
|
-
// https://git-scm.com/docs/githooks/2.46.1
|
|
58
|
-
interceptHooks: [
|
|
59
|
-
'pre-commit',
|
|
60
|
-
'prepare-commit-msg',
|
|
61
|
-
'commit-msg',
|
|
62
|
-
'post-commit',
|
|
63
|
-
...(options?.amend ? ['post-rewrite'] : []),
|
|
64
|
-
'pre-auto-gc',
|
|
65
|
-
],
|
|
66
|
-
onHookProgress: options?.onHookProgress,
|
|
67
|
-
onHookFailure: options?.onHookFailure,
|
|
68
|
-
onTerminalOutputAvailable: options?.onTerminalOutputAvailable,
|
|
69
|
-
}
|
|
70
|
-
)
|
|
71
|
-
return parseCommitSHA(result)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Creates a commit to finish an in-progress merge
|
|
76
|
-
* assumes that all conflicts have already been resolved
|
|
77
|
-
* *Warning:* Does _not_ clear staged files before it commits!
|
|
78
|
-
*
|
|
79
|
-
* @param repository repository to execute merge in
|
|
80
|
-
* @param files files to commit
|
|
81
|
-
*/
|
|
82
|
-
export async function createMergeCommit(
|
|
83
|
-
repository: Repository,
|
|
84
|
-
files: ReadonlyArray<WorkingDirectoryFileChange>,
|
|
85
|
-
manualResolutions: ReadonlyMap<string, ManualConflictResolution> = new Map()
|
|
86
|
-
): Promise<string> {
|
|
87
|
-
// apply manual conflict resolutions
|
|
88
|
-
for (const [path, resolution] of manualResolutions) {
|
|
89
|
-
const file = files.find(f => f.path === path)
|
|
90
|
-
if (file !== undefined) {
|
|
91
|
-
await stageManualConflictResolution(repository, file, resolution)
|
|
92
|
-
} else {
|
|
93
|
-
console.error(
|
|
94
|
-
`couldn't find file ${path} even though there's a manual resolution for it`
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const otherFiles = files.filter(f => !manualResolutions.has(f.path))
|
|
100
|
-
|
|
101
|
-
await stageFiles(repository, otherFiles)
|
|
102
|
-
const result = await git(
|
|
103
|
-
[
|
|
104
|
-
'commit',
|
|
105
|
-
// no-edit here ensures the app does not accidentally invoke the user's editor
|
|
106
|
-
'--no-edit',
|
|
107
|
-
// By default Git merge commits do not contain any commentary (which
|
|
108
|
-
// are lines prefixed with `#`). This works because the Git CLI will
|
|
109
|
-
// prompt the user to edit the file in `.git/COMMIT_MSG` before
|
|
110
|
-
// committing, and then it will run `--cleanup=strip`.
|
|
111
|
-
//
|
|
112
|
-
// This clashes with our use of `--no-edit` above as Git will now change
|
|
113
|
-
// it's behavior to invoke `--cleanup=whitespace` as it did not ask
|
|
114
|
-
// the user to edit the COMMIT_MSG as part of creating a commit.
|
|
115
|
-
//
|
|
116
|
-
// From the docs on git-commit (https://git-scm.com/docs/git-commit) I'll
|
|
117
|
-
// quote the relevant section:
|
|
118
|
-
// --cleanup=<mode>
|
|
119
|
-
// strip
|
|
120
|
-
// Strip leading and trailing empty lines, trailing whitespace,
|
|
121
|
-
// commentary and collapse consecutive empty lines.
|
|
122
|
-
// whitespace
|
|
123
|
-
// Same as `strip` except #commentary is not removed.
|
|
124
|
-
// default
|
|
125
|
-
// Same as `strip` if the message is to be edited. Otherwise `whitespace`.
|
|
126
|
-
//
|
|
127
|
-
// We should emulate the behavior in this situation because we don't
|
|
128
|
-
// let the user view or change the commit message before making the
|
|
129
|
-
// commit.
|
|
130
|
-
'--cleanup=strip',
|
|
131
|
-
],
|
|
132
|
-
repository.path,
|
|
133
|
-
'createMergeCommit'
|
|
134
|
-
)
|
|
135
|
-
return parseCommitSHA(result)
|
|
136
|
-
}
|
package/src/git/config.ts
DELETED
|
@@ -1,392 +0,0 @@
|
|
|
1
|
-
import { git } from './core.js'
|
|
2
|
-
import { Repository } from '../models/repository.js'
|
|
3
|
-
import { normalize } from 'path'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Look up a config value by name in the repository.
|
|
7
|
-
*
|
|
8
|
-
* @param onlyLocal Whether or not the value to be retrieved should stick to
|
|
9
|
-
* the local repository settings. It is false by default. This
|
|
10
|
-
* is equivalent to using the `--local` argument in the
|
|
11
|
-
* `git config` invocation.
|
|
12
|
-
*/
|
|
13
|
-
export function getConfigValue(
|
|
14
|
-
repository: Repository,
|
|
15
|
-
name: string,
|
|
16
|
-
onlyLocal: boolean = false
|
|
17
|
-
): Promise<string | null> {
|
|
18
|
-
return getConfigValueInPath(name, repository.path, onlyLocal)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/** Look up a global config value by name. */
|
|
22
|
-
export function getGlobalConfigValue(
|
|
23
|
-
name: string,
|
|
24
|
-
env?: {
|
|
25
|
-
HOME: string
|
|
26
|
-
}
|
|
27
|
-
): Promise<string | null> {
|
|
28
|
-
return getConfigValueInPath(name, null, false, undefined, env)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Look up a config value by name.
|
|
33
|
-
*
|
|
34
|
-
* Treats the returned value as a boolean as per Git's
|
|
35
|
-
* own definition of a boolean configuration value (i.e.
|
|
36
|
-
* 0 -> false, "off" -> false, "yes" -> true etc)
|
|
37
|
-
*/
|
|
38
|
-
export async function getBooleanConfigValue(
|
|
39
|
-
repository: Repository,
|
|
40
|
-
name: string,
|
|
41
|
-
onlyLocal: boolean = false,
|
|
42
|
-
env?: {
|
|
43
|
-
HOME: string
|
|
44
|
-
}
|
|
45
|
-
): Promise<boolean | null> {
|
|
46
|
-
const value = await getConfigValueInPath(
|
|
47
|
-
name,
|
|
48
|
-
repository.path,
|
|
49
|
-
onlyLocal,
|
|
50
|
-
'bool',
|
|
51
|
-
env
|
|
52
|
-
)
|
|
53
|
-
return value === null ? null : value !== 'false'
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* Look up a global config value by name.
|
|
58
|
-
*
|
|
59
|
-
* Treats the returned value as a boolean as per Git's
|
|
60
|
-
* own definition of a boolean configuration value (i.e.
|
|
61
|
-
* 0 -> false, "off" -> false, "yes" -> true etc)
|
|
62
|
-
*/
|
|
63
|
-
export async function getGlobalBooleanConfigValue(
|
|
64
|
-
name: string,
|
|
65
|
-
env?: {
|
|
66
|
-
HOME: string
|
|
67
|
-
}
|
|
68
|
-
): Promise<boolean | null> {
|
|
69
|
-
const value = await getConfigValueInPath(name, null, false, 'bool', env)
|
|
70
|
-
return value === null ? null : value !== 'false'
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Look up a config value by name
|
|
75
|
-
*
|
|
76
|
-
* @param path The path to execute the `git` command in. If null
|
|
77
|
-
* we'll use the global configuration (i.e. --global)
|
|
78
|
-
* and execute the Git call from the same location that
|
|
79
|
-
* GitHub Desktop is installed in.
|
|
80
|
-
* @param onlyLocal Whether or not the value to be retrieved should stick to
|
|
81
|
-
* the local repository settings (if a path is specified). It
|
|
82
|
-
* is false by default. It is equivalent to using the `--local`
|
|
83
|
-
* argument in the `git config` invocation.
|
|
84
|
-
* @param type Canonicalize configuration values according to the
|
|
85
|
-
* expected type (i.e. 0 -> false, "on" -> true etc).
|
|
86
|
-
* See `--type` documentation in `git config`
|
|
87
|
-
*/
|
|
88
|
-
async function getConfigValueInPath(
|
|
89
|
-
name: string,
|
|
90
|
-
path: string | null,
|
|
91
|
-
onlyLocal: boolean = false,
|
|
92
|
-
type?: 'bool' | 'int' | 'bool-or-int' | 'path' | 'expiry-date' | 'color',
|
|
93
|
-
env?: {
|
|
94
|
-
HOME: string
|
|
95
|
-
}
|
|
96
|
-
): Promise<string | null> {
|
|
97
|
-
const flags = ['config', '-z']
|
|
98
|
-
if (!path) {
|
|
99
|
-
flags.push('--global')
|
|
100
|
-
} else if (onlyLocal) {
|
|
101
|
-
flags.push('--local')
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (type !== undefined) {
|
|
105
|
-
flags.push('--type', type)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
flags.push(name)
|
|
109
|
-
|
|
110
|
-
const result = await git(flags, path || __dirname, 'getConfigValueInPath', {
|
|
111
|
-
successExitCodes: new Set([0, 1]),
|
|
112
|
-
env,
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
// Git exits with 1 if the value isn't found. That's OK.
|
|
116
|
-
if (result.exitCode === 1) {
|
|
117
|
-
return null
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const output = result.stdout
|
|
121
|
-
const pieces = output.split('\0')
|
|
122
|
-
return pieces[0]
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* Get the path to the global git config
|
|
127
|
-
*
|
|
128
|
-
* Note: this uses git config --edit which will automatically create the global
|
|
129
|
-
* config file if it doesn't exist yet. The primary purpose behind this method
|
|
130
|
-
* is to support opening the global git config for editing.
|
|
131
|
-
*/
|
|
132
|
-
export const getGlobalConfigPath = (env?: { HOME: string }) =>
|
|
133
|
-
git(['config', '--edit', '--global'], __dirname, 'getGlobalConfigPath', {
|
|
134
|
-
// We're using printf instead of echo because echo could attempt to decode
|
|
135
|
-
// escape sequences like \n which would be bad in a case like
|
|
136
|
-
// c:\Users\niik\.gitconfig
|
|
137
|
-
// ^^
|
|
138
|
-
env: { ...env, GIT_EDITOR: 'printf %s' },
|
|
139
|
-
}).then(x => normalize(x.stdout))
|
|
140
|
-
|
|
141
|
-
/** Set the local config value by name. */
|
|
142
|
-
export async function setConfigValue(
|
|
143
|
-
repository: Repository,
|
|
144
|
-
name: string,
|
|
145
|
-
value: string,
|
|
146
|
-
env?: {
|
|
147
|
-
HOME: string
|
|
148
|
-
}
|
|
149
|
-
): Promise<void> {
|
|
150
|
-
return setConfigValueInPath(name, value, repository.path, env)
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
/** Set the global config value by name. */
|
|
154
|
-
export async function setGlobalConfigValue(
|
|
155
|
-
name: string,
|
|
156
|
-
value: string,
|
|
157
|
-
env?: {
|
|
158
|
-
HOME: string
|
|
159
|
-
}
|
|
160
|
-
): Promise<void> {
|
|
161
|
-
return setConfigValueInPath(name, value, null, env)
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/** Set the global config value by name. */
|
|
165
|
-
export async function addGlobalConfigValue(
|
|
166
|
-
name: string,
|
|
167
|
-
value: string
|
|
168
|
-
): Promise<void> {
|
|
169
|
-
await git(
|
|
170
|
-
['config', '--global', '--add', name, value],
|
|
171
|
-
__dirname,
|
|
172
|
-
'addGlobalConfigValue'
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Adds a path to the `safe.directories` configuration variable if it's not
|
|
178
|
-
* already present. Adding a path to `safe.directory` will cause Git to ignore
|
|
179
|
-
* if the path is owner by a different user than the current.
|
|
180
|
-
*/
|
|
181
|
-
export async function addSafeDirectory(path: string) {
|
|
182
|
-
// UNC-paths on Windows need to be prefixed with `%(prefix)/`, see
|
|
183
|
-
// https://github.com/git-for-windows/git/commit/e394a16023cbb62784e380f70ad8a833fb960d68
|
|
184
|
-
if (process.platform === 'win32' && path[0] === '/') {
|
|
185
|
-
path = `%(prefix)/${path}`
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
await addGlobalConfigValueIfMissing('safe.directory', path)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/** Set the global config value by name. */
|
|
192
|
-
export async function addGlobalConfigValueIfMissing(
|
|
193
|
-
name: string,
|
|
194
|
-
value: string
|
|
195
|
-
): Promise<void> {
|
|
196
|
-
const { stdout, exitCode } = await git(
|
|
197
|
-
['config', '--global', '-z', '--get-all', name, value],
|
|
198
|
-
__dirname,
|
|
199
|
-
'addGlobalConfigValue',
|
|
200
|
-
{ successExitCodes: new Set([0, 1]) }
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
if (exitCode === 1 || !stdout.split('\0').includes(value)) {
|
|
204
|
-
await addGlobalConfigValue(name, value)
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Set config value by name
|
|
210
|
-
*
|
|
211
|
-
* @param path The path to execute the `git` command in. If null
|
|
212
|
-
* we'll use the global configuration (i.e. --global)
|
|
213
|
-
* and execute the Git call from the same location that
|
|
214
|
-
* GitHub Desktop is installed in.
|
|
215
|
-
*/
|
|
216
|
-
async function setConfigValueInPath(
|
|
217
|
-
name: string,
|
|
218
|
-
value: string,
|
|
219
|
-
path: string | null,
|
|
220
|
-
env?: {
|
|
221
|
-
HOME: string
|
|
222
|
-
}
|
|
223
|
-
): Promise<void> {
|
|
224
|
-
const options = env ? { env } : undefined
|
|
225
|
-
|
|
226
|
-
const flags = ['config']
|
|
227
|
-
|
|
228
|
-
if (!path) {
|
|
229
|
-
flags.push('--global')
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
flags.push('--replace-all', name, value)
|
|
233
|
-
|
|
234
|
-
await git(flags, path || __dirname, 'setConfigValueInPath', options)
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/** Remove the local config value by name. */
|
|
238
|
-
export async function removeConfigValue(
|
|
239
|
-
repository: Repository,
|
|
240
|
-
name: string,
|
|
241
|
-
env?: {
|
|
242
|
-
HOME: string
|
|
243
|
-
}
|
|
244
|
-
): Promise<void> {
|
|
245
|
-
return removeConfigValueInPath(name, repository.path, env)
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/** Remove the global config value by name. */
|
|
249
|
-
export async function removeGlobalConfigValue(
|
|
250
|
-
name: string,
|
|
251
|
-
env?: {
|
|
252
|
-
HOME: string
|
|
253
|
-
}
|
|
254
|
-
): Promise<void> {
|
|
255
|
-
return removeConfigValueInPath(name, null, env)
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Remove config value by name
|
|
260
|
-
*
|
|
261
|
-
* @param path The path to execute the `git` command in. If null
|
|
262
|
-
* we'll use the global configuration (i.e. --global)
|
|
263
|
-
* and execute the Git call from the same location that
|
|
264
|
-
* GitHub Desktop is installed in.
|
|
265
|
-
*/
|
|
266
|
-
async function removeConfigValueInPath(
|
|
267
|
-
name: string,
|
|
268
|
-
path: string | null,
|
|
269
|
-
env?: {
|
|
270
|
-
HOME: string
|
|
271
|
-
}
|
|
272
|
-
): Promise<void> {
|
|
273
|
-
const options = env ? { env } : undefined
|
|
274
|
-
|
|
275
|
-
const flags = ['config']
|
|
276
|
-
|
|
277
|
-
if (!path) {
|
|
278
|
-
flags.push('--global')
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
flags.push('--unset-all', name)
|
|
282
|
-
|
|
283
|
-
await git(flags, path || __dirname, 'removeConfigValueInPath', options)
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
export interface IConfigValueOrigin {
|
|
287
|
-
readonly value: string
|
|
288
|
-
readonly scope: string
|
|
289
|
-
readonly origin: string
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Look up a config value along with its source file and scope.
|
|
294
|
-
* Requires Git 2.26+ for --show-scope.
|
|
295
|
-
*/
|
|
296
|
-
export async function getConfigValueWithOrigin(
|
|
297
|
-
repository: Repository,
|
|
298
|
-
name: string
|
|
299
|
-
): Promise<IConfigValueOrigin | null> {
|
|
300
|
-
const result = await git(
|
|
301
|
-
['config', '--show-origin', '--show-scope', '-z', name],
|
|
302
|
-
repository.path,
|
|
303
|
-
'getConfigValueWithOrigin',
|
|
304
|
-
// 0 = found, 1 = key not set, 128 = not a git repo or git error
|
|
305
|
-
{ successExitCodes: new Set([0, 1, 128]) }
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
if (result.exitCode !== 0) {
|
|
309
|
-
return null
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
const parts = result.stdout.split('\0')
|
|
313
|
-
if (parts.length >= 3) {
|
|
314
|
-
return {
|
|
315
|
-
scope: parts[0],
|
|
316
|
-
origin: parts[1],
|
|
317
|
-
value: parts[2],
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
return null
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Extract the file path from a config value origin, stripping the `file:` prefix.
|
|
326
|
-
* When repositoryPath is provided, relative paths (e.g. `.git/config` for local
|
|
327
|
-
* scope) are resolved to absolute paths.
|
|
328
|
-
*/
|
|
329
|
-
export function getOriginFilePath(
|
|
330
|
-
origin: IConfigValueOrigin,
|
|
331
|
-
repositoryPath?: string
|
|
332
|
-
): string {
|
|
333
|
-
const filePath = origin.origin.replace(/^file:/, '')
|
|
334
|
-
// Git returns relative paths for local/worktree scope (e.g. `.git/config`)
|
|
335
|
-
if (repositoryPath && !/^([a-zA-Z]:|[/\\])/.test(filePath)) {
|
|
336
|
-
const base = repositoryPath.replace(/[\\/]+$/, '')
|
|
337
|
-
return `${base}/${filePath}`
|
|
338
|
-
}
|
|
339
|
-
return filePath
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/**
|
|
343
|
-
* Check whether a global-scoped config value comes from a conditionally
|
|
344
|
-
* included file (via includeIf directive) rather than a standard location.
|
|
345
|
-
*/
|
|
346
|
-
export function isConditionalInclude(origin: IConfigValueOrigin): boolean {
|
|
347
|
-
if (origin.scope !== 'global') {
|
|
348
|
-
return false
|
|
349
|
-
}
|
|
350
|
-
const filePath = getOriginFilePath(origin)
|
|
351
|
-
return (
|
|
352
|
-
!/[/\\]\.gitconfig$/i.test(filePath) &&
|
|
353
|
-
!/[/\\]\.config[/\\]git[/\\]config$/i.test(filePath)
|
|
354
|
-
)
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
/** Format a human-readable scope description for a config value origin. */
|
|
358
|
-
export function formatConfigScope(origin: IConfigValueOrigin): string {
|
|
359
|
-
if (origin.scope === 'local') {
|
|
360
|
-
return 'local'
|
|
361
|
-
} else if (origin.scope === 'system') {
|
|
362
|
-
return 'system'
|
|
363
|
-
} else if (origin.scope === 'worktree') {
|
|
364
|
-
return 'worktree'
|
|
365
|
-
} else if (origin.scope === 'global') {
|
|
366
|
-
return isConditionalInclude(origin) ? 'global, via [includeIf]' : 'global'
|
|
367
|
-
}
|
|
368
|
-
return origin.scope
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Format the file path for a config value origin.
|
|
373
|
-
* For local/worktree scope, displays the path with a `<repo>` prefix.
|
|
374
|
-
*/
|
|
375
|
-
export function formatConfigPath(
|
|
376
|
-
origin: IConfigValueOrigin,
|
|
377
|
-
repositoryPath: string
|
|
378
|
-
): string {
|
|
379
|
-
const rawPath = origin.origin.replace(/^file:/, '')
|
|
380
|
-
if (origin.scope === 'local' || origin.scope === 'worktree') {
|
|
381
|
-
// Git returns relative paths for local scope (e.g. `.git/config`)
|
|
382
|
-
if (!/^([a-zA-Z]:|[/\\])/.test(rawPath)) {
|
|
383
|
-
return '<repo>/' + rawPath
|
|
384
|
-
}
|
|
385
|
-
// Absolute path — strip repo prefix
|
|
386
|
-
const normalized = repositoryPath.replace(/[\\/]+$/, '')
|
|
387
|
-
if (rawPath.toLowerCase().startsWith(normalized.toLowerCase())) {
|
|
388
|
-
return '<repo>' + rawPath.slice(normalized.length)
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
return rawPath
|
|
392
|
-
}
|