isomorphic-git 1.17.1 → 1.18.0
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 +1 -0
- package/browser-tests.json +6 -7
- package/index.cjs +215 -57
- package/index.d.ts +125 -34
- package/index.js +215 -57
- package/index.umd.min.d.ts +125 -34
- package/index.umd.min.js +2 -2
- package/index.umd.min.js.map +1 -1
- package/package.json +11 -11
- package/size_report.html +1 -1
package/README.md
CHANGED
|
@@ -345,6 +345,7 @@ Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds
|
|
|
345
345
|
</tr>
|
|
346
346
|
<tr>
|
|
347
347
|
<td align="center"><a href="https://github.com/seanpoulter"><img src="https://avatars.githubusercontent.com/u/2585460?v=4?s=60" width="60px;" alt=""/><br /><sub><b>Sean Poulter</b></sub></a><br /><a href="#maintenance-seanpoulter" title="Maintenance">🚧</a></td>
|
|
348
|
+
<td align="center"><a href="https://github.com/araknast"><img src="https://avatars.githubusercontent.com/u/84164531?v=4?s=60" width="60px;" alt=""/><br /><sub><b>\\</b></sub></a><br /><a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=araknast" title="Code">💻</a> <a href="https://github.com/isomorphic-git/isomorphic-git/commits?author=araknast" title="Tests">⚠️</a></td>
|
|
348
349
|
</tr>
|
|
349
350
|
</table>
|
|
350
351
|
|
package/browser-tests.json
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
[
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
"Safari 13.
|
|
7
|
-
"
|
|
8
|
-
"Chrome Mobile 99.0.4844 (Android 0.0.0)"
|
|
2
|
+
"Chrome Headless 79.0.3945.0 (Linux x86_64)",
|
|
3
|
+
"Firefox 100.0 (Ubuntu 0.0.0)",
|
|
4
|
+
"Chrome 100.0.4896.127 (Android 10)",
|
|
5
|
+
"Edge 79.0.309.65 (Windows 10)",
|
|
6
|
+
"Mobile Safari 13.0 (iOS 13.0)",
|
|
7
|
+
"Safari 13.1 (Mac OS 10.15.4)"
|
|
9
8
|
]
|
package/index.cjs
CHANGED
|
@@ -239,6 +239,19 @@ var diff3Merge = _interopDefault(require('diff3'));
|
|
|
239
239
|
* @return {{signature: string} | Promise<{signature: string}>} - an 'ASCII armor' encoded "detached" signature
|
|
240
240
|
*/
|
|
241
241
|
|
|
242
|
+
/**
|
|
243
|
+
* @typedef {Object} MergeDriverParams
|
|
244
|
+
* @property {Array<string>} branches
|
|
245
|
+
* @property {Array<string>} contents
|
|
246
|
+
* @property {string} path
|
|
247
|
+
*/
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* @callback MergeDriverCallback
|
|
251
|
+
* @param {MergeDriverParams} args
|
|
252
|
+
* @return {{cleanMerge: boolean, mergedText: string} | Promise<{cleanMerge: boolean, mergedText: string}>}
|
|
253
|
+
*/
|
|
254
|
+
|
|
242
255
|
/**
|
|
243
256
|
* @callback WalkerMap
|
|
244
257
|
* @param {string} filename
|
|
@@ -1474,6 +1487,21 @@ const getPath = (section, subsection, name) => {
|
|
|
1474
1487
|
.join('.')
|
|
1475
1488
|
};
|
|
1476
1489
|
|
|
1490
|
+
const normalizePath$1 = path => {
|
|
1491
|
+
const pathSegments = path.split('.');
|
|
1492
|
+
const section = pathSegments.shift();
|
|
1493
|
+
const name = pathSegments.pop();
|
|
1494
|
+
const subsection = pathSegments.length ? pathSegments.join('.') : undefined;
|
|
1495
|
+
|
|
1496
|
+
return {
|
|
1497
|
+
section,
|
|
1498
|
+
subsection,
|
|
1499
|
+
name,
|
|
1500
|
+
path: getPath(section, subsection, name),
|
|
1501
|
+
sectionPath: getPath(section, subsection, null),
|
|
1502
|
+
}
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1477
1505
|
const findLastIndex = (array, callback) => {
|
|
1478
1506
|
return array.reduce((lastIndex, item, index) => {
|
|
1479
1507
|
return callback(item) ? index : lastIndex
|
|
@@ -1513,8 +1541,9 @@ class GitConfig {
|
|
|
1513
1541
|
}
|
|
1514
1542
|
|
|
1515
1543
|
async get(path, getall = false) {
|
|
1544
|
+
const normalizedPath = normalizePath$1(path).path;
|
|
1516
1545
|
const allValues = this.parsedConfig
|
|
1517
|
-
.filter(config => config.path ===
|
|
1546
|
+
.filter(config => config.path === normalizedPath)
|
|
1518
1547
|
.map(({ section, name, value }) => {
|
|
1519
1548
|
const fn = schema[section] && schema[section][name];
|
|
1520
1549
|
return fn ? fn(value) : value
|
|
@@ -1544,9 +1573,16 @@ class GitConfig {
|
|
|
1544
1573
|
}
|
|
1545
1574
|
|
|
1546
1575
|
async set(path, value, append = false) {
|
|
1576
|
+
const {
|
|
1577
|
+
section,
|
|
1578
|
+
subsection,
|
|
1579
|
+
name,
|
|
1580
|
+
path: normalizedPath,
|
|
1581
|
+
sectionPath,
|
|
1582
|
+
} = normalizePath$1(path);
|
|
1547
1583
|
const configIndex = findLastIndex(
|
|
1548
1584
|
this.parsedConfig,
|
|
1549
|
-
config => config.path ===
|
|
1585
|
+
config => config.path === normalizedPath
|
|
1550
1586
|
);
|
|
1551
1587
|
if (value == null) {
|
|
1552
1588
|
if (configIndex !== -1) {
|
|
@@ -1555,7 +1591,9 @@ class GitConfig {
|
|
|
1555
1591
|
} else {
|
|
1556
1592
|
if (configIndex !== -1) {
|
|
1557
1593
|
const config = this.parsedConfig[configIndex];
|
|
1594
|
+
// Name should be overwritten in case the casing changed
|
|
1558
1595
|
const modifiedConfig = Object.assign({}, config, {
|
|
1596
|
+
name,
|
|
1559
1597
|
value,
|
|
1560
1598
|
modified: true,
|
|
1561
1599
|
});
|
|
@@ -1565,13 +1603,6 @@ class GitConfig {
|
|
|
1565
1603
|
this.parsedConfig[configIndex] = modifiedConfig;
|
|
1566
1604
|
}
|
|
1567
1605
|
} else {
|
|
1568
|
-
const pathSegments = path.split('.');
|
|
1569
|
-
const section = pathSegments.shift().toLowerCase();
|
|
1570
|
-
const name = pathSegments.pop();
|
|
1571
|
-
const subsection = pathSegments.length
|
|
1572
|
-
? pathSegments.join('.').toLowerCase()
|
|
1573
|
-
: undefined;
|
|
1574
|
-
const sectionPath = subsection ? section + '.' + subsection : section;
|
|
1575
1606
|
const sectionIndex = this.parsedConfig.findIndex(
|
|
1576
1607
|
config => config.path === sectionPath
|
|
1577
1608
|
);
|
|
@@ -1581,7 +1612,7 @@ class GitConfig {
|
|
|
1581
1612
|
name,
|
|
1582
1613
|
value,
|
|
1583
1614
|
modified: true,
|
|
1584
|
-
path:
|
|
1615
|
+
path: normalizedPath,
|
|
1585
1616
|
};
|
|
1586
1617
|
if (SECTION_REGEX.test(section) && VARIABLE_NAME_REGEX.test(name)) {
|
|
1587
1618
|
if (sectionIndex >= 0) {
|
|
@@ -1593,7 +1624,7 @@ class GitConfig {
|
|
|
1593
1624
|
section,
|
|
1594
1625
|
subsection,
|
|
1595
1626
|
modified: true,
|
|
1596
|
-
path:
|
|
1627
|
+
path: sectionPath,
|
|
1597
1628
|
};
|
|
1598
1629
|
this.parsedConfig.push(newSection, newConfig);
|
|
1599
1630
|
}
|
|
@@ -1609,6 +1640,10 @@ class GitConfig {
|
|
|
1609
1640
|
return line
|
|
1610
1641
|
}
|
|
1611
1642
|
if (name != null && value != null) {
|
|
1643
|
+
if (typeof value === 'string' && /[#;]/.test(value)) {
|
|
1644
|
+
// A `#` or `;` symbol denotes a comment, so we have to wrap it in double quotes
|
|
1645
|
+
return `\t${name} = "${value}"`
|
|
1646
|
+
}
|
|
1612
1647
|
return `\t${name} = ${value}`
|
|
1613
1648
|
}
|
|
1614
1649
|
if (subsection != null) {
|
|
@@ -3180,6 +3215,21 @@ class MergeNotSupportedError extends BaseError {
|
|
|
3180
3215
|
/** @type {'MergeNotSupportedError'} */
|
|
3181
3216
|
MergeNotSupportedError.code = 'MergeNotSupportedError';
|
|
3182
3217
|
|
|
3218
|
+
class MergeConflictError extends BaseError {
|
|
3219
|
+
/**
|
|
3220
|
+
* @param {Array<string>} filepaths
|
|
3221
|
+
*/
|
|
3222
|
+
constructor(filepaths) {
|
|
3223
|
+
super(
|
|
3224
|
+
`Automatic merge failed with one or more merge conflicts in the following files: ${filepaths.toString()}. Fix conflicts then commit the result.`
|
|
3225
|
+
);
|
|
3226
|
+
this.code = this.name = MergeConflictError.code;
|
|
3227
|
+
this.data = { filepaths };
|
|
3228
|
+
}
|
|
3229
|
+
}
|
|
3230
|
+
/** @type {'MergeConflictError'} */
|
|
3231
|
+
MergeConflictError.code = 'MergeConflictError';
|
|
3232
|
+
|
|
3183
3233
|
class MissingNameError extends BaseError {
|
|
3184
3234
|
/**
|
|
3185
3235
|
* @param {'author'|'committer'|'tagger'} role
|
|
@@ -3350,6 +3400,7 @@ var Errors = /*#__PURE__*/Object.freeze({
|
|
|
3350
3400
|
InvalidRefNameError: InvalidRefNameError,
|
|
3351
3401
|
MaxDepthError: MaxDepthError,
|
|
3352
3402
|
MergeNotSupportedError: MergeNotSupportedError,
|
|
3403
|
+
MergeConflictError: MergeConflictError,
|
|
3353
3404
|
MissingNameError: MissingNameError,
|
|
3354
3405
|
MissingParameterError: MissingParameterError,
|
|
3355
3406
|
MultipleGitError: MultipleGitError,
|
|
@@ -4611,7 +4662,15 @@ async function _commit({
|
|
|
4611
4662
|
// Probably an initial commit
|
|
4612
4663
|
parent = [];
|
|
4613
4664
|
}
|
|
4665
|
+
} else {
|
|
4666
|
+
// ensure that the parents are oids, not refs
|
|
4667
|
+
parent = await Promise.all(
|
|
4668
|
+
parent.map(p => {
|
|
4669
|
+
return GitRefManager.resolve({ fs, gitdir, ref: p })
|
|
4670
|
+
})
|
|
4671
|
+
);
|
|
4614
4672
|
}
|
|
4673
|
+
|
|
4615
4674
|
let comm = GitCommit.from({
|
|
4616
4675
|
tree,
|
|
4617
4676
|
parent,
|
|
@@ -6924,8 +6983,8 @@ function filterCapabilities(server, client) {
|
|
|
6924
6983
|
|
|
6925
6984
|
const pkg = {
|
|
6926
6985
|
name: 'isomorphic-git',
|
|
6927
|
-
version: '1.
|
|
6928
|
-
agent: 'git/isomorphic-git@1.
|
|
6986
|
+
version: '1.18.0',
|
|
6987
|
+
agent: 'git/isomorphic-git@1.18.0',
|
|
6929
6988
|
};
|
|
6930
6989
|
|
|
6931
6990
|
class FIFO {
|
|
@@ -8401,16 +8460,14 @@ async function _findMergeBase({ fs, cache, gitdir, oids }) {
|
|
|
8401
8460
|
|
|
8402
8461
|
const LINEBREAKS = /^.*(\r?\n|$)/gm;
|
|
8403
8462
|
|
|
8404
|
-
function mergeFile({
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
markerSize = 7,
|
|
8413
|
-
}) {
|
|
8463
|
+
function mergeFile({ branches, contents }) {
|
|
8464
|
+
const ourName = branches[1];
|
|
8465
|
+
const theirName = branches[2];
|
|
8466
|
+
|
|
8467
|
+
const baseContent = contents[0];
|
|
8468
|
+
const ourContent = contents[1];
|
|
8469
|
+
const theirContent = contents[2];
|
|
8470
|
+
|
|
8414
8471
|
const ours = ourContent.match(LINEBREAKS);
|
|
8415
8472
|
const base = baseContent.match(LINEBREAKS);
|
|
8416
8473
|
const theirs = theirContent.match(LINEBREAKS);
|
|
@@ -8418,9 +8475,12 @@ function mergeFile({
|
|
|
8418
8475
|
// Here we let the diff3 library do the heavy lifting.
|
|
8419
8476
|
const result = diff3Merge(ours, base, theirs);
|
|
8420
8477
|
|
|
8478
|
+
const markerSize = 7;
|
|
8479
|
+
|
|
8421
8480
|
// Here we note whether there are conflicts and format the results
|
|
8422
8481
|
let mergedText = '';
|
|
8423
8482
|
let cleanMerge = true;
|
|
8483
|
+
|
|
8424
8484
|
for (const item of result) {
|
|
8425
8485
|
if (item.ok) {
|
|
8426
8486
|
mergedText += item.ok.join('');
|
|
@@ -8429,10 +8489,7 @@ function mergeFile({
|
|
|
8429
8489
|
cleanMerge = false;
|
|
8430
8490
|
mergedText += `${'<'.repeat(markerSize)} ${ourName}\n`;
|
|
8431
8491
|
mergedText += item.conflict.a.join('');
|
|
8432
|
-
|
|
8433
|
-
mergedText += `${'|'.repeat(markerSize)} ${baseName}\n`;
|
|
8434
|
-
mergedText += item.conflict.o.join('');
|
|
8435
|
-
}
|
|
8492
|
+
|
|
8436
8493
|
mergedText += `${'='.repeat(markerSize)}\n`;
|
|
8437
8494
|
mergedText += item.conflict.b.join('');
|
|
8438
8495
|
mergedText += `${'>'.repeat(markerSize)} ${theirName}\n`;
|
|
@@ -8458,6 +8515,8 @@ function mergeFile({
|
|
|
8458
8515
|
* @param {string} [args.baseName='base'] - The name to use in conflicted files (in diff3 format) for the base hunks
|
|
8459
8516
|
* @param {string} [args.theirName='theirs'] - The name to use in conflicted files for their hunks
|
|
8460
8517
|
* @param {boolean} [args.dryRun=false]
|
|
8518
|
+
* @param {boolean} [args.abortOnConflict=false]
|
|
8519
|
+
* @param {MergeDriverCallback} [args.mergeDriver]
|
|
8461
8520
|
*
|
|
8462
8521
|
* @returns {Promise<string>} - The SHA-1 object id of the merged tree
|
|
8463
8522
|
*
|
|
@@ -8474,11 +8533,17 @@ async function mergeTree({
|
|
|
8474
8533
|
baseName = 'base',
|
|
8475
8534
|
theirName = 'theirs',
|
|
8476
8535
|
dryRun = false,
|
|
8536
|
+
abortOnConflict = true,
|
|
8537
|
+
mergeDriver,
|
|
8477
8538
|
}) {
|
|
8478
8539
|
const ourTree = TREE({ ref: ourOid });
|
|
8479
8540
|
const baseTree = TREE({ ref: baseOid });
|
|
8480
8541
|
const theirTree = TREE({ ref: theirOid });
|
|
8481
8542
|
|
|
8543
|
+
const unmergedFiles = [];
|
|
8544
|
+
|
|
8545
|
+
let cleanMerge = true;
|
|
8546
|
+
|
|
8482
8547
|
const results = await _walk({
|
|
8483
8548
|
fs,
|
|
8484
8549
|
cache,
|
|
@@ -8539,6 +8604,11 @@ async function mergeTree({
|
|
|
8539
8604
|
ourName,
|
|
8540
8605
|
baseName,
|
|
8541
8606
|
theirName,
|
|
8607
|
+
mergeDriver,
|
|
8608
|
+
}).then(r => {
|
|
8609
|
+
cleanMerge = r.cleanMerge;
|
|
8610
|
+
unmergedFiles.push(filepath);
|
|
8611
|
+
return r.mergeResult
|
|
8542
8612
|
})
|
|
8543
8613
|
}
|
|
8544
8614
|
// all other types of conflicts fail
|
|
@@ -8574,6 +8644,29 @@ async function mergeTree({
|
|
|
8574
8644
|
return parent
|
|
8575
8645
|
},
|
|
8576
8646
|
});
|
|
8647
|
+
|
|
8648
|
+
if (!cleanMerge) {
|
|
8649
|
+
if (dir && !abortOnConflict) {
|
|
8650
|
+
await _walk({
|
|
8651
|
+
fs,
|
|
8652
|
+
cache,
|
|
8653
|
+
dir,
|
|
8654
|
+
gitdir,
|
|
8655
|
+
trees: [TREE({ ref: results.oid })],
|
|
8656
|
+
map: async function(filepath, [entry]) {
|
|
8657
|
+
const path = `${dir}/${filepath}`;
|
|
8658
|
+
if ((await entry.type()) === 'blob') {
|
|
8659
|
+
const mode = await entry.mode();
|
|
8660
|
+
const content = new TextDecoder().decode(await entry.content());
|
|
8661
|
+
await fs.write(path, content, { mode });
|
|
8662
|
+
}
|
|
8663
|
+
return true
|
|
8664
|
+
},
|
|
8665
|
+
});
|
|
8666
|
+
}
|
|
8667
|
+
throw new MergeConflictError(unmergedFiles)
|
|
8668
|
+
}
|
|
8669
|
+
|
|
8577
8670
|
return results.oid
|
|
8578
8671
|
}
|
|
8579
8672
|
|
|
@@ -8612,9 +8705,8 @@ async function modified(entry, base) {
|
|
|
8612
8705
|
* @param {string} [args.ourName]
|
|
8613
8706
|
* @param {string} [args.baseName]
|
|
8614
8707
|
* @param {string} [args.theirName]
|
|
8615
|
-
* @param {string} [args.format]
|
|
8616
|
-
* @param {number} [args.markerSize]
|
|
8617
8708
|
* @param {boolean} [args.dryRun = false]
|
|
8709
|
+
* @param {MergeDriverCallback} [args.mergeDriver]
|
|
8618
8710
|
*
|
|
8619
8711
|
*/
|
|
8620
8712
|
async function mergeBlobs({
|
|
@@ -8627,9 +8719,8 @@ async function mergeBlobs({
|
|
|
8627
8719
|
ourName,
|
|
8628
8720
|
theirName,
|
|
8629
8721
|
baseName,
|
|
8630
|
-
format,
|
|
8631
|
-
markerSize,
|
|
8632
8722
|
dryRun,
|
|
8723
|
+
mergeDriver = mergeFile,
|
|
8633
8724
|
}) {
|
|
8634
8725
|
const type = 'blob';
|
|
8635
8726
|
// Compute the new mode.
|
|
@@ -8640,30 +8731,33 @@ async function mergeBlobs({
|
|
|
8640
8731
|
: await ours.mode();
|
|
8641
8732
|
// The trivial case: nothing to merge except maybe mode
|
|
8642
8733
|
if ((await ours.oid()) === (await theirs.oid())) {
|
|
8643
|
-
return {
|
|
8734
|
+
return {
|
|
8735
|
+
cleanMerge: true,
|
|
8736
|
+
mergeResult: { mode, path, oid: await ours.oid(), type },
|
|
8737
|
+
}
|
|
8644
8738
|
}
|
|
8645
8739
|
// if only one side made oid changes, return that side's oid
|
|
8646
8740
|
if ((await ours.oid()) === (await base.oid())) {
|
|
8647
|
-
return {
|
|
8741
|
+
return {
|
|
8742
|
+
cleanMerge: true,
|
|
8743
|
+
mergeResult: { mode, path, oid: await theirs.oid(), type },
|
|
8744
|
+
}
|
|
8648
8745
|
}
|
|
8649
8746
|
if ((await theirs.oid()) === (await base.oid())) {
|
|
8650
|
-
return {
|
|
8747
|
+
return {
|
|
8748
|
+
cleanMerge: true,
|
|
8749
|
+
mergeResult: { mode, path, oid: await ours.oid(), type },
|
|
8750
|
+
}
|
|
8651
8751
|
}
|
|
8652
8752
|
// if both sides made changes do a merge
|
|
8653
|
-
const
|
|
8654
|
-
|
|
8655
|
-
|
|
8656
|
-
|
|
8657
|
-
ourName,
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
format,
|
|
8661
|
-
markerSize,
|
|
8753
|
+
const ourContent = Buffer.from(await ours.content()).toString('utf8');
|
|
8754
|
+
const baseContent = Buffer.from(await base.content()).toString('utf8');
|
|
8755
|
+
const theirContent = Buffer.from(await theirs.content()).toString('utf8');
|
|
8756
|
+
const { mergedText, cleanMerge } = await mergeDriver({
|
|
8757
|
+
branches: [baseName, ourName, theirName],
|
|
8758
|
+
contents: [baseContent, ourContent, theirContent],
|
|
8759
|
+
path,
|
|
8662
8760
|
});
|
|
8663
|
-
if (!cleanMerge) {
|
|
8664
|
-
// all other types of conflicts fail
|
|
8665
|
-
throw new MergeNotSupportedError()
|
|
8666
|
-
}
|
|
8667
8761
|
const oid = await _writeObject({
|
|
8668
8762
|
fs,
|
|
8669
8763
|
gitdir,
|
|
@@ -8671,7 +8765,8 @@ async function mergeBlobs({
|
|
|
8671
8765
|
object: Buffer.from(mergedText, 'utf8'),
|
|
8672
8766
|
dryRun,
|
|
8673
8767
|
});
|
|
8674
|
-
|
|
8768
|
+
|
|
8769
|
+
return { cleanMerge, mergeResult: { mode, path, oid, type } }
|
|
8675
8770
|
}
|
|
8676
8771
|
|
|
8677
8772
|
// @ts-check
|
|
@@ -8699,6 +8794,7 @@ async function mergeBlobs({
|
|
|
8699
8794
|
* @param {boolean} args.fastForwardOnly
|
|
8700
8795
|
* @param {boolean} args.dryRun
|
|
8701
8796
|
* @param {boolean} args.noUpdateBranch
|
|
8797
|
+
* @param {boolean} args.abortOnConflict
|
|
8702
8798
|
* @param {string} [args.message]
|
|
8703
8799
|
* @param {Object} args.author
|
|
8704
8800
|
* @param {string} args.author.name
|
|
@@ -8712,6 +8808,7 @@ async function mergeBlobs({
|
|
|
8712
8808
|
* @param {number} args.committer.timezoneOffset
|
|
8713
8809
|
* @param {string} [args.signingKey]
|
|
8714
8810
|
* @param {SignCallback} [args.onSign] - a PGP signing implementation
|
|
8811
|
+
* @param {MergeDriverCallback} [args.mergeDriver]
|
|
8715
8812
|
*
|
|
8716
8813
|
* @returns {Promise<MergeResult>} Resolves to a description of the merge operation
|
|
8717
8814
|
*
|
|
@@ -8719,6 +8816,7 @@ async function mergeBlobs({
|
|
|
8719
8816
|
async function _merge({
|
|
8720
8817
|
fs,
|
|
8721
8818
|
cache,
|
|
8819
|
+
dir,
|
|
8722
8820
|
gitdir,
|
|
8723
8821
|
ours,
|
|
8724
8822
|
theirs,
|
|
@@ -8726,11 +8824,13 @@ async function _merge({
|
|
|
8726
8824
|
fastForwardOnly = false,
|
|
8727
8825
|
dryRun = false,
|
|
8728
8826
|
noUpdateBranch = false,
|
|
8827
|
+
abortOnConflict = true,
|
|
8729
8828
|
message,
|
|
8730
8829
|
author,
|
|
8731
8830
|
committer,
|
|
8732
8831
|
signingKey,
|
|
8733
8832
|
onSign,
|
|
8833
|
+
mergeDriver,
|
|
8734
8834
|
}) {
|
|
8735
8835
|
if (ours === undefined) {
|
|
8736
8836
|
ours = await _currentBranch({ fs, gitdir, fullname: true });
|
|
@@ -8790,14 +8890,17 @@ async function _merge({
|
|
|
8790
8890
|
const tree = await mergeTree({
|
|
8791
8891
|
fs,
|
|
8792
8892
|
cache,
|
|
8893
|
+
dir,
|
|
8793
8894
|
gitdir,
|
|
8794
8895
|
ourOid,
|
|
8795
8896
|
theirOid,
|
|
8796
8897
|
baseOid,
|
|
8797
|
-
ourName: ours,
|
|
8898
|
+
ourName: abbreviateRef(ours),
|
|
8798
8899
|
baseName: 'base',
|
|
8799
|
-
theirName: theirs,
|
|
8900
|
+
theirName: abbreviateRef(theirs),
|
|
8800
8901
|
dryRun,
|
|
8902
|
+
abortOnConflict,
|
|
8903
|
+
mergeDriver,
|
|
8801
8904
|
});
|
|
8802
8905
|
if (!message) {
|
|
8803
8906
|
message = `Merge branch '${abbreviateRef(theirs)}' into ${abbreviateRef(
|
|
@@ -10765,11 +10868,11 @@ async function _log({
|
|
|
10765
10868
|
}
|
|
10766
10869
|
}
|
|
10767
10870
|
if (!found) {
|
|
10768
|
-
if (!force && !follow) throw e
|
|
10769
10871
|
if (isOk && lastFileOid) {
|
|
10770
10872
|
commits.push(lastCommit);
|
|
10771
|
-
|
|
10873
|
+
if (!force) break
|
|
10772
10874
|
}
|
|
10875
|
+
if (!force && !follow) throw e
|
|
10773
10876
|
}
|
|
10774
10877
|
lastCommit = commit;
|
|
10775
10878
|
isOk = false;
|
|
@@ -10889,15 +10992,63 @@ async function log({
|
|
|
10889
10992
|
/**
|
|
10890
10993
|
* Merge two branches
|
|
10891
10994
|
*
|
|
10892
|
-
* ## Limitations
|
|
10893
|
-
*
|
|
10894
|
-
* Currently it does not support incomplete merges. That is, if there are merge conflicts it cannot solve
|
|
10895
|
-
* with the built in diff3 algorithm it will not modify the working dir, and will throw a [`MergeNotSupportedError`](./errors.md#mergenotsupportedError) error.
|
|
10896
|
-
*
|
|
10897
10995
|
* Currently it will fail if multiple candidate merge bases are found. (It doesn't yet implement the recursive merge strategy.)
|
|
10898
10996
|
*
|
|
10899
10997
|
* Currently it does not support selecting alternative merge strategies.
|
|
10900
10998
|
*
|
|
10999
|
+
* Currently it is not possible to abort an incomplete merge. To restore the worktree to a clean state, you will need to checkout an earlier commit.
|
|
11000
|
+
*
|
|
11001
|
+
* Currently it does not directly support the behavior of `git merge --continue`. To complete a merge after manual conflict resolution, you will need to add and commit the files manually, and specify the appropriate parent commits.
|
|
11002
|
+
*
|
|
11003
|
+
* ## Manually resolving merge conflicts
|
|
11004
|
+
* By default, if isomorphic-git encounters a merge conflict it cannot resolve using the builtin diff3 algorithm or provided merge driver, it will abort and throw a `MergeNotSupportedError`.
|
|
11005
|
+
* This leaves the index and working tree untouched.
|
|
11006
|
+
*
|
|
11007
|
+
* When `abortOnConflict` is set to `false`, and a merge conflict cannot be automatically resolved, a `MergeConflictError` is thrown and the results of the incomplete merge will be written to the working directory.
|
|
11008
|
+
* This includes conflict markers in files with unresolved merge conflicts.
|
|
11009
|
+
*
|
|
11010
|
+
* To complete the merge, edit the conflicting files as you see fit, and then add and commit the resolved merge.
|
|
11011
|
+
*
|
|
11012
|
+
* For a proper merge commit, be sure to specify the branches or commits you are merging in the `parent` argument to `git.commit`.
|
|
11013
|
+
* For example, say we are merging the branch `feature` into the branch `main` and there is a conflict we want to resolve manually.
|
|
11014
|
+
* The flow would look like this:
|
|
11015
|
+
*
|
|
11016
|
+
* ```
|
|
11017
|
+
* await git.merge({
|
|
11018
|
+
* fs,
|
|
11019
|
+
* dir,
|
|
11020
|
+
* ours: 'main',
|
|
11021
|
+
* theirs: 'feature',
|
|
11022
|
+
* abortOnConflict: false,
|
|
11023
|
+
* }).catch(e => {
|
|
11024
|
+
* if (e instanceof Errors.MergeConflictError) {
|
|
11025
|
+
* console.log(
|
|
11026
|
+
* 'Automatic merge failed for the following files: '
|
|
11027
|
+
* + `${e.data}. `
|
|
11028
|
+
* + 'Resolve these conflicts and then commit your changes.'
|
|
11029
|
+
* )
|
|
11030
|
+
* } else throw e
|
|
11031
|
+
* })
|
|
11032
|
+
*
|
|
11033
|
+
* // This is the where we manually edit the files that have been written to the working directory
|
|
11034
|
+
* // ...
|
|
11035
|
+
* // Files have been edited and we are ready to commit
|
|
11036
|
+
*
|
|
11037
|
+
* await git.add({
|
|
11038
|
+
* fs,
|
|
11039
|
+
* dir,
|
|
11040
|
+
* filepath: '.',
|
|
11041
|
+
* })
|
|
11042
|
+
*
|
|
11043
|
+
* await git.commit({
|
|
11044
|
+
* fs,
|
|
11045
|
+
* dir,
|
|
11046
|
+
* ref: 'main',
|
|
11047
|
+
* message: "Merge branch 'feature' into main",
|
|
11048
|
+
* parent: ['main', 'feature'], // Be sure to specify the parents when creating a merge commit
|
|
11049
|
+
* })
|
|
11050
|
+
* ```
|
|
11051
|
+
*
|
|
10901
11052
|
* @param {object} args
|
|
10902
11053
|
* @param {FsClient} args.fs - a file system client
|
|
10903
11054
|
* @param {SignCallback} [args.onSign] - a PGP signing implementation
|
|
@@ -10909,6 +11060,7 @@ async function log({
|
|
|
10909
11060
|
* @param {boolean} [args.fastForwardOnly = false] - If true, then non-fast-forward merges will throw an Error instead of performing a merge.
|
|
10910
11061
|
* @param {boolean} [args.dryRun = false] - If true, simulates a merge so you can test whether it would succeed.
|
|
10911
11062
|
* @param {boolean} [args.noUpdateBranch = false] - If true, does not update the branch pointer after creating the commit.
|
|
11063
|
+
* @param {boolean} [args.abortOnConflict = true] - If true, merges with conflicts will not update the worktree or index.
|
|
10912
11064
|
* @param {string} [args.message] - Overrides the default auto-generated merge commit message
|
|
10913
11065
|
* @param {Object} [args.author] - passed to [commit](commit.md) when creating a merge commit
|
|
10914
11066
|
* @param {string} [args.author.name] - Default is `user.name` config.
|
|
@@ -10922,6 +11074,7 @@ async function log({
|
|
|
10922
11074
|
* @param {number} [args.committer.timezoneOffset] - Set the committer timezone offset field. This is the difference, in minutes, from the current timezone to UTC. Default is `(new Date()).getTimezoneOffset()`.
|
|
10923
11075
|
* @param {string} [args.signingKey] - passed to [commit](commit.md) when creating a merge commit
|
|
10924
11076
|
* @param {object} [args.cache] - a [cache](cache.md) object
|
|
11077
|
+
* @param {MergeDriverCallback} [args.mergeDriver] - a [merge driver](mergeDriver.md) implementation
|
|
10925
11078
|
*
|
|
10926
11079
|
* @returns {Promise<MergeResult>} Resolves to a description of the merge operation
|
|
10927
11080
|
* @see MergeResult
|
|
@@ -10947,11 +11100,13 @@ async function merge({
|
|
|
10947
11100
|
fastForwardOnly = false,
|
|
10948
11101
|
dryRun = false,
|
|
10949
11102
|
noUpdateBranch = false,
|
|
11103
|
+
abortOnConflict = true,
|
|
10950
11104
|
message,
|
|
10951
11105
|
author: _author,
|
|
10952
11106
|
committer: _committer,
|
|
10953
11107
|
signingKey,
|
|
10954
11108
|
cache = {},
|
|
11109
|
+
mergeDriver,
|
|
10955
11110
|
}) {
|
|
10956
11111
|
try {
|
|
10957
11112
|
assertParameter('fs', _fs);
|
|
@@ -10978,6 +11133,7 @@ async function merge({
|
|
|
10978
11133
|
return await _merge({
|
|
10979
11134
|
fs,
|
|
10980
11135
|
cache,
|
|
11136
|
+
dir,
|
|
10981
11137
|
gitdir,
|
|
10982
11138
|
ours,
|
|
10983
11139
|
theirs,
|
|
@@ -10985,11 +11141,13 @@ async function merge({
|
|
|
10985
11141
|
fastForwardOnly,
|
|
10986
11142
|
dryRun,
|
|
10987
11143
|
noUpdateBranch,
|
|
11144
|
+
abortOnConflict,
|
|
10988
11145
|
message,
|
|
10989
11146
|
author,
|
|
10990
11147
|
committer,
|
|
10991
11148
|
signingKey,
|
|
10992
11149
|
onSign,
|
|
11150
|
+
mergeDriver,
|
|
10993
11151
|
})
|
|
10994
11152
|
} catch (err) {
|
|
10995
11153
|
err.caller = 'git.merge';
|