isomorphic-git 1.41.4 → 1.41.7

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 CHANGED
@@ -3651,6 +3651,10 @@ async function _readObject({
3651
3651
  oid,
3652
3652
  format = 'content',
3653
3653
  }) {
3654
+ if (!['deflated', 'wrapped', 'content'].includes(format)) {
3655
+ throw new InternalError(`invalid requested format "${format}"`)
3656
+ }
3657
+
3654
3658
  // Curry the current read method so that the packfile un-deltification
3655
3659
  // process can acquire external ref-deltas.
3656
3660
  const getExternalRefDelta = oid => _readObject({ fs, cache, gitdir, oid });
@@ -3710,11 +3714,7 @@ async function _readObject({
3710
3714
  result.object = object;
3711
3715
  result.format = 'content';
3712
3716
 
3713
- if (format === 'content') {
3714
- return result
3715
- }
3716
-
3717
- throw new InternalError(`invalid requested format "${format}"`)
3717
+ return result
3718
3718
  }
3719
3719
 
3720
3720
  class AlreadyExistsError extends BaseError {
@@ -6321,6 +6321,23 @@ async function constructTree({ fs, gitdir, inode, dryRun }) {
6321
6321
  // @ts-check
6322
6322
 
6323
6323
  async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6324
+ const entry = await resolveFilepathEntry({
6325
+ fs,
6326
+ cache,
6327
+ gitdir,
6328
+ oid,
6329
+ filepath,
6330
+ });
6331
+ return entry.oid
6332
+ }
6333
+
6334
+ async function resolveFilepathEntry({
6335
+ fs,
6336
+ cache,
6337
+ gitdir,
6338
+ oid,
6339
+ filepath,
6340
+ }) {
6324
6341
  // Ensure there are no leading or trailing directory separators.
6325
6342
  // I was going to do this automatically, but then found that the Git Terminal for Windows
6326
6343
  // auto-expands --filepath=/src/utils to --filepath=C:/Users/Will/AppData/Local/Programs/Git/src/utils
@@ -6334,10 +6351,10 @@ async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6334
6351
  const result = await resolveTree({ fs, cache, gitdir, oid });
6335
6352
  const tree = result.tree;
6336
6353
  if (filepath === '') {
6337
- oid = result.oid;
6354
+ return { mode: '040000', oid: result.oid, path: '', type: 'tree' }
6338
6355
  } else {
6339
6356
  const pathArray = filepath.split('/');
6340
- oid = await _resolveFilepath({
6357
+ return _resolveFilepath({
6341
6358
  fs,
6342
6359
  cache,
6343
6360
  gitdir,
@@ -6345,9 +6362,8 @@ async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6345
6362
  pathArray,
6346
6363
  oid: _oid,
6347
6364
  filepath,
6348
- });
6365
+ })
6349
6366
  }
6350
- return oid
6351
6367
  }
6352
6368
 
6353
6369
  async function _resolveFilepath({
@@ -6363,7 +6379,7 @@ async function _resolveFilepath({
6363
6379
  for (const entry of tree) {
6364
6380
  if (entry.path === name) {
6365
6381
  if (pathArray.length === 0) {
6366
- return entry.oid
6382
+ return entry
6367
6383
  } else {
6368
6384
  const { type, object } = await _readObject({
6369
6385
  fs,
@@ -9712,8 +9728,8 @@ function filterCapabilities(server, client) {
9712
9728
 
9713
9729
  const pkg = {
9714
9730
  name: 'isomorphic-git',
9715
- version: '1.41.4',
9716
- agent: 'git/isomorphic-git@1.41.4',
9731
+ version: '1.41.7',
9732
+ agent: 'git/isomorphic-git@1.41.7',
9717
9733
  };
9718
9734
 
9719
9735
  class FIFO {
@@ -11209,44 +11225,70 @@ async function _findMergeBase({ fs, cache, gitdir, oids }) {
11209
11225
  // and computing virtual merge bases is just too much for me to fathom right now.
11210
11226
 
11211
11227
  // If we start N independent walkers, one at each of the given `oids`, and walk backwards
11212
- // through ancestors, eventually we'll discover a commit where each one of these N walkers
11213
- // has passed through. So we just need to keep track of which walkers have visited each commit
11214
- // until we find a commit that N distinct walkers has visited.
11228
+ // through ancestors, eventually we'll discover commits where each one of these N walkers
11229
+ // has passed through. We cannot stop at the first common commit because a better common
11230
+ // ancestor may still be present in another branch of the graph.
11215
11231
  const visits = {};
11216
11232
  const passes = oids.length;
11233
+ const common = new Set();
11234
+ const parents = new Map();
11235
+ const shallows = await GitShallowManager.read({ fs, gitdir });
11236
+ const readParents = async oid => {
11237
+ if (parents.has(oid)) return parents.get(oid)
11238
+ const { object, type } = await _readObject({ fs, cache, gitdir, oid });
11239
+ if (type !== 'commit') {
11240
+ throw new ObjectTypeError(oid, type, 'commit')
11241
+ }
11242
+ const commit = GitCommit.from(object);
11243
+ const { parent } = commit.parseHeaders();
11244
+ const result = shallows.has(oid) ? [] : parent;
11245
+ parents.set(oid, result);
11246
+ return result
11247
+ };
11217
11248
  let heads = oids.map((oid, index) => ({ index, oid }));
11218
11249
  while (heads.length) {
11219
11250
  // Count how many times we've passed each commit
11220
- const result = new Set();
11221
11251
  for (const { oid, index } of heads) {
11252
+ await readParents(oid);
11222
11253
  if (!visits[oid]) visits[oid] = new Set();
11223
11254
  visits[oid].add(index);
11224
11255
  if (visits[oid].size === passes) {
11225
- result.add(oid);
11256
+ common.add(oid);
11226
11257
  }
11227
11258
  }
11228
- if (result.size > 0) {
11229
- return [...result]
11230
- }
11231
- // We haven't found a common ancestor yet
11232
11259
  const newheads = new Map();
11233
11260
  for (const { oid, index } of heads) {
11234
- try {
11235
- const { object } = await _readObject({ fs, cache, gitdir, oid });
11236
- const commit = GitCommit.from(object);
11237
- const { parent } = commit.parseHeaders();
11238
- for (const oid of parent) {
11239
- if (!visits[oid] || !visits[oid].has(index)) {
11240
- newheads.set(oid + ':' + index, { oid, index });
11241
- }
11261
+ // Parents of a common commit cannot be better merge bases.
11262
+ if (common.has(oid)) continue
11263
+ for (const parent of await readParents(oid)) {
11264
+ if (!visits[parent] || !visits[parent].has(index)) {
11265
+ newheads.set(parent + ':' + index, { oid: parent, index });
11242
11266
  }
11243
- } catch (err) {
11244
- // do nothing
11245
11267
  }
11246
11268
  }
11247
11269
  heads = Array.from(newheads.values());
11248
11270
  }
11249
- return []
11271
+
11272
+ if (common.size < 2) return [...common]
11273
+
11274
+ // A merge base is only "best" when it is not an ancestor of another
11275
+ // common ancestor. This also keeps independent criss-cross bases.
11276
+ const redundant = new Set();
11277
+ for (const oid of common) {
11278
+ const ancestors = [...(await readParents(oid))];
11279
+ const seen = new Set();
11280
+ while (ancestors.length) {
11281
+ const ancestor = ancestors.pop();
11282
+ if (seen.has(ancestor)) continue
11283
+ seen.add(ancestor);
11284
+ if (common.has(ancestor)) {
11285
+ redundant.add(ancestor);
11286
+ } else {
11287
+ ancestors.push(...(await readParents(ancestor)));
11288
+ }
11289
+ }
11290
+ }
11291
+ return [...common].filter(oid => !redundant.has(oid))
11250
11292
  }
11251
11293
 
11252
11294
  // @ts-check
@@ -13327,6 +13369,7 @@ async function _log({
13327
13369
  const oid = await GitRefManager.resolve({ fs, gitdir, ref });
13328
13370
  const tips = [await _readCommit({ fs, cache, gitdir, oid })];
13329
13371
  let lastFileOid;
13372
+ let lastFileMode;
13330
13373
  let lastCommit;
13331
13374
  let isOk;
13332
13375
 
@@ -13346,19 +13389,23 @@ async function _log({
13346
13389
  }
13347
13390
 
13348
13391
  if (filepath) {
13349
- let vFileOid;
13392
+ let vFileEntry;
13350
13393
  try {
13351
- vFileOid = await resolveFilepath({
13394
+ vFileEntry = await resolveFilepathEntry({
13352
13395
  fs,
13353
13396
  cache,
13354
13397
  gitdir,
13355
13398
  oid: commit.commit.tree,
13356
13399
  filepath,
13357
13400
  });
13358
- if (lastCommit && lastFileOid !== vFileOid) {
13401
+ if (
13402
+ lastCommit &&
13403
+ (lastFileOid !== vFileEntry.oid || lastFileMode !== vFileEntry.mode)
13404
+ ) {
13359
13405
  commits.push(lastCommit);
13360
13406
  }
13361
- lastFileOid = vFileOid;
13407
+ lastFileOid = vFileEntry.oid;
13408
+ lastFileMode = vFileEntry.mode;
13362
13409
  lastCommit = commit;
13363
13410
  isOk = true;
13364
13411
  } catch (e) {
package/index.js CHANGED
@@ -3638,6 +3638,10 @@ async function _readObject({
3638
3638
  oid,
3639
3639
  format = 'content',
3640
3640
  }) {
3641
+ if (!['deflated', 'wrapped', 'content'].includes(format)) {
3642
+ throw new InternalError(`invalid requested format "${format}"`)
3643
+ }
3644
+
3641
3645
  // Curry the current read method so that the packfile un-deltification
3642
3646
  // process can acquire external ref-deltas.
3643
3647
  const getExternalRefDelta = oid => _readObject({ fs, cache, gitdir, oid });
@@ -3697,11 +3701,7 @@ async function _readObject({
3697
3701
  result.object = object;
3698
3702
  result.format = 'content';
3699
3703
 
3700
- if (format === 'content') {
3701
- return result
3702
- }
3703
-
3704
- throw new InternalError(`invalid requested format "${format}"`)
3704
+ return result
3705
3705
  }
3706
3706
 
3707
3707
  class AlreadyExistsError extends BaseError {
@@ -6308,6 +6308,23 @@ async function constructTree({ fs, gitdir, inode, dryRun }) {
6308
6308
  // @ts-check
6309
6309
 
6310
6310
  async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6311
+ const entry = await resolveFilepathEntry({
6312
+ fs,
6313
+ cache,
6314
+ gitdir,
6315
+ oid,
6316
+ filepath,
6317
+ });
6318
+ return entry.oid
6319
+ }
6320
+
6321
+ async function resolveFilepathEntry({
6322
+ fs,
6323
+ cache,
6324
+ gitdir,
6325
+ oid,
6326
+ filepath,
6327
+ }) {
6311
6328
  // Ensure there are no leading or trailing directory separators.
6312
6329
  // I was going to do this automatically, but then found that the Git Terminal for Windows
6313
6330
  // auto-expands --filepath=/src/utils to --filepath=C:/Users/Will/AppData/Local/Programs/Git/src/utils
@@ -6321,10 +6338,10 @@ async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6321
6338
  const result = await resolveTree({ fs, cache, gitdir, oid });
6322
6339
  const tree = result.tree;
6323
6340
  if (filepath === '') {
6324
- oid = result.oid;
6341
+ return { mode: '040000', oid: result.oid, path: '', type: 'tree' }
6325
6342
  } else {
6326
6343
  const pathArray = filepath.split('/');
6327
- oid = await _resolveFilepath({
6344
+ return _resolveFilepath({
6328
6345
  fs,
6329
6346
  cache,
6330
6347
  gitdir,
@@ -6332,9 +6349,8 @@ async function resolveFilepath({ fs, cache, gitdir, oid, filepath }) {
6332
6349
  pathArray,
6333
6350
  oid: _oid,
6334
6351
  filepath,
6335
- });
6352
+ })
6336
6353
  }
6337
- return oid
6338
6354
  }
6339
6355
 
6340
6356
  async function _resolveFilepath({
@@ -6350,7 +6366,7 @@ async function _resolveFilepath({
6350
6366
  for (const entry of tree) {
6351
6367
  if (entry.path === name) {
6352
6368
  if (pathArray.length === 0) {
6353
- return entry.oid
6369
+ return entry
6354
6370
  } else {
6355
6371
  const { type, object } = await _readObject({
6356
6372
  fs,
@@ -9699,8 +9715,8 @@ function filterCapabilities(server, client) {
9699
9715
 
9700
9716
  const pkg = {
9701
9717
  name: 'isomorphic-git',
9702
- version: '1.41.4',
9703
- agent: 'git/isomorphic-git@1.41.4',
9718
+ version: '1.41.7',
9719
+ agent: 'git/isomorphic-git@1.41.7',
9704
9720
  };
9705
9721
 
9706
9722
  class FIFO {
@@ -11196,44 +11212,70 @@ async function _findMergeBase({ fs, cache, gitdir, oids }) {
11196
11212
  // and computing virtual merge bases is just too much for me to fathom right now.
11197
11213
 
11198
11214
  // If we start N independent walkers, one at each of the given `oids`, and walk backwards
11199
- // through ancestors, eventually we'll discover a commit where each one of these N walkers
11200
- // has passed through. So we just need to keep track of which walkers have visited each commit
11201
- // until we find a commit that N distinct walkers has visited.
11215
+ // through ancestors, eventually we'll discover commits where each one of these N walkers
11216
+ // has passed through. We cannot stop at the first common commit because a better common
11217
+ // ancestor may still be present in another branch of the graph.
11202
11218
  const visits = {};
11203
11219
  const passes = oids.length;
11220
+ const common = new Set();
11221
+ const parents = new Map();
11222
+ const shallows = await GitShallowManager.read({ fs, gitdir });
11223
+ const readParents = async oid => {
11224
+ if (parents.has(oid)) return parents.get(oid)
11225
+ const { object, type } = await _readObject({ fs, cache, gitdir, oid });
11226
+ if (type !== 'commit') {
11227
+ throw new ObjectTypeError(oid, type, 'commit')
11228
+ }
11229
+ const commit = GitCommit.from(object);
11230
+ const { parent } = commit.parseHeaders();
11231
+ const result = shallows.has(oid) ? [] : parent;
11232
+ parents.set(oid, result);
11233
+ return result
11234
+ };
11204
11235
  let heads = oids.map((oid, index) => ({ index, oid }));
11205
11236
  while (heads.length) {
11206
11237
  // Count how many times we've passed each commit
11207
- const result = new Set();
11208
11238
  for (const { oid, index } of heads) {
11239
+ await readParents(oid);
11209
11240
  if (!visits[oid]) visits[oid] = new Set();
11210
11241
  visits[oid].add(index);
11211
11242
  if (visits[oid].size === passes) {
11212
- result.add(oid);
11243
+ common.add(oid);
11213
11244
  }
11214
11245
  }
11215
- if (result.size > 0) {
11216
- return [...result]
11217
- }
11218
- // We haven't found a common ancestor yet
11219
11246
  const newheads = new Map();
11220
11247
  for (const { oid, index } of heads) {
11221
- try {
11222
- const { object } = await _readObject({ fs, cache, gitdir, oid });
11223
- const commit = GitCommit.from(object);
11224
- const { parent } = commit.parseHeaders();
11225
- for (const oid of parent) {
11226
- if (!visits[oid] || !visits[oid].has(index)) {
11227
- newheads.set(oid + ':' + index, { oid, index });
11228
- }
11248
+ // Parents of a common commit cannot be better merge bases.
11249
+ if (common.has(oid)) continue
11250
+ for (const parent of await readParents(oid)) {
11251
+ if (!visits[parent] || !visits[parent].has(index)) {
11252
+ newheads.set(parent + ':' + index, { oid: parent, index });
11229
11253
  }
11230
- } catch (err) {
11231
- // do nothing
11232
11254
  }
11233
11255
  }
11234
11256
  heads = Array.from(newheads.values());
11235
11257
  }
11236
- return []
11258
+
11259
+ if (common.size < 2) return [...common]
11260
+
11261
+ // A merge base is only "best" when it is not an ancestor of another
11262
+ // common ancestor. This also keeps independent criss-cross bases.
11263
+ const redundant = new Set();
11264
+ for (const oid of common) {
11265
+ const ancestors = [...(await readParents(oid))];
11266
+ const seen = new Set();
11267
+ while (ancestors.length) {
11268
+ const ancestor = ancestors.pop();
11269
+ if (seen.has(ancestor)) continue
11270
+ seen.add(ancestor);
11271
+ if (common.has(ancestor)) {
11272
+ redundant.add(ancestor);
11273
+ } else {
11274
+ ancestors.push(...(await readParents(ancestor)));
11275
+ }
11276
+ }
11277
+ }
11278
+ return [...common].filter(oid => !redundant.has(oid))
11237
11279
  }
11238
11280
 
11239
11281
  // @ts-check
@@ -13314,6 +13356,7 @@ async function _log({
13314
13356
  const oid = await GitRefManager.resolve({ fs, gitdir, ref });
13315
13357
  const tips = [await _readCommit({ fs, cache, gitdir, oid })];
13316
13358
  let lastFileOid;
13359
+ let lastFileMode;
13317
13360
  let lastCommit;
13318
13361
  let isOk;
13319
13362
 
@@ -13333,19 +13376,23 @@ async function _log({
13333
13376
  }
13334
13377
 
13335
13378
  if (filepath) {
13336
- let vFileOid;
13379
+ let vFileEntry;
13337
13380
  try {
13338
- vFileOid = await resolveFilepath({
13381
+ vFileEntry = await resolveFilepathEntry({
13339
13382
  fs,
13340
13383
  cache,
13341
13384
  gitdir,
13342
13385
  oid: commit.commit.tree,
13343
13386
  filepath,
13344
13387
  });
13345
- if (lastCommit && lastFileOid !== vFileOid) {
13388
+ if (
13389
+ lastCommit &&
13390
+ (lastFileOid !== vFileEntry.oid || lastFileMode !== vFileEntry.mode)
13391
+ ) {
13346
13392
  commits.push(lastCommit);
13347
13393
  }
13348
- lastFileOid = vFileOid;
13394
+ lastFileOid = vFileEntry.oid;
13395
+ lastFileMode = vFileEntry.mode;
13349
13396
  lastCommit = commit;
13350
13397
  isOk = true;
13351
13398
  } catch (e) {