isomorphic-git 1.39.0 → 1.40.1
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 +115 -29
- package/index.d.cts +8 -1
- package/index.d.ts +8 -1
- package/index.js +115 -29
- package/index.umd.min.d.ts +8 -1
- package/index.umd.min.js +1 -1
- package/index.umd.min.js.map +1 -1
- package/managers/index.cjs +60 -26
- package/managers/index.d.cts +4 -0
- package/managers/index.d.ts +4 -0
- package/managers/index.js +60 -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
|
@@ -66,6 +66,7 @@ var diff3Merge = _interopDefault(require('diff3'));
|
|
|
66
66
|
* @property {string} message Commit message
|
|
67
67
|
* @property {string} tree SHA-1 object id of corresponding file tree
|
|
68
68
|
* @property {string[]} parent an array of zero or more SHA-1 object ids
|
|
69
|
+
* @property {Array.<Array.<string|null>>} [changes] Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
69
70
|
* @property {Object} author
|
|
70
71
|
* @property {string} author.name The author's name
|
|
71
72
|
* @property {string} author.email The author's email
|
|
@@ -1331,6 +1332,23 @@ class InvalidOidError extends BaseError {
|
|
|
1331
1332
|
/** @type {'InvalidOidError'} */
|
|
1332
1333
|
InvalidOidError.code = 'InvalidOidError';
|
|
1333
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
|
+
|
|
1334
1352
|
class NoRefspecError extends BaseError {
|
|
1335
1353
|
/**
|
|
1336
1354
|
* @param {string} remote
|
|
@@ -2002,6 +2020,16 @@ const refpaths = ref => [
|
|
|
2002
2020
|
// @see https://git-scm.com/docs/gitrepository-layout
|
|
2003
2021
|
const GIT_FILES = ['config', 'description', 'index', 'shallow', 'commondir'];
|
|
2004
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
|
+
|
|
2005
2033
|
let lock$1;
|
|
2006
2034
|
|
|
2007
2035
|
async function acquireLock(ref, callback) {
|
|
@@ -2056,6 +2084,31 @@ class GitRefManager {
|
|
|
2056
2084
|
}
|
|
2057
2085
|
const refspec = GitRefSpecSet.from(refspecs);
|
|
2058
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
|
+
}
|
|
2059
2112
|
// Delete all current tags if the pruneTags argument is true.
|
|
2060
2113
|
if (pruneTags) {
|
|
2061
2114
|
const tags = await GitRefManager.listRefs({
|
|
@@ -2083,18 +2136,12 @@ class GitRefManager {
|
|
|
2083
2136
|
}
|
|
2084
2137
|
}
|
|
2085
2138
|
// Combine refs and symrefs giving symrefs priority
|
|
2086
|
-
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2087
2139
|
for (const [serverRef, translatedRef] of refTranslations) {
|
|
2088
2140
|
const value = refs.get(serverRef);
|
|
2089
2141
|
actualRefsToWrite.set(translatedRef, value);
|
|
2090
2142
|
}
|
|
2091
|
-
const
|
|
2092
|
-
|
|
2093
|
-
const value = symrefs.get(serverRef);
|
|
2094
|
-
const symtarget = refspec.translateOne(value);
|
|
2095
|
-
if (symtarget) {
|
|
2096
|
-
actualRefsToWrite.set(translatedRef, `ref: ${symtarget}`);
|
|
2097
|
-
}
|
|
2143
|
+
for (const [translatedRef, value] of symrefTranslations) {
|
|
2144
|
+
actualRefsToWrite.set(translatedRef, value);
|
|
2098
2145
|
}
|
|
2099
2146
|
// If `prune` argument is true, clear out the existing local refspec roots
|
|
2100
2147
|
const pruned = [];
|
|
@@ -2153,6 +2200,7 @@ class GitRefManager {
|
|
|
2153
2200
|
// TODO: make this less crude?
|
|
2154
2201
|
static async writeRef({ fs, gitdir, ref, value }) {
|
|
2155
2202
|
// Validate input
|
|
2203
|
+
assertWritableRef(ref);
|
|
2156
2204
|
if (!value.match(/[0-9a-f]{40}/)) {
|
|
2157
2205
|
throw new InvalidOidError(value)
|
|
2158
2206
|
}
|
|
@@ -2172,6 +2220,7 @@ class GitRefManager {
|
|
|
2172
2220
|
* @returns {Promise<void>}
|
|
2173
2221
|
*/
|
|
2174
2222
|
static async writeSymbolicRef({ fs, gitdir, ref, value }) {
|
|
2223
|
+
assertWritableRef(ref);
|
|
2175
2224
|
await acquireLock(ref, async () =>
|
|
2176
2225
|
fs.write(join(gitdir, ref), 'ref: ' + `${value.trim()}\n`, 'utf8')
|
|
2177
2226
|
);
|
|
@@ -2200,6 +2249,8 @@ class GitRefManager {
|
|
|
2200
2249
|
* @returns {Promise<void>}
|
|
2201
2250
|
*/
|
|
2202
2251
|
static async deleteRefs({ fs, gitdir, refs }) {
|
|
2252
|
+
// Validate input
|
|
2253
|
+
refs.forEach(assertWritableRef);
|
|
2203
2254
|
// Delete regular ref
|
|
2204
2255
|
await Promise.all(refs.map(ref => fs.rm(join(gitdir, ref))));
|
|
2205
2256
|
// Delete any packed ref
|
|
@@ -2323,7 +2374,7 @@ class GitRefManager {
|
|
|
2323
2374
|
// We need to alternate between the file system and the packed-refs
|
|
2324
2375
|
const packedMap = await GitRefManager.packedRefs({ fs, gitdir });
|
|
2325
2376
|
// Look in all the proper paths, in this order
|
|
2326
|
-
const allpaths = refpaths(ref);
|
|
2377
|
+
const allpaths = refpaths(ref).filter(p => !GIT_FILES.includes(p)); // exclude git system files (#709)
|
|
2327
2378
|
for (const ref of allpaths) {
|
|
2328
2379
|
const refExists = await acquireLock(ref, async () =>
|
|
2329
2380
|
fs.exists(`${gitdir}/${ref}`)
|
|
@@ -3823,23 +3874,6 @@ class InvalidFilepathError extends BaseError {
|
|
|
3823
3874
|
/** @type {'InvalidFilepathError'} */
|
|
3824
3875
|
InvalidFilepathError.code = 'InvalidFilepathError';
|
|
3825
3876
|
|
|
3826
|
-
class InvalidRefNameError extends BaseError {
|
|
3827
|
-
/**
|
|
3828
|
-
* @param {string} ref
|
|
3829
|
-
* @param {string} suggestion
|
|
3830
|
-
* @param {boolean} canForce
|
|
3831
|
-
*/
|
|
3832
|
-
constructor(ref, suggestion) {
|
|
3833
|
-
super(
|
|
3834
|
-
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
3835
|
-
);
|
|
3836
|
-
this.code = this.name = InvalidRefNameError.code;
|
|
3837
|
-
this.data = { ref, suggestion };
|
|
3838
|
-
}
|
|
3839
|
-
}
|
|
3840
|
-
/** @type {'InvalidRefNameError'} */
|
|
3841
|
-
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
3842
|
-
|
|
3843
3877
|
class MaxDepthError extends BaseError {
|
|
3844
3878
|
/**
|
|
3845
3879
|
* @param {number} depth
|
|
@@ -9523,8 +9557,8 @@ function filterCapabilities(server, client) {
|
|
|
9523
9557
|
|
|
9524
9558
|
const pkg = {
|
|
9525
9559
|
name: 'isomorphic-git',
|
|
9526
|
-
version: '1.
|
|
9527
|
-
agent: 'git/isomorphic-git@1.
|
|
9560
|
+
version: '1.40.1',
|
|
9561
|
+
agent: 'git/isomorphic-git@1.40.1',
|
|
9528
9562
|
};
|
|
9529
9563
|
|
|
9530
9564
|
class FIFO {
|
|
@@ -13097,7 +13131,7 @@ async function _resolveFileId({
|
|
|
13097
13131
|
* @param {number|void} args.depth
|
|
13098
13132
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
13099
13133
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
13100
|
-
* @param {boolean=} args.
|
|
13134
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit.
|
|
13101
13135
|
*
|
|
13102
13136
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
13103
13137
|
* @see ReadCommitResult
|
|
@@ -13118,6 +13152,7 @@ async function _log({
|
|
|
13118
13152
|
since,
|
|
13119
13153
|
force,
|
|
13120
13154
|
follow,
|
|
13155
|
+
includeChanges,
|
|
13121
13156
|
}) {
|
|
13122
13157
|
const sinceTimestamp =
|
|
13123
13158
|
typeof since === 'undefined'
|
|
@@ -13245,9 +13280,57 @@ async function _log({
|
|
|
13245
13280
|
// Process tips in order by age
|
|
13246
13281
|
tips.sort((a, b) => compareAge(a.commit, b.commit));
|
|
13247
13282
|
}
|
|
13283
|
+
if (includeChanges) {
|
|
13284
|
+
for (const commit of commits) {
|
|
13285
|
+
commit.commit.changes = await getChanges({
|
|
13286
|
+
fs,
|
|
13287
|
+
cache,
|
|
13288
|
+
gitdir,
|
|
13289
|
+
commit,
|
|
13290
|
+
shallow: shallowCommits.has(commit.oid),
|
|
13291
|
+
});
|
|
13292
|
+
}
|
|
13293
|
+
}
|
|
13248
13294
|
return commits
|
|
13249
13295
|
}
|
|
13250
13296
|
|
|
13297
|
+
async function getChanges({ fs, cache, gitdir, commit, shallow }) {
|
|
13298
|
+
const parent =
|
|
13299
|
+
shallow || !commit.commit.parent[0]
|
|
13300
|
+
? '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
|
|
13301
|
+
: commit.commit.parent[0];
|
|
13302
|
+
return _walk({
|
|
13303
|
+
fs,
|
|
13304
|
+
cache,
|
|
13305
|
+
gitdir,
|
|
13306
|
+
trees: [TREE({ ref: commit.oid }), TREE({ ref: parent })],
|
|
13307
|
+
map: async (filepath, [current, previous]) => {
|
|
13308
|
+
const [currentType, previousType] = await Promise.all([
|
|
13309
|
+
current && current.type(),
|
|
13310
|
+
previous && previous.type(),
|
|
13311
|
+
]);
|
|
13312
|
+
if (currentType === 'tree') {
|
|
13313
|
+
if (previousType && previousType !== 'tree') {
|
|
13314
|
+
return [null, await previous.oid(), filepath]
|
|
13315
|
+
}
|
|
13316
|
+
return
|
|
13317
|
+
}
|
|
13318
|
+
if (previousType === 'tree') {
|
|
13319
|
+
if (currentType) {
|
|
13320
|
+
return [await current.oid(), null, filepath]
|
|
13321
|
+
}
|
|
13322
|
+
return
|
|
13323
|
+
}
|
|
13324
|
+
const [newOid, oldOid] = await Promise.all([
|
|
13325
|
+
current ? current.oid() : null,
|
|
13326
|
+
previous ? previous.oid() : null,
|
|
13327
|
+
]);
|
|
13328
|
+
if (newOid === oldOid) return
|
|
13329
|
+
return [newOid, oldOid, filepath]
|
|
13330
|
+
},
|
|
13331
|
+
})
|
|
13332
|
+
}
|
|
13333
|
+
|
|
13251
13334
|
// @ts-check
|
|
13252
13335
|
|
|
13253
13336
|
/**
|
|
@@ -13263,6 +13346,7 @@ async function _log({
|
|
|
13263
13346
|
* @param {Date} [args.since] - Return history newer than the given date. Can be combined with `depth` to get whichever is shorter.
|
|
13264
13347
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
13265
13348
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
13349
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit. Each tuple is `[newOid, oldOid, filepath]`; an added or removed file has a null old or new oid, respectively.
|
|
13266
13350
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
13267
13351
|
*
|
|
13268
13352
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
@@ -13289,6 +13373,7 @@ async function log({
|
|
|
13289
13373
|
since, // Date
|
|
13290
13374
|
force,
|
|
13291
13375
|
follow,
|
|
13376
|
+
includeChanges = false,
|
|
13292
13377
|
cache = {},
|
|
13293
13378
|
}) {
|
|
13294
13379
|
try {
|
|
@@ -13308,6 +13393,7 @@ async function log({
|
|
|
13308
13393
|
since,
|
|
13309
13394
|
force,
|
|
13310
13395
|
follow,
|
|
13396
|
+
includeChanges,
|
|
13311
13397
|
})
|
|
13312
13398
|
} catch (err) {
|
|
13313
13399
|
err.caller = 'git.log';
|
package/index.d.cts
CHANGED
|
@@ -354,6 +354,10 @@ export type CommitObject = {
|
|
|
354
354
|
* an array of zero or more SHA-1 object ids
|
|
355
355
|
*/
|
|
356
356
|
parent: string[];
|
|
357
|
+
/**
|
|
358
|
+
* Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
359
|
+
*/
|
|
360
|
+
changes?: (string | null)[][] | undefined;
|
|
357
361
|
author: {
|
|
358
362
|
name: string;
|
|
359
363
|
email: string;
|
|
@@ -2181,6 +2185,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2181
2185
|
* @param {Date} [args.since] - Return history newer than the given date. Can be combined with `depth` to get whichever is shorter.
|
|
2182
2186
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
2183
2187
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
2188
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit. Each tuple is `[newOid, oldOid, filepath]`; an added or removed file has a null old or new oid, respectively.
|
|
2184
2189
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
2185
2190
|
*
|
|
2186
2191
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
@@ -2197,7 +2202,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2197
2202
|
* console.log(commits)
|
|
2198
2203
|
*
|
|
2199
2204
|
*/
|
|
2200
|
-
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, cache, }: {
|
|
2205
|
+
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, includeChanges, cache, }: {
|
|
2201
2206
|
fs: FsClient;
|
|
2202
2207
|
dir?: string | undefined;
|
|
2203
2208
|
gitdir?: string | undefined;
|
|
@@ -2207,6 +2212,7 @@ export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follo
|
|
|
2207
2212
|
since?: Date | undefined;
|
|
2208
2213
|
force?: boolean | undefined;
|
|
2209
2214
|
follow?: boolean | undefined;
|
|
2215
|
+
includeChanges?: boolean | undefined;
|
|
2210
2216
|
cache?: object;
|
|
2211
2217
|
}): Promise<Array<ReadCommitResult>>;
|
|
2212
2218
|
/**
|
|
@@ -4521,6 +4527,7 @@ declare namespace NoCommitError {
|
|
|
4521
4527
|
* @property {string} message Commit message
|
|
4522
4528
|
* @property {string} tree SHA-1 object id of corresponding file tree
|
|
4523
4529
|
* @property {string[]} parent an array of zero or more SHA-1 object ids
|
|
4530
|
+
* @property {Array.<Array.<string|null>>} [changes] Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
4524
4531
|
* @property {Object} author
|
|
4525
4532
|
* @property {string} author.name The author's name
|
|
4526
4533
|
* @property {string} author.email The author's email
|
package/index.d.ts
CHANGED
|
@@ -353,6 +353,10 @@ export type CommitObject = {
|
|
|
353
353
|
* an array of zero or more SHA-1 object ids
|
|
354
354
|
*/
|
|
355
355
|
parent: string[];
|
|
356
|
+
/**
|
|
357
|
+
* Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
358
|
+
*/
|
|
359
|
+
changes?: (string | null)[][] | undefined;
|
|
356
360
|
author: {
|
|
357
361
|
name: string;
|
|
358
362
|
email: string;
|
|
@@ -2180,6 +2184,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2180
2184
|
* @param {Date} [args.since] - Return history newer than the given date. Can be combined with `depth` to get whichever is shorter.
|
|
2181
2185
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
2182
2186
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
2187
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit. Each tuple is `[newOid, oldOid, filepath]`; an added or removed file has a null old or new oid, respectively.
|
|
2183
2188
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
2184
2189
|
*
|
|
2185
2190
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
@@ -2196,7 +2201,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2196
2201
|
* console.log(commits)
|
|
2197
2202
|
*
|
|
2198
2203
|
*/
|
|
2199
|
-
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, cache, }: {
|
|
2204
|
+
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, includeChanges, cache, }: {
|
|
2200
2205
|
fs: FsClient;
|
|
2201
2206
|
dir?: string | undefined;
|
|
2202
2207
|
gitdir?: string | undefined;
|
|
@@ -2206,6 +2211,7 @@ export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follo
|
|
|
2206
2211
|
since?: Date | undefined;
|
|
2207
2212
|
force?: boolean | undefined;
|
|
2208
2213
|
follow?: boolean | undefined;
|
|
2214
|
+
includeChanges?: boolean | undefined;
|
|
2209
2215
|
cache?: object;
|
|
2210
2216
|
}): Promise<Array<ReadCommitResult>>;
|
|
2211
2217
|
/**
|
|
@@ -4520,6 +4526,7 @@ declare namespace NoCommitError {
|
|
|
4520
4526
|
* @property {string} message Commit message
|
|
4521
4527
|
* @property {string} tree SHA-1 object id of corresponding file tree
|
|
4522
4528
|
* @property {string[]} parent an array of zero or more SHA-1 object ids
|
|
4529
|
+
* @property {Array.<Array.<string|null>>} [changes] Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
4523
4530
|
* @property {Object} author
|
|
4524
4531
|
* @property {string} author.name The author's name
|
|
4525
4532
|
* @property {string} author.email The author's email
|
package/index.js
CHANGED
|
@@ -59,6 +59,7 @@ import diff3Merge from 'diff3';
|
|
|
59
59
|
* @property {string} message Commit message
|
|
60
60
|
* @property {string} tree SHA-1 object id of corresponding file tree
|
|
61
61
|
* @property {string[]} parent an array of zero or more SHA-1 object ids
|
|
62
|
+
* @property {Array.<Array.<string|null>>} [changes] Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
62
63
|
* @property {Object} author
|
|
63
64
|
* @property {string} author.name The author's name
|
|
64
65
|
* @property {string} author.email The author's email
|
|
@@ -1324,6 +1325,23 @@ class InvalidOidError extends BaseError {
|
|
|
1324
1325
|
/** @type {'InvalidOidError'} */
|
|
1325
1326
|
InvalidOidError.code = 'InvalidOidError';
|
|
1326
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
|
+
|
|
1327
1345
|
class NoRefspecError extends BaseError {
|
|
1328
1346
|
/**
|
|
1329
1347
|
* @param {string} remote
|
|
@@ -1995,6 +2013,16 @@ const refpaths = ref => [
|
|
|
1995
2013
|
// @see https://git-scm.com/docs/gitrepository-layout
|
|
1996
2014
|
const GIT_FILES = ['config', 'description', 'index', 'shallow', 'commondir'];
|
|
1997
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
|
+
|
|
1998
2026
|
let lock$1;
|
|
1999
2027
|
|
|
2000
2028
|
async function acquireLock(ref, callback) {
|
|
@@ -2049,6 +2077,31 @@ class GitRefManager {
|
|
|
2049
2077
|
}
|
|
2050
2078
|
const refspec = GitRefSpecSet.from(refspecs);
|
|
2051
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
|
+
}
|
|
2052
2105
|
// Delete all current tags if the pruneTags argument is true.
|
|
2053
2106
|
if (pruneTags) {
|
|
2054
2107
|
const tags = await GitRefManager.listRefs({
|
|
@@ -2076,18 +2129,12 @@ class GitRefManager {
|
|
|
2076
2129
|
}
|
|
2077
2130
|
}
|
|
2078
2131
|
// Combine refs and symrefs giving symrefs priority
|
|
2079
|
-
const refTranslations = refspec.translate([...refs.keys()]);
|
|
2080
2132
|
for (const [serverRef, translatedRef] of refTranslations) {
|
|
2081
2133
|
const value = refs.get(serverRef);
|
|
2082
2134
|
actualRefsToWrite.set(translatedRef, value);
|
|
2083
2135
|
}
|
|
2084
|
-
const
|
|
2085
|
-
|
|
2086
|
-
const value = symrefs.get(serverRef);
|
|
2087
|
-
const symtarget = refspec.translateOne(value);
|
|
2088
|
-
if (symtarget) {
|
|
2089
|
-
actualRefsToWrite.set(translatedRef, `ref: ${symtarget}`);
|
|
2090
|
-
}
|
|
2136
|
+
for (const [translatedRef, value] of symrefTranslations) {
|
|
2137
|
+
actualRefsToWrite.set(translatedRef, value);
|
|
2091
2138
|
}
|
|
2092
2139
|
// If `prune` argument is true, clear out the existing local refspec roots
|
|
2093
2140
|
const pruned = [];
|
|
@@ -2146,6 +2193,7 @@ class GitRefManager {
|
|
|
2146
2193
|
// TODO: make this less crude?
|
|
2147
2194
|
static async writeRef({ fs, gitdir, ref, value }) {
|
|
2148
2195
|
// Validate input
|
|
2196
|
+
assertWritableRef(ref);
|
|
2149
2197
|
if (!value.match(/[0-9a-f]{40}/)) {
|
|
2150
2198
|
throw new InvalidOidError(value)
|
|
2151
2199
|
}
|
|
@@ -2165,6 +2213,7 @@ class GitRefManager {
|
|
|
2165
2213
|
* @returns {Promise<void>}
|
|
2166
2214
|
*/
|
|
2167
2215
|
static async writeSymbolicRef({ fs, gitdir, ref, value }) {
|
|
2216
|
+
assertWritableRef(ref);
|
|
2168
2217
|
await acquireLock(ref, async () =>
|
|
2169
2218
|
fs.write(join(gitdir, ref), 'ref: ' + `${value.trim()}\n`, 'utf8')
|
|
2170
2219
|
);
|
|
@@ -2193,6 +2242,8 @@ class GitRefManager {
|
|
|
2193
2242
|
* @returns {Promise<void>}
|
|
2194
2243
|
*/
|
|
2195
2244
|
static async deleteRefs({ fs, gitdir, refs }) {
|
|
2245
|
+
// Validate input
|
|
2246
|
+
refs.forEach(assertWritableRef);
|
|
2196
2247
|
// Delete regular ref
|
|
2197
2248
|
await Promise.all(refs.map(ref => fs.rm(join(gitdir, ref))));
|
|
2198
2249
|
// Delete any packed ref
|
|
@@ -2316,7 +2367,7 @@ class GitRefManager {
|
|
|
2316
2367
|
// We need to alternate between the file system and the packed-refs
|
|
2317
2368
|
const packedMap = await GitRefManager.packedRefs({ fs, gitdir });
|
|
2318
2369
|
// Look in all the proper paths, in this order
|
|
2319
|
-
const allpaths = refpaths(ref);
|
|
2370
|
+
const allpaths = refpaths(ref).filter(p => !GIT_FILES.includes(p)); // exclude git system files (#709)
|
|
2320
2371
|
for (const ref of allpaths) {
|
|
2321
2372
|
const refExists = await acquireLock(ref, async () =>
|
|
2322
2373
|
fs.exists(`${gitdir}/${ref}`)
|
|
@@ -3810,23 +3861,6 @@ class InvalidFilepathError extends BaseError {
|
|
|
3810
3861
|
/** @type {'InvalidFilepathError'} */
|
|
3811
3862
|
InvalidFilepathError.code = 'InvalidFilepathError';
|
|
3812
3863
|
|
|
3813
|
-
class InvalidRefNameError extends BaseError {
|
|
3814
|
-
/**
|
|
3815
|
-
* @param {string} ref
|
|
3816
|
-
* @param {string} suggestion
|
|
3817
|
-
* @param {boolean} canForce
|
|
3818
|
-
*/
|
|
3819
|
-
constructor(ref, suggestion) {
|
|
3820
|
-
super(
|
|
3821
|
-
`"${ref}" would be an invalid git reference. (Hint: a valid alternative would be "${suggestion}".)`
|
|
3822
|
-
);
|
|
3823
|
-
this.code = this.name = InvalidRefNameError.code;
|
|
3824
|
-
this.data = { ref, suggestion };
|
|
3825
|
-
}
|
|
3826
|
-
}
|
|
3827
|
-
/** @type {'InvalidRefNameError'} */
|
|
3828
|
-
InvalidRefNameError.code = 'InvalidRefNameError';
|
|
3829
|
-
|
|
3830
3864
|
class MaxDepthError extends BaseError {
|
|
3831
3865
|
/**
|
|
3832
3866
|
* @param {number} depth
|
|
@@ -9510,8 +9544,8 @@ function filterCapabilities(server, client) {
|
|
|
9510
9544
|
|
|
9511
9545
|
const pkg = {
|
|
9512
9546
|
name: 'isomorphic-git',
|
|
9513
|
-
version: '1.
|
|
9514
|
-
agent: 'git/isomorphic-git@1.
|
|
9547
|
+
version: '1.40.1',
|
|
9548
|
+
agent: 'git/isomorphic-git@1.40.1',
|
|
9515
9549
|
};
|
|
9516
9550
|
|
|
9517
9551
|
class FIFO {
|
|
@@ -13084,7 +13118,7 @@ async function _resolveFileId({
|
|
|
13084
13118
|
* @param {number|void} args.depth
|
|
13085
13119
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
13086
13120
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
13087
|
-
* @param {boolean=} args.
|
|
13121
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit.
|
|
13088
13122
|
*
|
|
13089
13123
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
13090
13124
|
* @see ReadCommitResult
|
|
@@ -13105,6 +13139,7 @@ async function _log({
|
|
|
13105
13139
|
since,
|
|
13106
13140
|
force,
|
|
13107
13141
|
follow,
|
|
13142
|
+
includeChanges,
|
|
13108
13143
|
}) {
|
|
13109
13144
|
const sinceTimestamp =
|
|
13110
13145
|
typeof since === 'undefined'
|
|
@@ -13232,9 +13267,57 @@ async function _log({
|
|
|
13232
13267
|
// Process tips in order by age
|
|
13233
13268
|
tips.sort((a, b) => compareAge(a.commit, b.commit));
|
|
13234
13269
|
}
|
|
13270
|
+
if (includeChanges) {
|
|
13271
|
+
for (const commit of commits) {
|
|
13272
|
+
commit.commit.changes = await getChanges({
|
|
13273
|
+
fs,
|
|
13274
|
+
cache,
|
|
13275
|
+
gitdir,
|
|
13276
|
+
commit,
|
|
13277
|
+
shallow: shallowCommits.has(commit.oid),
|
|
13278
|
+
});
|
|
13279
|
+
}
|
|
13280
|
+
}
|
|
13235
13281
|
return commits
|
|
13236
13282
|
}
|
|
13237
13283
|
|
|
13284
|
+
async function getChanges({ fs, cache, gitdir, commit, shallow }) {
|
|
13285
|
+
const parent =
|
|
13286
|
+
shallow || !commit.commit.parent[0]
|
|
13287
|
+
? '4b825dc642cb6eb9a060e54bf8d69288fbee4904'
|
|
13288
|
+
: commit.commit.parent[0];
|
|
13289
|
+
return _walk({
|
|
13290
|
+
fs,
|
|
13291
|
+
cache,
|
|
13292
|
+
gitdir,
|
|
13293
|
+
trees: [TREE({ ref: commit.oid }), TREE({ ref: parent })],
|
|
13294
|
+
map: async (filepath, [current, previous]) => {
|
|
13295
|
+
const [currentType, previousType] = await Promise.all([
|
|
13296
|
+
current && current.type(),
|
|
13297
|
+
previous && previous.type(),
|
|
13298
|
+
]);
|
|
13299
|
+
if (currentType === 'tree') {
|
|
13300
|
+
if (previousType && previousType !== 'tree') {
|
|
13301
|
+
return [null, await previous.oid(), filepath]
|
|
13302
|
+
}
|
|
13303
|
+
return
|
|
13304
|
+
}
|
|
13305
|
+
if (previousType === 'tree') {
|
|
13306
|
+
if (currentType) {
|
|
13307
|
+
return [await current.oid(), null, filepath]
|
|
13308
|
+
}
|
|
13309
|
+
return
|
|
13310
|
+
}
|
|
13311
|
+
const [newOid, oldOid] = await Promise.all([
|
|
13312
|
+
current ? current.oid() : null,
|
|
13313
|
+
previous ? previous.oid() : null,
|
|
13314
|
+
]);
|
|
13315
|
+
if (newOid === oldOid) return
|
|
13316
|
+
return [newOid, oldOid, filepath]
|
|
13317
|
+
},
|
|
13318
|
+
})
|
|
13319
|
+
}
|
|
13320
|
+
|
|
13238
13321
|
// @ts-check
|
|
13239
13322
|
|
|
13240
13323
|
/**
|
|
@@ -13250,6 +13333,7 @@ async function _log({
|
|
|
13250
13333
|
* @param {Date} [args.since] - Return history newer than the given date. Can be combined with `depth` to get whichever is shorter.
|
|
13251
13334
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
13252
13335
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
13336
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit. Each tuple is `[newOid, oldOid, filepath]`; an added or removed file has a null old or new oid, respectively.
|
|
13253
13337
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
13254
13338
|
*
|
|
13255
13339
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
@@ -13276,6 +13360,7 @@ async function log({
|
|
|
13276
13360
|
since, // Date
|
|
13277
13361
|
force,
|
|
13278
13362
|
follow,
|
|
13363
|
+
includeChanges = false,
|
|
13279
13364
|
cache = {},
|
|
13280
13365
|
}) {
|
|
13281
13366
|
try {
|
|
@@ -13295,6 +13380,7 @@ async function log({
|
|
|
13295
13380
|
since,
|
|
13296
13381
|
force,
|
|
13297
13382
|
follow,
|
|
13383
|
+
includeChanges,
|
|
13298
13384
|
})
|
|
13299
13385
|
} catch (err) {
|
|
13300
13386
|
err.caller = 'git.log';
|
package/index.umd.min.d.ts
CHANGED
|
@@ -353,6 +353,10 @@ export type CommitObject = {
|
|
|
353
353
|
* an array of zero or more SHA-1 object ids
|
|
354
354
|
*/
|
|
355
355
|
parent: string[];
|
|
356
|
+
/**
|
|
357
|
+
* Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
358
|
+
*/
|
|
359
|
+
changes?: (string | null)[][] | undefined;
|
|
356
360
|
author: {
|
|
357
361
|
name: string;
|
|
358
362
|
email: string;
|
|
@@ -2180,6 +2184,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2180
2184
|
* @param {Date} [args.since] - Return history newer than the given date. Can be combined with `depth` to get whichever is shorter.
|
|
2181
2185
|
* @param {boolean=} [args.force=false] do not throw error if filepath is not exist (works only for a single file). defaults to false
|
|
2182
2186
|
* @param {boolean=} [args.follow=false] Continue listing the history of a file beyond renames (works only for a single file). defaults to false
|
|
2187
|
+
* @param {boolean=} [args.includeChanges=false] Include changed file object ids for each commit. Each tuple is `[newOid, oldOid, filepath]`; an added or removed file has a null old or new oid, respectively.
|
|
2183
2188
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
2184
2189
|
*
|
|
2185
2190
|
* @returns {Promise<Array<ReadCommitResult>>} Resolves to an array of ReadCommitResult objects
|
|
@@ -2196,7 +2201,7 @@ export function listTags({ fs, dir, gitdir }: {
|
|
|
2196
2201
|
* console.log(commits)
|
|
2197
2202
|
*
|
|
2198
2203
|
*/
|
|
2199
|
-
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, cache, }: {
|
|
2204
|
+
export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follow, includeChanges, cache, }: {
|
|
2200
2205
|
fs: FsClient;
|
|
2201
2206
|
dir?: string | undefined;
|
|
2202
2207
|
gitdir?: string | undefined;
|
|
@@ -2206,6 +2211,7 @@ export function log({ fs, dir, gitdir, filepath, ref, depth, since, force, follo
|
|
|
2206
2211
|
since?: Date | undefined;
|
|
2207
2212
|
force?: boolean | undefined;
|
|
2208
2213
|
follow?: boolean | undefined;
|
|
2214
|
+
includeChanges?: boolean | undefined;
|
|
2209
2215
|
cache?: object;
|
|
2210
2216
|
}): Promise<Array<ReadCommitResult>>;
|
|
2211
2217
|
/**
|
|
@@ -4520,6 +4526,7 @@ declare namespace NoCommitError {
|
|
|
4520
4526
|
* @property {string} message Commit message
|
|
4521
4527
|
* @property {string} tree SHA-1 object id of corresponding file tree
|
|
4522
4528
|
* @property {string[]} parent an array of zero or more SHA-1 object ids
|
|
4529
|
+
* @property {Array.<Array.<string|null>>} [changes] Changed files as `[newOid, oldOid, filepath]`; present when `log` is called with `includeChanges: true`.
|
|
4523
4530
|
* @property {Object} author
|
|
4524
4531
|
* @property {string} author.name The author's name
|
|
4525
4532
|
* @property {string} author.email The author's email
|