isomorphic-git 1.40.0 → 1.40.2
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/index.cjs +92 -39
- package/index.js +92 -39
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +59 -26
- package/managers/index.js +59 -26
- package/managers/index.umd.min.js +1 -1
- package/managers/index.umd.min.js.map +1 -1
- package/package.json +1 -1
package/index.cjs
CHANGED
|
@@ -1332,6 +1332,23 @@ class InvalidOidError extends BaseError {
|
|
|
1332
1332
|
/** @type {'InvalidOidError'} */
|
|
1333
1333
|
InvalidOidError.code = 'InvalidOidError';
|
|
1334
1334
|
|
|
1335
|
+
class InvalidRefNameError extends BaseError {
|
|
1336
|
+
/**
|
|
1337
|
+
* @param {string} ref
|
|
1338
|
+
* @param {string} suggestion
|
|
1339
|
+
* @param {boolean} canForce
|
|
1340
|
+
*/
|
|
1341
|
+
constructor(ref, suggestion) {
|
|
1342
|
+
super(
|
|
1343
|
+
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
1344
|
+
);
|
|
1345
|
+
this.code = this.name = InvalidRefNameError.code;
|
|
1346
|
+
this.data = { ref, suggestion };
|
|
1347
|
+
}
|
|
1348
|
+
}
|
|
1349
|
+
/** @type {'InvalidRefNameError'} */
|
|
1350
|
+
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
1351
|
+
|
|
1335
1352
|
class NoRefspecError extends BaseError {
|
|
1336
1353
|
/**
|
|
1337
1354
|
* @param {string} remote
|
|
@@ -2003,6 +2020,16 @@ const refpaths = ref => [
|
|
|
2003
2020
|
// @see https://git-scm.com/docs/gitrepository-layout
|
|
2004
2021
|
const GIT_FILES = ['config', 'description', 'index', 'shallow', 'commondir'];
|
|
2005
2022
|
|
|
2023
|
+
// These names are legal one-level ref names, so nothing upstream of here
|
|
2024
|
+
// rejects them, and writing to one lands on the repository file itself.
|
|
2025
|
+
// Canonical git refuses too: `git update-ref index <oid>` fails with
|
|
2026
|
+
// "cannot lock ref 'index': reference broken" and leaves the file alone.
|
|
2027
|
+
function assertWritableRef(ref) {
|
|
2028
|
+
if (GIT_FILES.includes(ref)) {
|
|
2029
|
+
throw new InvalidRefNameError(ref, `refs/heads/${ref}`)
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2006
2033
|
let lock$1;
|
|
2007
2034
|
|
|
2008
2035
|
async function acquireLock(ref, callback) {
|
|
@@ -2057,6 +2084,31 @@ class GitRefManager {
|
|
|
2057
2084
|
}
|
|
2058
2085
|
const refspec = GitRefSpecSet.from(refspecs);
|
|
2059
2086
|
const actualRefsToWrite = new Map();
|
|
2087
|
+
// Work out every destination this call will write, before touching the
|
|
2088
|
+
// repository. Translating is pure, so it can happen up here; the writes
|
|
2089
|
+
// themselves stay at the end of the function.
|
|
2090
|
+
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2091
|
+
const symrefTranslations = [];
|
|
2092
|
+
for (const [serverRef, translatedRef] of refspec.translate([
|
|
2093
|
+
...symrefs.keys(),
|
|
2094
|
+
])) {
|
|
2095
|
+
const symtarget = refspec.translateOne(symrefs.get(serverRef));
|
|
2096
|
+
if (symtarget) {
|
|
2097
|
+
symrefTranslations.push([translatedRef, `ref: ${symtarget}`]);
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
// The local side of a refspec is whatever `remote.<name>.fetch` says, so a
|
|
2101
|
+
// config like `+refs/heads/main:index` lands a write on `.git/index`.
|
|
2102
|
+
// Refuse it here rather than at the write loop: `pruneTags` and `prune`
|
|
2103
|
+
// delete refs in between, so a later throw leaves the repository pruned
|
|
2104
|
+
// and not updated. The tags added below are always `refs/tags/...`, which
|
|
2105
|
+
// is never a system file, so nothing is missed by checking this early.
|
|
2106
|
+
for (const [, translatedRef] of refTranslations) {
|
|
2107
|
+
assertWritableRef(translatedRef);
|
|
2108
|
+
}
|
|
2109
|
+
for (const [translatedRef] of symrefTranslations) {
|
|
2110
|
+
assertWritableRef(translatedRef);
|
|
2111
|
+
}
|
|
2060
2112
|
// Delete all current tags if the pruneTags argument is true.
|
|
2061
2113
|
if (pruneTags) {
|
|
2062
2114
|
const tags = await GitRefManager.listRefs({
|
|
@@ -2084,18 +2136,12 @@ class GitRefManager {
|
|
|
2084
2136
|
}
|
|
2085
2137
|
}
|
|
2086
2138
|
// Combine refs and symrefs giving symrefs priority
|
|
2087
|
-
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2088
2139
|
for (const [serverRef, translatedRef] of refTranslations) {
|
|
2089
2140
|
const value = refs.get(serverRef);
|
|
2090
2141
|
actualRefsToWrite.set(translatedRef, value);
|
|
2091
2142
|
}
|
|
2092
|
-
const
|
|
2093
|
-
|
|
2094
|
-
const value = symrefs.get(serverRef);
|
|
2095
|
-
const symtarget = refspec.translateOne(value);
|
|
2096
|
-
if (symtarget) {
|
|
2097
|
-
actualRefsToWrite.set(translatedRef, `ref: ${symtarget}`);
|
|
2098
|
-
}
|
|
2143
|
+
for (const [translatedRef, value] of symrefTranslations) {
|
|
2144
|
+
actualRefsToWrite.set(translatedRef, value);
|
|
2099
2145
|
}
|
|
2100
2146
|
// If `prune` argument is true, clear out the existing local refspec roots
|
|
2101
2147
|
const pruned = [];
|
|
@@ -2154,6 +2200,7 @@ class GitRefManager {
|
|
|
2154
2200
|
// TODO: make this less crude?
|
|
2155
2201
|
static async writeRef({ fs, gitdir, ref, value }) {
|
|
2156
2202
|
// Validate input
|
|
2203
|
+
assertWritableRef(ref);
|
|
2157
2204
|
if (!value.match(/[0-9a-f]{40}/)) {
|
|
2158
2205
|
throw new InvalidOidError(value)
|
|
2159
2206
|
}
|
|
@@ -2173,6 +2220,7 @@ class GitRefManager {
|
|
|
2173
2220
|
* @returns {Promise<void>}
|
|
2174
2221
|
*/
|
|
2175
2222
|
static async writeSymbolicRef({ fs, gitdir, ref, value }) {
|
|
2223
|
+
assertWritableRef(ref);
|
|
2176
2224
|
await acquireLock(ref, async () =>
|
|
2177
2225
|
fs.write(join(gitdir, ref), 'ref: ' + `${value.trim()}\n`, 'utf8')
|
|
2178
2226
|
);
|
|
@@ -2201,6 +2249,8 @@ class GitRefManager {
|
|
|
2201
2249
|
* @returns {Promise<void>}
|
|
2202
2250
|
*/
|
|
2203
2251
|
static async deleteRefs({ fs, gitdir, refs }) {
|
|
2252
|
+
// Validate input
|
|
2253
|
+
refs.forEach(assertWritableRef);
|
|
2204
2254
|
// Delete regular ref
|
|
2205
2255
|
await Promise.all(refs.map(ref => fs.rm(join(gitdir, ref))));
|
|
2206
2256
|
// Delete any packed ref
|
|
@@ -2324,7 +2374,7 @@ class GitRefManager {
|
|
|
2324
2374
|
// We need to alternate between the file system and the packed-refs
|
|
2325
2375
|
const packedMap = await GitRefManager.packedRefs({ fs, gitdir });
|
|
2326
2376
|
// Look in all the proper paths, in this order
|
|
2327
|
-
const allpaths = refpaths(ref);
|
|
2377
|
+
const allpaths = refpaths(ref).filter(p => !GIT_FILES.includes(p)); // exclude git system files (#709)
|
|
2328
2378
|
for (const ref of allpaths) {
|
|
2329
2379
|
const refExists = await acquireLock(ref, async () =>
|
|
2330
2380
|
fs.exists(`${gitdir}/${ref}`)
|
|
@@ -3824,23 +3874,6 @@ class InvalidFilepathError extends BaseError {
|
|
|
3824
3874
|
/** @type {'InvalidFilepathError'} */
|
|
3825
3875
|
InvalidFilepathError.code = 'InvalidFilepathError';
|
|
3826
3876
|
|
|
3827
|
-
class InvalidRefNameError extends BaseError {
|
|
3828
|
-
/**
|
|
3829
|
-
* @param {string} ref
|
|
3830
|
-
* @param {string} suggestion
|
|
3831
|
-
* @param {boolean} canForce
|
|
3832
|
-
*/
|
|
3833
|
-
constructor(ref, suggestion) {
|
|
3834
|
-
super(
|
|
3835
|
-
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
3836
|
-
);
|
|
3837
|
-
this.code = this.name = InvalidRefNameError.code;
|
|
3838
|
-
this.data = { ref, suggestion };
|
|
3839
|
-
}
|
|
3840
|
-
}
|
|
3841
|
-
/** @type {'InvalidRefNameError'} */
|
|
3842
|
-
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
3843
|
-
|
|
3844
3877
|
class MaxDepthError extends BaseError {
|
|
3845
3878
|
/**
|
|
3846
3879
|
* @param {number} depth
|
|
@@ -5732,6 +5765,18 @@ async function add({
|
|
|
5732
5765
|
}
|
|
5733
5766
|
}
|
|
5734
5767
|
|
|
5768
|
+
// True for a path the index already holds, and for a folder holding one. The
|
|
5769
|
+
// exact lookup is a Map hit; the prefix scan only runs for folders, since a
|
|
5770
|
+
// tracked file always answers on the first check.
|
|
5771
|
+
function isTracked(index, filepath) {
|
|
5772
|
+
if (index.has({ filepath })) return true
|
|
5773
|
+
const prefix = `${filepath}/`;
|
|
5774
|
+
for (const entry of index.entriesMap.keys()) {
|
|
5775
|
+
if (entry.startsWith(prefix)) return true
|
|
5776
|
+
}
|
|
5777
|
+
return false
|
|
5778
|
+
}
|
|
5779
|
+
|
|
5735
5780
|
async function addToIndex({
|
|
5736
5781
|
dir,
|
|
5737
5782
|
gitdir,
|
|
@@ -5742,10 +5787,13 @@ async function addToIndex({
|
|
|
5742
5787
|
parallel,
|
|
5743
5788
|
autocrlf,
|
|
5744
5789
|
}) {
|
|
5745
|
-
// TODO: Should ignore UNLESS it's already in the index.
|
|
5746
5790
|
filepath = Array.isArray(filepath) ? filepath : [filepath];
|
|
5747
5791
|
const promises = filepath.map(async currentFilepath => {
|
|
5748
|
-
|
|
5792
|
+
// .gitignore governs untracked paths. Once a path is in the index, adding a
|
|
5793
|
+
// matching rule does not stop canonical git from staging further changes,
|
|
5794
|
+
// and an ignored folder is still walked for the sake of what it tracks:
|
|
5795
|
+
// the recursion below re-checks every child, so only tracked ones get in.
|
|
5796
|
+
if (!force && !isTracked(index, currentFilepath)) {
|
|
5749
5797
|
const ignored = await GitIgnoreManager.isIgnored({
|
|
5750
5798
|
fs,
|
|
5751
5799
|
dir,
|
|
@@ -9524,8 +9572,8 @@ function filterCapabilities(server, client) {
|
|
|
9524
9572
|
|
|
9525
9573
|
const pkg = {
|
|
9526
9574
|
name: 'isomorphic-git',
|
|
9527
|
-
version: '1.40.
|
|
9528
|
-
agent: 'git/isomorphic-git@1.40.
|
|
9575
|
+
version: '1.40.2',
|
|
9576
|
+
agent: 'git/isomorphic-git@1.40.2',
|
|
9529
9577
|
};
|
|
9530
9578
|
|
|
9531
9579
|
class FIFO {
|
|
@@ -16308,15 +16356,6 @@ async function status({
|
|
|
16308
16356
|
|
|
16309
16357
|
const fs = new FileSystem(_fs);
|
|
16310
16358
|
const updatedGitdir = await discoverGitdir({ fsp: fs, dotgit: gitdir });
|
|
16311
|
-
const ignored = await GitIgnoreManager.isIgnored({
|
|
16312
|
-
fs,
|
|
16313
|
-
gitdir: updatedGitdir,
|
|
16314
|
-
dir,
|
|
16315
|
-
filepath,
|
|
16316
|
-
});
|
|
16317
|
-
if (ignored) {
|
|
16318
|
-
return 'ignored'
|
|
16319
|
-
}
|
|
16320
16359
|
const headTree = await getHeadTree({ fs, cache, gitdir: updatedGitdir });
|
|
16321
16360
|
const treeOid = await getOidAtPath({
|
|
16322
16361
|
fs,
|
|
@@ -16334,6 +16373,20 @@ async function status({
|
|
|
16334
16373
|
return null
|
|
16335
16374
|
}
|
|
16336
16375
|
);
|
|
16376
|
+
// .gitignore governs untracked files. A file in HEAD or in the index is
|
|
16377
|
+
// tracked, so canonical git keeps reporting its real state, and
|
|
16378
|
+
// `git check-ignore` does not match it. statusMatrix already does this.
|
|
16379
|
+
if (treeOid === null && indexEntry === null) {
|
|
16380
|
+
const ignored = await GitIgnoreManager.isIgnored({
|
|
16381
|
+
fs,
|
|
16382
|
+
gitdir: updatedGitdir,
|
|
16383
|
+
dir,
|
|
16384
|
+
filepath,
|
|
16385
|
+
});
|
|
16386
|
+
if (ignored) {
|
|
16387
|
+
return 'ignored'
|
|
16388
|
+
}
|
|
16389
|
+
}
|
|
16337
16390
|
const stats = await fs.lstat(join(dir, filepath));
|
|
16338
16391
|
|
|
16339
16392
|
const H = treeOid !== null; // head
|
package/index.js
CHANGED
|
@@ -1325,6 +1325,23 @@ class InvalidOidError extends BaseError {
|
|
|
1325
1325
|
/** @type {'InvalidOidError'} */
|
|
1326
1326
|
InvalidOidError.code = 'InvalidOidError';
|
|
1327
1327
|
|
|
1328
|
+
class InvalidRefNameError extends BaseError {
|
|
1329
|
+
/**
|
|
1330
|
+
* @param {string} ref
|
|
1331
|
+
* @param {string} suggestion
|
|
1332
|
+
* @param {boolean} canForce
|
|
1333
|
+
*/
|
|
1334
|
+
constructor(ref, suggestion) {
|
|
1335
|
+
super(
|
|
1336
|
+
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
1337
|
+
);
|
|
1338
|
+
this.code = this.name = InvalidRefNameError.code;
|
|
1339
|
+
this.data = { ref, suggestion };
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
/** @type {'InvalidRefNameError'} */
|
|
1343
|
+
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
1344
|
+
|
|
1328
1345
|
class NoRefspecError extends BaseError {
|
|
1329
1346
|
/**
|
|
1330
1347
|
* @param {string} remote
|
|
@@ -1996,6 +2013,16 @@ const refpaths = ref => [
|
|
|
1996
2013
|
// @see https://git-scm.com/docs/gitrepository-layout
|
|
1997
2014
|
const GIT_FILES = ['config', 'description', 'index', 'shallow', 'commondir'];
|
|
1998
2015
|
|
|
2016
|
+
// These names are legal one-level ref names, so nothing upstream of here
|
|
2017
|
+
// rejects them, and writing to one lands on the repository file itself.
|
|
2018
|
+
// Canonical git refuses too: `git update-ref index <oid>` fails with
|
|
2019
|
+
// "cannot lock ref 'index': reference broken" and leaves the file alone.
|
|
2020
|
+
function assertWritableRef(ref) {
|
|
2021
|
+
if (GIT_FILES.includes(ref)) {
|
|
2022
|
+
throw new InvalidRefNameError(ref, `refs/heads/${ref}`)
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1999
2026
|
let lock$1;
|
|
2000
2027
|
|
|
2001
2028
|
async function acquireLock(ref, callback) {
|
|
@@ -2050,6 +2077,31 @@ class GitRefManager {
|
|
|
2050
2077
|
}
|
|
2051
2078
|
const refspec = GitRefSpecSet.from(refspecs);
|
|
2052
2079
|
const actualRefsToWrite = new Map();
|
|
2080
|
+
// Work out every destination this call will write, before touching the
|
|
2081
|
+
// repository. Translating is pure, so it can happen up here; the writes
|
|
2082
|
+
// themselves stay at the end of the function.
|
|
2083
|
+
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2084
|
+
const symrefTranslations = [];
|
|
2085
|
+
for (const [serverRef, translatedRef] of refspec.translate([
|
|
2086
|
+
...symrefs.keys(),
|
|
2087
|
+
])) {
|
|
2088
|
+
const symtarget = refspec.translateOne(symrefs.get(serverRef));
|
|
2089
|
+
if (symtarget) {
|
|
2090
|
+
symrefTranslations.push([translatedRef, `ref: ${symtarget}`]);
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
// The local side of a refspec is whatever `remote.<name>.fetch` says, so a
|
|
2094
|
+
// config like `+refs/heads/main:index` lands a write on `.git/index`.
|
|
2095
|
+
// Refuse it here rather than at the write loop: `pruneTags` and `prune`
|
|
2096
|
+
// delete refs in between, so a later throw leaves the repository pruned
|
|
2097
|
+
// and not updated. The tags added below are always `refs/tags/...`, which
|
|
2098
|
+
// is never a system file, so nothing is missed by checking this early.
|
|
2099
|
+
for (const [, translatedRef] of refTranslations) {
|
|
2100
|
+
assertWritableRef(translatedRef);
|
|
2101
|
+
}
|
|
2102
|
+
for (const [translatedRef] of symrefTranslations) {
|
|
2103
|
+
assertWritableRef(translatedRef);
|
|
2104
|
+
}
|
|
2053
2105
|
// Delete all current tags if the pruneTags argument is true.
|
|
2054
2106
|
if (pruneTags) {
|
|
2055
2107
|
const tags = await GitRefManager.listRefs({
|
|
@@ -2077,18 +2129,12 @@ class GitRefManager {
|
|
|
2077
2129
|
}
|
|
2078
2130
|
}
|
|
2079
2131
|
// Combine refs and symrefs giving symrefs priority
|
|
2080
|
-
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2081
2132
|
for (const [serverRef, translatedRef] of refTranslations) {
|
|
2082
2133
|
const value = refs.get(serverRef);
|
|
2083
2134
|
actualRefsToWrite.set(translatedRef, value);
|
|
2084
2135
|
}
|
|
2085
|
-
const
|
|
2086
|
-
|
|
2087
|
-
const value = symrefs.get(serverRef);
|
|
2088
|
-
const symtarget = refspec.translateOne(value);
|
|
2089
|
-
if (symtarget) {
|
|
2090
|
-
actualRefsToWrite.set(translatedRef, `ref: ${symtarget}`);
|
|
2091
|
-
}
|
|
2136
|
+
for (const [translatedRef, value] of symrefTranslations) {
|
|
2137
|
+
actualRefsToWrite.set(translatedRef, value);
|
|
2092
2138
|
}
|
|
2093
2139
|
// If `prune` argument is true, clear out the existing local refspec roots
|
|
2094
2140
|
const pruned = [];
|
|
@@ -2147,6 +2193,7 @@ class GitRefManager {
|
|
|
2147
2193
|
// TODO: make this less crude?
|
|
2148
2194
|
static async writeRef({ fs, gitdir, ref, value }) {
|
|
2149
2195
|
// Validate input
|
|
2196
|
+
assertWritableRef(ref);
|
|
2150
2197
|
if (!value.match(/[0-9a-f]{40}/)) {
|
|
2151
2198
|
throw new InvalidOidError(value)
|
|
2152
2199
|
}
|
|
@@ -2166,6 +2213,7 @@ class GitRefManager {
|
|
|
2166
2213
|
* @returns {Promise<void>}
|
|
2167
2214
|
*/
|
|
2168
2215
|
static async writeSymbolicRef({ fs, gitdir, ref, value }) {
|
|
2216
|
+
assertWritableRef(ref);
|
|
2169
2217
|
await acquireLock(ref, async () =>
|
|
2170
2218
|
fs.write(join(gitdir, ref), 'ref: ' + `${value.trim()}\n`, 'utf8')
|
|
2171
2219
|
);
|
|
@@ -2194,6 +2242,8 @@ class GitRefManager {
|
|
|
2194
2242
|
* @returns {Promise<void>}
|
|
2195
2243
|
*/
|
|
2196
2244
|
static async deleteRefs({ fs, gitdir, refs }) {
|
|
2245
|
+
// Validate input
|
|
2246
|
+
refs.forEach(assertWritableRef);
|
|
2197
2247
|
// Delete regular ref
|
|
2198
2248
|
await Promise.all(refs.map(ref => fs.rm(join(gitdir, ref))));
|
|
2199
2249
|
// Delete any packed ref
|
|
@@ -2317,7 +2367,7 @@ class GitRefManager {
|
|
|
2317
2367
|
// We need to alternate between the file system and the packed-refs
|
|
2318
2368
|
const packedMap = await GitRefManager.packedRefs({ fs, gitdir });
|
|
2319
2369
|
// Look in all the proper paths, in this order
|
|
2320
|
-
const allpaths = refpaths(ref);
|
|
2370
|
+
const allpaths = refpaths(ref).filter(p => !GIT_FILES.includes(p)); // exclude git system files (#709)
|
|
2321
2371
|
for (const ref of allpaths) {
|
|
2322
2372
|
const refExists = await acquireLock(ref, async () =>
|
|
2323
2373
|
fs.exists(`${gitdir}/${ref}`)
|
|
@@ -3811,23 +3861,6 @@ class InvalidFilepathError extends BaseError {
|
|
|
3811
3861
|
/** @type {'InvalidFilepathError'} */
|
|
3812
3862
|
InvalidFilepathError.code = 'InvalidFilepathError';
|
|
3813
3863
|
|
|
3814
|
-
class InvalidRefNameError extends BaseError {
|
|
3815
|
-
/**
|
|
3816
|
-
* @param {string} ref
|
|
3817
|
-
* @param {string} suggestion
|
|
3818
|
-
* @param {boolean} canForce
|
|
3819
|
-
*/
|
|
3820
|
-
constructor(ref, suggestion) {
|
|
3821
|
-
super(
|
|
3822
|
-
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
3823
|
-
);
|
|
3824
|
-
this.code = this.name = InvalidRefNameError.code;
|
|
3825
|
-
this.data = { ref, suggestion };
|
|
3826
|
-
}
|
|
3827
|
-
}
|
|
3828
|
-
/** @type {'InvalidRefNameError'} */
|
|
3829
|
-
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
3830
|
-
|
|
3831
3864
|
class MaxDepthError extends BaseError {
|
|
3832
3865
|
/**
|
|
3833
3866
|
* @param {number} depth
|
|
@@ -5719,6 +5752,18 @@ async function add({
|
|
|
5719
5752
|
}
|
|
5720
5753
|
}
|
|
5721
5754
|
|
|
5755
|
+
// True for a path the index already holds, and for a folder holding one. The
|
|
5756
|
+
// exact lookup is a Map hit; the prefix scan only runs for folders, since a
|
|
5757
|
+
// tracked file always answers on the first check.
|
|
5758
|
+
function isTracked(index, filepath) {
|
|
5759
|
+
if (index.has({ filepath })) return true
|
|
5760
|
+
const prefix = `${filepath}/`;
|
|
5761
|
+
for (const entry of index.entriesMap.keys()) {
|
|
5762
|
+
if (entry.startsWith(prefix)) return true
|
|
5763
|
+
}
|
|
5764
|
+
return false
|
|
5765
|
+
}
|
|
5766
|
+
|
|
5722
5767
|
async function addToIndex({
|
|
5723
5768
|
dir,
|
|
5724
5769
|
gitdir,
|
|
@@ -5729,10 +5774,13 @@ async function addToIndex({
|
|
|
5729
5774
|
parallel,
|
|
5730
5775
|
autocrlf,
|
|
5731
5776
|
}) {
|
|
5732
|
-
// TODO: Should ignore UNLESS it's already in the index.
|
|
5733
5777
|
filepath = Array.isArray(filepath) ? filepath : [filepath];
|
|
5734
5778
|
const promises = filepath.map(async currentFilepath => {
|
|
5735
|
-
|
|
5779
|
+
// .gitignore governs untracked paths. Once a path is in the index, adding a
|
|
5780
|
+
// matching rule does not stop canonical git from staging further changes,
|
|
5781
|
+
// and an ignored folder is still walked for the sake of what it tracks:
|
|
5782
|
+
// the recursion below re-checks every child, so only tracked ones get in.
|
|
5783
|
+
if (!force && !isTracked(index, currentFilepath)) {
|
|
5736
5784
|
const ignored = await GitIgnoreManager.isIgnored({
|
|
5737
5785
|
fs,
|
|
5738
5786
|
dir,
|
|
@@ -9511,8 +9559,8 @@ function filterCapabilities(server, client) {
|
|
|
9511
9559
|
|
|
9512
9560
|
const pkg = {
|
|
9513
9561
|
name: 'isomorphic-git',
|
|
9514
|
-
version: '1.40.
|
|
9515
|
-
agent: 'git/isomorphic-git@1.40.
|
|
9562
|
+
version: '1.40.2',
|
|
9563
|
+
agent: 'git/isomorphic-git@1.40.2',
|
|
9516
9564
|
};
|
|
9517
9565
|
|
|
9518
9566
|
class FIFO {
|
|
@@ -16295,15 +16343,6 @@ async function status({
|
|
|
16295
16343
|
|
|
16296
16344
|
const fs = new FileSystem(_fs);
|
|
16297
16345
|
const updatedGitdir = await discoverGitdir({ fsp: fs, dotgit: gitdir });
|
|
16298
|
-
const ignored = await GitIgnoreManager.isIgnored({
|
|
16299
|
-
fs,
|
|
16300
|
-
gitdir: updatedGitdir,
|
|
16301
|
-
dir,
|
|
16302
|
-
filepath,
|
|
16303
|
-
});
|
|
16304
|
-
if (ignored) {
|
|
16305
|
-
return 'ignored'
|
|
16306
|
-
}
|
|
16307
16346
|
const headTree = await getHeadTree({ fs, cache, gitdir: updatedGitdir });
|
|
16308
16347
|
const treeOid = await getOidAtPath({
|
|
16309
16348
|
fs,
|
|
@@ -16321,6 +16360,20 @@ async function status({
|
|
|
16321
16360
|
return null
|
|
16322
16361
|
}
|
|
16323
16362
|
);
|
|
16363
|
+
// .gitignore governs untracked files. A file in HEAD or in the index is
|
|
16364
|
+
// tracked, so canonical git keeps reporting its real state, and
|
|
16365
|
+
// `git check-ignore` does not match it. statusMatrix already does this.
|
|
16366
|
+
if (treeOid === null && indexEntry === null) {
|
|
16367
|
+
const ignored = await GitIgnoreManager.isIgnored({
|
|
16368
|
+
fs,
|
|
16369
|
+
gitdir: updatedGitdir,
|
|
16370
|
+
dir,
|
|
16371
|
+
filepath,
|
|
16372
|
+
});
|
|
16373
|
+
if (ignored) {
|
|
16374
|
+
return 'ignored'
|
|
16375
|
+
}
|
|
16376
|
+
}
|
|
16324
16377
|
const stats = await fs.lstat(join(dir, filepath));
|
|
16325
16378
|
|
|
16326
16379
|
const H = treeOid !== null; // head
|