@ibgib/vcs-gib 0.0.34 → 0.0.39
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/VCS_CLI_USER_GUIDE.md +23 -7
- package/dist/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/bootstrap/node-bootstrap.d.mts +5 -0
- package/dist/bootstrap/node-bootstrap.d.mts.map +1 -1
- package/dist/bootstrap/node-bootstrap.mjs +4 -0
- package/dist/bootstrap/node-bootstrap.mjs.map +1 -1
- package/dist/cli/commands/cli-checkout-cmd.mjs +5 -5
- package/dist/cli/commands/cli-checkout-cmd.mjs.map +1 -1
- package/dist/cli/commands/cli-init-cmd.d.mts.map +1 -1
- package/dist/cli/commands/cli-init-cmd.mjs +16 -1
- package/dist/cli/commands/cli-init-cmd.mjs.map +1 -1
- package/dist/cli/commands/cli-log-cmd.d.mts +2 -1
- package/dist/cli/commands/cli-log-cmd.d.mts.map +1 -1
- package/dist/cli/commands/cli-log-cmd.mjs +23 -10
- package/dist/cli/commands/cli-log-cmd.mjs.map +1 -1
- package/dist/cli/commands/cli-merge-cmd.d.mts.map +1 -1
- package/dist/cli/commands/cli-merge-cmd.mjs +9 -11
- package/dist/cli/commands/cli-merge-cmd.mjs.map +1 -1
- package/dist/cli/vcs-cli-main.d.mts.map +1 -1
- package/dist/cli/vcs-cli-main.mjs +24 -1
- package/dist/cli/vcs-cli-main.mjs.map +1 -1
- package/dist/cli/vcs-repo-helper.d.mts.map +1 -1
- package/dist/cli/vcs-repo-helper.mjs +6 -2
- package/dist/cli/vcs-repo-helper.mjs.map +1 -1
- package/package.json +3 -3
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/bootstrap/node-bootstrap.mts +10 -0
- package/src/cli/cli-e2e.respec.mts +151 -0
- package/src/cli/commands/cli-checkout-cmd.mts +5 -5
- package/src/cli/commands/cli-init-cmd.mts +17 -1
- package/src/cli/commands/cli-log-cmd.mts +27 -9
- package/src/cli/commands/cli-merge-cmd.mts +9 -11
- package/src/cli/vcs-cli-main.mts +21 -1
- package/src/cli/vcs-repo-helper.mts +7 -2
- package/tsconfig.test.tsbuildinfo +1 -1
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -37,6 +37,10 @@ export interface BootstrapVcsMetaspaceOpts {
|
|
|
37
37
|
* Default space name for non-interactive headless testing. Defaults to 'vcs_space'
|
|
38
38
|
*/
|
|
39
39
|
defaultSpaceName?: string;
|
|
40
|
+
/**
|
|
41
|
+
* If true, throws if .vcsgib is not found during upward discovery without initializing spaces.
|
|
42
|
+
*/
|
|
43
|
+
mustExist?: boolean;
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
export interface BootstrapVcsMetaspaceResult {
|
|
@@ -44,6 +48,7 @@ export interface BootstrapVcsMetaspaceResult {
|
|
|
44
48
|
localSpace: IbGibSpaceAny;
|
|
45
49
|
vcsPath: string;
|
|
46
50
|
repoRoot: string;
|
|
51
|
+
foundVcsPath?: string;
|
|
47
52
|
}
|
|
48
53
|
|
|
49
54
|
/**
|
|
@@ -94,6 +99,10 @@ export async function bootstrapVcsMetaspace(
|
|
|
94
99
|
currentDir = parentDir;
|
|
95
100
|
}
|
|
96
101
|
|
|
102
|
+
if (opts.mustExist && !foundVcsPath) {
|
|
103
|
+
throw new Error(`fatal: not an ibgib repository (or any of the parent directories): ${vcsFolderName}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
97
106
|
const vcsPath = foundVcsPath || path.resolve(repoPath, vcsFolderName);
|
|
98
107
|
if (!foundVcsPath) {
|
|
99
108
|
repoRoot = path.resolve(repoPath);
|
|
@@ -181,6 +190,7 @@ export async function bootstrapVcsMetaspace(
|
|
|
181
190
|
localSpace,
|
|
182
191
|
vcsPath,
|
|
183
192
|
repoRoot,
|
|
193
|
+
foundVcsPath,
|
|
184
194
|
};
|
|
185
195
|
} catch (error: any) {
|
|
186
196
|
console.error(`${lc} ${error?.message || error} (E: genuuid)`);
|
|
@@ -21,6 +21,7 @@ import { executeCommitCmd } from './commands/cli-commit-cmd.mjs';
|
|
|
21
21
|
import { executeLogCmd } from './commands/cli-log-cmd.mjs';
|
|
22
22
|
import { executeBranchCmd } from './commands/cli-branch-cmd.mjs';
|
|
23
23
|
import { executeCheckoutCmd } from './commands/cli-checkout-cmd.mjs';
|
|
24
|
+
import { executeMergeCmd } from './commands/cli-merge-cmd.mjs';
|
|
24
25
|
import { bootstrapVcsMetaspace } from '../bootstrap/node-bootstrap.mjs';
|
|
25
26
|
import { getB2tFSIndexIbGib } from '@ibgib/core-gib/dist/vcs/index/index-helper.mjs';
|
|
26
27
|
|
|
@@ -316,4 +317,154 @@ await respecfully(lc, `Full E2E CLI Integration Spec`, async () => {
|
|
|
316
317
|
}
|
|
317
318
|
});
|
|
318
319
|
|
|
320
|
+
await ifWe(lc, `fails gracefully with fatal error message on uninitialized repository`, async () => {
|
|
321
|
+
const uninitDir = path.join(process.cwd(), `.test_cli_e2e_uninit_${Date.now()}`);
|
|
322
|
+
await fs.mkdir(uninitDir, { recursive: true });
|
|
323
|
+
|
|
324
|
+
const origCwd = process.cwd();
|
|
325
|
+
const origError = console.error;
|
|
326
|
+
let capturedErrors: string[] = [];
|
|
327
|
+
|
|
328
|
+
console.error = (...args: any[]) => {
|
|
329
|
+
capturedErrors.push(args.join(' '));
|
|
330
|
+
};
|
|
331
|
+
|
|
332
|
+
try {
|
|
333
|
+
process.chdir(uninitDir);
|
|
334
|
+
|
|
335
|
+
// Execute status, commit, log, branch, checkout in uninitialized directory
|
|
336
|
+
const statusExitCode = await main({ argv: ['status'] });
|
|
337
|
+
iReckon(lc, statusExitCode).willEqual(1);
|
|
338
|
+
|
|
339
|
+
const commitExitCode = await main({ argv: ['commit', '-m', 'test'] });
|
|
340
|
+
iReckon(lc, commitExitCode).willEqual(1);
|
|
341
|
+
|
|
342
|
+
const logExitCode = await main({ argv: ['log'] });
|
|
343
|
+
iReckon(lc, logExitCode).willEqual(1);
|
|
344
|
+
|
|
345
|
+
const branchExitCode = await main({ argv: ['branch'] });
|
|
346
|
+
iReckon(lc, branchExitCode).willEqual(1);
|
|
347
|
+
|
|
348
|
+
const checkoutExitCode = await main({ argv: ['checkout', 'main'] });
|
|
349
|
+
iReckon(lc, checkoutExitCode).willEqual(1);
|
|
350
|
+
|
|
351
|
+
// Verify clean error messages without storage stack traces
|
|
352
|
+
const hasFatalMsg = capturedErrors.some(e => e.includes('fatal: not an ibgib repository'));
|
|
353
|
+
iReckon(lc, hasFatalMsg).isGonnaBeTrue();
|
|
354
|
+
|
|
355
|
+
const hasStorageError = capturedErrors.some(e => e.includes('couldn\'t get special'));
|
|
356
|
+
iReckon(lc, hasStorageError).isGonnaBeFalse();
|
|
357
|
+
} finally {
|
|
358
|
+
process.chdir(origCwd);
|
|
359
|
+
console.error = origError;
|
|
360
|
+
await fs.rm(uninitDir, { recursive: true, force: true });
|
|
361
|
+
}
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
await ifWe(lc, `preserves worktree state when checkout is executed from within secondary worktree`, async () => {
|
|
365
|
+
const testDir = path.join(process.cwd(), `.test_cli_e2e_worktree_${Date.now()}`);
|
|
366
|
+
const vcsFolderName = '.vcsgib';
|
|
367
|
+
|
|
368
|
+
const origCwd = process.cwd();
|
|
369
|
+
|
|
370
|
+
try {
|
|
371
|
+
process.chdir(testDir);
|
|
372
|
+
} catch {
|
|
373
|
+
await fs.mkdir(testDir, { recursive: true });
|
|
374
|
+
process.chdir(testDir);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
try {
|
|
378
|
+
// 1. Init main repo
|
|
379
|
+
await executeInitCmd({
|
|
380
|
+
targetDir: testDir,
|
|
381
|
+
vcsFolderName,
|
|
382
|
+
quiet: true,
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
await fs.writeFile(path.join(testDir, 'main.txt'), 'content on main\n', 'utf8');
|
|
386
|
+
await executeAddCmd({ targetDir: testDir, vcsFolderName, all: true, quiet: true });
|
|
387
|
+
await executeCommitCmd({ targetDir: testDir, vcsFolderName, message: 'Commit on main', quiet: true });
|
|
388
|
+
|
|
389
|
+
// 2. Create feature branch
|
|
390
|
+
await executeBranchCmd({
|
|
391
|
+
targetDir: testDir,
|
|
392
|
+
vcsFolderName,
|
|
393
|
+
branchName: 'feature-strings',
|
|
394
|
+
quiet: true,
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const worktreeDir = path.join(testDir, 'b', 'feature-strings');
|
|
398
|
+
await fs.mkdir(worktreeDir, { recursive: true });
|
|
399
|
+
const worktreeFile = path.join(worktreeDir, 'feature.txt');
|
|
400
|
+
await fs.writeFile(worktreeFile, 'content on feature branch\n', 'utf8');
|
|
401
|
+
|
|
402
|
+
// 3. Commit within secondary worktree
|
|
403
|
+
await executeAddCmd({ targetDir: worktreeDir, vcsFolderName, all: true, quiet: true });
|
|
404
|
+
await executeCommitCmd({ targetDir: worktreeDir, vcsFolderName, message: 'Commit on feature', quiet: true });
|
|
405
|
+
|
|
406
|
+
// 4. Run checkout main from within the secondary worktree directory
|
|
407
|
+
process.chdir(worktreeDir);
|
|
408
|
+
const checkoutRes = await executeCheckoutCmd({
|
|
409
|
+
targetDir: worktreeDir,
|
|
410
|
+
vcsFolderName,
|
|
411
|
+
branchName: 'main',
|
|
412
|
+
quiet: true,
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
iReckon(lc, checkoutRes.currentBranch).willEqual('main');
|
|
416
|
+
|
|
417
|
+
// 5. Verify feature.txt still exists untouched in b/feature-strings
|
|
418
|
+
const featureFileExists = await fs.stat(worktreeFile).then(s => s.isFile()).catch(() => false);
|
|
419
|
+
iReckon(lc, featureFileExists).isGonnaBeTrue();
|
|
420
|
+
|
|
421
|
+
const featureContent = await fs.readFile(worktreeFile, 'utf8');
|
|
422
|
+
iReckon(lc, featureContent).willEqual('content on feature branch\n');
|
|
423
|
+
|
|
424
|
+
// 6. Verify log from inside worktree succeeds and reflects feature branch history
|
|
425
|
+
const logRes = await executeLogCmd({
|
|
426
|
+
targetDir: worktreeDir,
|
|
427
|
+
vcsFolderName,
|
|
428
|
+
quiet: true,
|
|
429
|
+
});
|
|
430
|
+
iReckon(lc, logRes.branchName).willEqual('feature-strings');
|
|
431
|
+
iReckon(lc, logRes.commits.length).willEqual(2);
|
|
432
|
+
iReckon(lc, logRes.commits[0].message).willEqual('Commit on feature');
|
|
433
|
+
iReckon(lc, logRes.commits[1].message).willEqual('Commit on main');
|
|
434
|
+
|
|
435
|
+
// 7. Verify explicit -b flag logs feature-strings from repo root
|
|
436
|
+
const rootLogExplicitBranchRes = await executeLogCmd({
|
|
437
|
+
targetDir: testDir,
|
|
438
|
+
vcsFolderName,
|
|
439
|
+
branchName: 'feature-strings',
|
|
440
|
+
quiet: true,
|
|
441
|
+
});
|
|
442
|
+
iReckon(lc, rootLogExplicitBranchRes.branchName).willEqual('feature-strings');
|
|
443
|
+
iReckon(lc, rootLogExplicitBranchRes.commits.length).willEqual(2);
|
|
444
|
+
iReckon(lc, rootLogExplicitBranchRes.commits[0].message).willEqual('Commit on feature');
|
|
445
|
+
iReckon(lc, rootLogExplicitBranchRes.commits[1].message).willEqual('Commit on main');
|
|
446
|
+
|
|
447
|
+
// 8. Merge feature-strings into main and verify log on main
|
|
448
|
+
process.chdir(testDir);
|
|
449
|
+
await executeMergeCmd({
|
|
450
|
+
targetDir: testDir,
|
|
451
|
+
vcsFolderName,
|
|
452
|
+
incomingBranchName: 'feature-strings',
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
const mainLogAfterMergeRes = await executeLogCmd({
|
|
456
|
+
targetDir: testDir,
|
|
457
|
+
vcsFolderName,
|
|
458
|
+
quiet: true,
|
|
459
|
+
});
|
|
460
|
+
iReckon(lc, mainLogAfterMergeRes.branchName).willEqual('main');
|
|
461
|
+
iReckon(lc, mainLogAfterMergeRes.commits.length >= 2).isGonnaBeTrue();
|
|
462
|
+
iReckon(lc, mainLogAfterMergeRes.commits[0].message).willEqual('Commit on feature');
|
|
463
|
+
iReckon(lc, mainLogAfterMergeRes.commits[1].message).willEqual('Commit on main');
|
|
464
|
+
} finally {
|
|
465
|
+
process.chdir(origCwd);
|
|
466
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
|
|
319
470
|
});
|
|
@@ -37,11 +37,11 @@ export async function executeCheckoutCmd({
|
|
|
37
37
|
}: CheckoutCmdOpts = {}): Promise<CheckoutCmdResult> {
|
|
38
38
|
const lc = `${lcFile}[${executeCheckoutCmd.name}]`;
|
|
39
39
|
try {
|
|
40
|
-
if (logalot) { console.log(`${lc} starting... (I:
|
|
40
|
+
if (logalot) { console.log(`${lc} starting... (I: 1cd9d2565ff16c18e82d7802ea033226)`); }
|
|
41
41
|
|
|
42
42
|
const trimmedBranchName = branchName?.trim();
|
|
43
43
|
if (!trimmedBranchName) {
|
|
44
|
-
throw new Error(`Branch name is required for checkout (E:
|
|
44
|
+
throw new Error(`Branch name is required for checkout (E: 16edcde284b7fdfb05547c829fda5d26)`);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
const absTargetDir = path.resolve(targetDir);
|
|
@@ -54,7 +54,7 @@ export async function executeCheckoutCmd({
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
if (!quiet) {
|
|
57
|
-
console.log(`Switched to branch '${checkoutRes.currentBranch}' (I:
|
|
57
|
+
console.log(`Switched to branch '${checkoutRes.currentBranch}' (I: f73f287d3271149058e5ee9851392726)`);
|
|
58
58
|
console.log(`Worktree path: ${checkoutRes.worktreePath}`);
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -64,9 +64,9 @@ export async function executeCheckoutCmd({
|
|
|
64
64
|
worktreePath: checkoutRes.worktreePath,
|
|
65
65
|
};
|
|
66
66
|
} catch (error) {
|
|
67
|
-
console.error(`${lc} ${extractErrorMsg(error)} (E:
|
|
67
|
+
console.error(`${lc} ${extractErrorMsg(error)} (E: 008fbfd6f9f8eb496854b4edc55ea726)`);
|
|
68
68
|
throw error;
|
|
69
69
|
} finally {
|
|
70
|
-
if (logalot) { console.log(`${lc} complete. (I:
|
|
70
|
+
if (logalot) { console.log(`${lc} complete. (I: d515f834dd18286f2fe1871605888c26)`); }
|
|
71
71
|
}
|
|
72
72
|
}
|
|
@@ -14,6 +14,7 @@ import { B2TFS_BRANCH_DEFAULT_NAME } from '@ibgib/core-gib/dist/vcs/branch/branc
|
|
|
14
14
|
|
|
15
15
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
16
16
|
import { bootstrapVcsMetaspace } from '../../bootstrap/node-bootstrap.mjs';
|
|
17
|
+
import { getB2tFSIndexIbGib } from '@ibgib/core-gib/dist/vcs/index/index-helper.mjs';
|
|
17
18
|
import { writeVcsIndexProjectionToDisk } from '../vcs-projection-helper.mjs';
|
|
18
19
|
|
|
19
20
|
const lcFile = `[init-cmd]`;
|
|
@@ -46,12 +47,27 @@ export async function executeInitCmd({
|
|
|
46
47
|
await fs.mkdir(absTargetDir, { recursive: true });
|
|
47
48
|
|
|
48
49
|
// 2. Bootstrap Metaspace and localSpace (creates .vcsgib on disk)
|
|
49
|
-
const { metaspace, localSpace } = await bootstrapVcsMetaspace({
|
|
50
|
+
const { metaspace, localSpace, foundVcsPath } = await bootstrapVcsMetaspace({
|
|
50
51
|
repoPath: absTargetDir,
|
|
51
52
|
vcsFolderName,
|
|
52
53
|
defaultSpaceName: `vcs_${path.basename(absTargetDir).replace(/[^a-zA-Z0-9_\-]/g, '_')}`,
|
|
53
54
|
});
|
|
54
55
|
|
|
56
|
+
if (foundVcsPath) {
|
|
57
|
+
const existingIndex = await getB2tFSIndexIbGib({ space: localSpace, metaspace });
|
|
58
|
+
if (existingIndex) {
|
|
59
|
+
if (!quiet) {
|
|
60
|
+
console.log(`Reinitialized existing ibgib repository in ${vcsPath}`);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
vcsPath,
|
|
64
|
+
spaceId: existingIndex.data.activeSpaceId,
|
|
65
|
+
branchName: existingIndex.data.activeBranchName || defaultBranchName,
|
|
66
|
+
rootItemIb: '',
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
55
71
|
// 3. Facade instantiation and domain init
|
|
56
72
|
const repo = new VcsRepository({
|
|
57
73
|
metaspace,
|
|
@@ -9,7 +9,7 @@ import path from 'node:path';
|
|
|
9
9
|
import fs from 'node:fs/promises';
|
|
10
10
|
|
|
11
11
|
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
12
|
-
|
|
12
|
+
import { getAllBranchInfosFromIndex } from '@ibgib/core-gib/dist/vcs/branch/branch-helper.mjs';
|
|
13
13
|
|
|
14
14
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
15
15
|
import { openVcsRepository } from '../vcs-repo-helper.mjs';
|
|
@@ -33,6 +33,7 @@ export interface LogCmdOpts {
|
|
|
33
33
|
targetDir?: string;
|
|
34
34
|
vcsFolderName?: string;
|
|
35
35
|
filePath?: string;
|
|
36
|
+
branchName?: string;
|
|
36
37
|
allComments?: boolean;
|
|
37
38
|
quiet?: boolean;
|
|
38
39
|
}
|
|
@@ -47,6 +48,7 @@ export async function executeLogCmd({
|
|
|
47
48
|
targetDir = process.cwd(),
|
|
48
49
|
vcsFolderName = '.vcsgib',
|
|
49
50
|
filePath,
|
|
51
|
+
branchName,
|
|
50
52
|
allComments = false,
|
|
51
53
|
quiet = false,
|
|
52
54
|
}: LogCmdOpts = {}): Promise<LogCmdResult> {
|
|
@@ -54,19 +56,35 @@ export async function executeLogCmd({
|
|
|
54
56
|
|
|
55
57
|
try {
|
|
56
58
|
if (logalot) {
|
|
57
|
-
console.log(`${lc} starting executeLogCmd (I:
|
|
59
|
+
console.log(`${lc} starting executeLogCmd (I: c6920dc083bff49d8b4dd148a36de826)`);
|
|
58
60
|
}
|
|
59
61
|
|
|
60
62
|
const absTargetDir = path.resolve(targetDir);
|
|
61
63
|
const { repo } = await openVcsRepository({ targetDir: absTargetDir, vcsFolderName });
|
|
62
64
|
const indexIbGib = await repo.getIndexIbGib();
|
|
63
|
-
|
|
65
|
+
|
|
66
|
+
let resolvedBranchName = branchName;
|
|
67
|
+
let resolvedFilePath = filePath;
|
|
68
|
+
|
|
69
|
+
if (!resolvedBranchName && resolvedFilePath) {
|
|
70
|
+
const branchInfos = await getAllBranchInfosFromIndex({ indexIbGib });
|
|
71
|
+
if (branchInfos.some(b => b.branchName === resolvedFilePath)) {
|
|
72
|
+
resolvedBranchName = resolvedFilePath;
|
|
73
|
+
resolvedFilePath = undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const activeBranchSpace = await repo.getActiveBranchSpace({
|
|
78
|
+
indexIbGib,
|
|
79
|
+
targetDir: absTargetDir,
|
|
80
|
+
branchName: resolvedBranchName,
|
|
81
|
+
});
|
|
64
82
|
|
|
65
83
|
const logRes = await repo.log({
|
|
66
84
|
activeBranchSpace,
|
|
67
85
|
indexIbGib,
|
|
68
|
-
|
|
69
|
-
filePath,
|
|
86
|
+
branchName: resolvedBranchName,
|
|
87
|
+
filePath: resolvedFilePath,
|
|
70
88
|
allComments,
|
|
71
89
|
targetDir: absTargetDir,
|
|
72
90
|
});
|
|
@@ -75,7 +93,7 @@ export async function executeLogCmd({
|
|
|
75
93
|
|
|
76
94
|
if (!quiet) {
|
|
77
95
|
if (logRes.targetPath) {
|
|
78
|
-
console.log(`File: ${logRes.targetPath} (branch: ${logRes.branchName}) (I:
|
|
96
|
+
console.log(`File: ${logRes.targetPath} (branch: ${logRes.branchName}) (I: 5b56b87941a81ed7e9036f382ca80326)`);
|
|
79
97
|
if (commits.length === 0) {
|
|
80
98
|
console.log('No comments found for this file.');
|
|
81
99
|
} else {
|
|
@@ -86,7 +104,7 @@ export async function executeLogCmd({
|
|
|
86
104
|
}
|
|
87
105
|
}
|
|
88
106
|
} else {
|
|
89
|
-
console.log(`Branch: ${logRes.branchName} (I:
|
|
107
|
+
console.log(`Branch: ${logRes.branchName} (I: da4a28fe715c302be839ad08d9f0ca26)`);
|
|
90
108
|
if (commits.length === 0) {
|
|
91
109
|
console.log('No commits yet.');
|
|
92
110
|
} else {
|
|
@@ -116,11 +134,11 @@ export async function executeLogCmd({
|
|
|
116
134
|
commits,
|
|
117
135
|
};
|
|
118
136
|
} catch (error) {
|
|
119
|
-
console.error(`${lc} ${extractErrorMsg(error)} (E:
|
|
137
|
+
console.error(`${lc} ${extractErrorMsg(error)} (E: f279d589ced70f7e78050948f2191e26)`);
|
|
120
138
|
throw error;
|
|
121
139
|
} finally {
|
|
122
140
|
if (logalot) {
|
|
123
|
-
console.log(`${lc} complete. (I:
|
|
141
|
+
console.log(`${lc} complete. (I: 081e084ef158f7a608fd16a801bedf26)`);
|
|
124
142
|
}
|
|
125
143
|
}
|
|
126
144
|
}
|
|
@@ -42,40 +42,38 @@ export async function executeMergeCmd({
|
|
|
42
42
|
const lc = `${lcFile}[${executeMergeCmd.name}]`;
|
|
43
43
|
try {
|
|
44
44
|
if (logalot) {
|
|
45
|
-
console.log(`${lc} starting... (I:
|
|
45
|
+
console.log(`${lc} starting... (I: d14fb7ac187875d165abcbf8fe51ce26)`);
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const trimmedIncomingBranchName = incomingBranchName?.trim();
|
|
49
49
|
if (!trimmedIncomingBranchName) {
|
|
50
|
-
throw new Error(`Branch name is required for merge (E:
|
|
50
|
+
throw new Error(`Branch name is required for merge (E: f47fd65e49a8518da859217ae1bef826)`);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
const absTargetDir = path.resolve(targetDir);
|
|
54
54
|
const { repo, vcsPath, activeWorktreeDir } =
|
|
55
55
|
await openVcsRepository({ targetDir: absTargetDir, vcsFolderName });
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
const baseBranchName = await repo.getActiveBranchName();
|
|
57
|
+
const indexIbGib = await repo.getIndexIbGib();
|
|
58
|
+
const baseBranchName = await repo.getActiveBranchName({ indexIbGib, targetDir: absTargetDir });
|
|
59
59
|
|
|
60
60
|
const incomingSpaceRes = await getOrCreateBranchSpace({
|
|
61
61
|
metaspace: repo.metaspace,
|
|
62
62
|
branchName: trimmedIncomingBranchName,
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
const activeBranchSpace = await repo.getActiveBranchSpace();
|
|
65
|
+
const activeBranchSpace = await repo.getActiveBranchSpace({ indexIbGib, targetDir: absTargetDir });
|
|
66
66
|
const activeBranchSpaceId = getSpaceIdFromIb(activeBranchSpace.ib);
|
|
67
67
|
|
|
68
68
|
const mergeRes = await repo.merge({
|
|
69
|
-
baseBranchSpace: activeBranchSpace,
|
|
70
|
-
// message,
|
|
71
|
-
// repoRoot,
|
|
69
|
+
baseBranchSpace: activeBranchSpace,
|
|
72
70
|
incomingBranchName: trimmedIncomingBranchName,
|
|
73
71
|
incomingBranchSpace: incomingSpaceRes.space,
|
|
74
72
|
targetDir: absTargetDir,
|
|
75
73
|
});
|
|
76
74
|
|
|
77
75
|
if (!quiet) {
|
|
78
|
-
console.log(`Successfully merged branch '${trimmedIncomingBranchName}' into '${baseBranchName}' (I:
|
|
76
|
+
console.log(`Successfully merged branch '${trimmedIncomingBranchName}' into '${baseBranchName}' (I: 943c67d40bb8a3177d470da667571726)`);
|
|
79
77
|
console.log(` Worktree projection: ${activeWorktreeDir}`);
|
|
80
78
|
}
|
|
81
79
|
|
|
@@ -89,11 +87,11 @@ export async function executeMergeCmd({
|
|
|
89
87
|
worktreePath: activeWorktreeDir,
|
|
90
88
|
};
|
|
91
89
|
} catch (error) {
|
|
92
|
-
console.error(`${lc} ${extractErrorMsg(error)} (E:
|
|
90
|
+
console.error(`${lc} ${extractErrorMsg(error)} (E: acfb283f49f8e533586e0578ac9d4426)`);
|
|
93
91
|
throw error;
|
|
94
92
|
} finally {
|
|
95
93
|
if (logalot) {
|
|
96
|
-
console.log(`${lc} complete. (I:
|
|
94
|
+
console.log(`${lc} complete. (I: 67210ef7c05454c19cdb6b08149b7326)`);
|
|
97
95
|
}
|
|
98
96
|
}
|
|
99
97
|
}
|
package/src/cli/vcs-cli-main.mts
CHANGED
|
@@ -126,9 +126,11 @@ export async function main({
|
|
|
126
126
|
case VCS_SUBCOMMANDS.LOG: {
|
|
127
127
|
const targetDir = process.cwd();
|
|
128
128
|
const filePath = parsed.positionals[0];
|
|
129
|
+
const branchName = parsed.flags.branchName;
|
|
129
130
|
await executeLogCmd({
|
|
130
131
|
targetDir,
|
|
131
132
|
filePath,
|
|
133
|
+
branchName,
|
|
132
134
|
allComments: parsed.flags.all,
|
|
133
135
|
});
|
|
134
136
|
break;
|
|
@@ -183,7 +185,25 @@ export async function main({
|
|
|
183
185
|
|
|
184
186
|
return 0;
|
|
185
187
|
} catch (error) {
|
|
186
|
-
|
|
188
|
+
let rawMsg = extractErrorMsg(error);
|
|
189
|
+
// Strip trailing internal UUID / error markers like (E: ...)
|
|
190
|
+
const cleanMsg = rawMsg.replace(/\s*\(E:\s*[a-f0-9-]+\)\s*$/i, '').trim();
|
|
191
|
+
|
|
192
|
+
if (cleanMsg.startsWith('fatal:') || cleanMsg.startsWith('error:')) {
|
|
193
|
+
console.error(cleanMsg);
|
|
194
|
+
} else if (cleanMsg.toLowerCase().includes('nothing to commit')) {
|
|
195
|
+
console.error('nothing to commit, working tree clean');
|
|
196
|
+
} else if (cleanMsg.toLowerCase().includes('already exists')) {
|
|
197
|
+
const branchMatch = cleanMsg.match(/["']([^"']+)["']/);
|
|
198
|
+
const name = branchMatch ? branchMatch[1] : '';
|
|
199
|
+
console.error(name ? `fatal: a branch named '${name}' already exists.` : `fatal: ${cleanMsg}`);
|
|
200
|
+
} else if (cleanMsg.toLowerCase().includes('not found in indexibgib') || cleanMsg.toLowerCase().includes('not found on branch')) {
|
|
201
|
+
const branchMatch = cleanMsg.match(/\(([^)]+)\)/) || cleanMsg.match(/['"]([^'"]+)['"]/);
|
|
202
|
+
const name = branchMatch ? branchMatch[1] : '';
|
|
203
|
+
console.error(name ? `error: pathspec '${name}' did not match any file(s) known to ibgib` : `error: ${cleanMsg}`);
|
|
204
|
+
} else {
|
|
205
|
+
console.error(`fatal: ${cleanMsg}`);
|
|
206
|
+
}
|
|
187
207
|
return 1;
|
|
188
208
|
} finally {
|
|
189
209
|
if (logalot) {
|
|
@@ -45,15 +45,20 @@ export async function openVcsRepository({
|
|
|
45
45
|
const absTargetDir = path.resolve(targetDir);
|
|
46
46
|
|
|
47
47
|
// 1. Locate repository root and bootstrap Node localSpace
|
|
48
|
-
const { metaspace, localSpace, vcsPath, repoRoot } = await bootstrapVcsMetaspace({
|
|
48
|
+
const { metaspace, localSpace, vcsPath, repoRoot, foundVcsPath } = await bootstrapVcsMetaspace({
|
|
49
49
|
repoPath: absTargetDir,
|
|
50
50
|
vcsFolderName,
|
|
51
|
+
mustExist: true,
|
|
51
52
|
});
|
|
52
53
|
|
|
54
|
+
if (!foundVcsPath) {
|
|
55
|
+
throw new Error(`fatal: not an ibgib repository (or any of the parent directories): ${vcsFolderName}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
53
58
|
// 2. Fetch authoritative in-band index from localSpace
|
|
54
59
|
const indexIbGib = await getB2tFSIndexIbGib({ space: localSpace, metaspace });
|
|
55
60
|
if (!indexIbGib) {
|
|
56
|
-
throw new Error(`
|
|
61
|
+
throw new Error(`fatal: not an ibgib repository (index not found in ${vcsPath})`);
|
|
57
62
|
}
|
|
58
63
|
|
|
59
64
|
// 3. Determine active branch and worktree directory
|