@ibgib/vcs-gib 0.0.6 → 0.0.17
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 +24 -2
- package/VCS_CLI_USER_GUIDE.md +2 -2
- package/dist/AUTO-GENERATED-version.d.mts +1 -1
- package/dist/AUTO-GENERATED-version.d.mts.map +1 -1
- package/dist/AUTO-GENERATED-version.mjs +1 -1
- package/dist/AUTO-GENERATED-version.mjs.map +1 -1
- package/dist/bootstrap/node-bootstrap.d.mts.map +1 -1
- package/dist/bootstrap/node-bootstrap.mjs +6 -0
- package/dist/bootstrap/node-bootstrap.mjs.map +1 -1
- package/dist/cli/cli-arg-parser.d.mts +3 -0
- package/dist/cli/cli-arg-parser.d.mts.map +1 -1
- package/dist/cli/cli-arg-parser.mjs +13 -1
- package/dist/cli/cli-arg-parser.mjs.map +1 -1
- package/dist/cli/cli-constants.d.mts +5 -0
- package/dist/cli/cli-constants.d.mts.map +1 -1
- package/dist/cli/cli-constants.mjs +23 -0
- package/dist/cli/cli-constants.mjs.map +1 -1
- package/dist/cli/cli-e2e.respec.node.mjs +1 -1
- package/dist/cli/cli-e2e.respec.node.mjs.map +1 -1
- package/dist/cli/commands/add-cmd.d.mts.map +1 -1
- package/dist/cli/commands/add-cmd.mjs +33 -28
- package/dist/cli/commands/add-cmd.mjs.map +1 -1
- package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs +70 -0
- package/dist/cli/commands/branch-checkout-cmd.respec.node.mjs.map +1 -1
- package/dist/cli/commands/branch-cmd.d.mts +2 -1
- package/dist/cli/commands/branch-cmd.d.mts.map +1 -1
- package/dist/cli/commands/branch-cmd.mjs +57 -6
- package/dist/cli/commands/branch-cmd.mjs.map +1 -1
- package/dist/cli/commands/checkout-cmd.d.mts.map +1 -1
- package/dist/cli/commands/checkout-cmd.mjs +23 -11
- package/dist/cli/commands/checkout-cmd.mjs.map +1 -1
- package/dist/cli/commands/commit-cmd.d.mts.map +1 -1
- package/dist/cli/commands/commit-cmd.mjs +24 -21
- package/dist/cli/commands/commit-cmd.mjs.map +1 -1
- package/dist/cli/commands/reset-cmd.d.mts +21 -0
- package/dist/cli/commands/reset-cmd.d.mts.map +1 -0
- package/dist/cli/commands/reset-cmd.mjs +93 -0
- package/dist/cli/commands/reset-cmd.mjs.map +1 -0
- package/dist/cli/commands/reset-restore-cmd.respec.node.d.mts +7 -0
- package/dist/cli/commands/reset-restore-cmd.respec.node.d.mts.map +1 -0
- package/dist/cli/commands/reset-restore-cmd.respec.node.mjs +185 -0
- package/dist/cli/commands/reset-restore-cmd.respec.node.mjs.map +1 -0
- package/dist/cli/commands/restore-cmd.d.mts +22 -0
- package/dist/cli/commands/restore-cmd.d.mts.map +1 -0
- package/dist/cli/commands/restore-cmd.mjs +115 -0
- package/dist/cli/commands/restore-cmd.mjs.map +1 -0
- package/dist/cli/commands/status-add-cmd.respec.node.mjs +24 -0
- package/dist/cli/commands/status-add-cmd.respec.node.mjs.map +1 -1
- package/dist/cli/vcs-cli-main.d.mts.map +1 -1
- package/dist/cli/vcs-cli-main.mjs +29 -3
- package/dist/cli/vcs-cli-main.mjs.map +1 -1
- package/dist/engine/branch/branch-graph-helper.d.mts +12 -3
- package/dist/engine/branch/branch-graph-helper.d.mts.map +1 -1
- package/dist/engine/branch/branch-graph-helper.mjs +50 -18
- package/dist/engine/branch/branch-graph-helper.mjs.map +1 -1
- package/dist/engine/branch/branch-space-helper.d.mts +1 -0
- package/dist/engine/branch/branch-space-helper.d.mts.map +1 -1
- package/dist/engine/branch/branch-space-helper.mjs +1 -0
- package/dist/engine/branch/branch-space-helper.mjs.map +1 -1
- package/dist/engine/branch/branch-space.respec.node.mjs +11 -6
- package/dist/engine/branch/branch-space.respec.node.mjs.map +1 -1
- package/dist/engine/index/index-helper.d.mts +35 -0
- package/dist/engine/index/index-helper.d.mts.map +1 -1
- package/dist/engine/index/index-helper.mjs +241 -0
- package/dist/engine/index/index-helper.mjs.map +1 -1
- package/dist/engine/item/item-helper.d.mts +29 -3
- package/dist/engine/item/item-helper.d.mts.map +1 -1
- package/dist/engine/item/item-helper.mjs +234 -56
- package/dist/engine/item/item-helper.mjs.map +1 -1
- package/dist/engine/item/item.respec.node.d.mts +7 -0
- package/dist/engine/item/item.respec.node.d.mts.map +1 -0
- package/dist/engine/item/item.respec.node.mjs +75 -0
- package/dist/engine/item/item.respec.node.mjs.map +1 -0
- package/package.json +3 -3
- package/src/AUTO-GENERATED-version.mts +1 -1
- package/src/bootstrap/node-bootstrap.mts +2 -0
- package/src/cli/cli-arg-parser.mts +15 -0
- package/src/cli/cli-constants.mts +26 -0
- package/src/cli/cli-e2e.respec.node.mts +2 -2
- package/src/cli/commands/add-cmd.mts +36 -26
- package/src/cli/commands/branch-checkout-cmd.respec.node.mts +79 -0
- package/src/cli/commands/branch-cmd.mts +75 -6
- package/src/cli/commands/checkout-cmd.mts +25 -14
- package/src/cli/commands/commit-cmd.mts +30 -23
- package/src/cli/commands/reset-cmd.mts +128 -0
- package/src/cli/commands/reset-restore-cmd.respec.node.mts +222 -0
- package/src/cli/commands/restore-cmd.mts +155 -0
- package/src/cli/commands/status-add-cmd.respec.node.mts +27 -0
- package/src/cli/vcs-cli-main.mts +29 -3
- package/src/engine/branch/branch-graph-helper.mts +66 -18
- package/src/engine/branch/branch-space-helper.mts +6 -0
- package/src/engine/branch/branch-space.respec.node.mts +12 -6
- package/src/engine/index/index-helper.mts +324 -0
- package/src/engine/item/item-helper.mts +284 -58
- package/src/engine/item/item.respec.node.mts +92 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/test_runs/001-hello-node/20260728_090100_0001-flow-core-main.md +0 -39
- package/test_runs/001-hello-node/20260728_090200_0003-flow-branching-worktree.md +0 -54
- package/test_runs/001-hello-node/20260728_090300_0002-flow-selective-add.md +0 -45
- package/test_runs/001-hello-node/20260728_142100_0007-flow-edge-cases.md +0 -44
- package/test_runs/001-hello-node/20260728_142400_0005-flow-hardcoded-ignores.md +0 -36
- package/tools/pack-for-test.mjs +0 -73
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module reset-restore-cmd.respec
|
|
3
|
+
*
|
|
4
|
+
* Unit tests for `vcs reset` and `vcs restore` command handlers.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import fs from 'node:fs/promises';
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
respecfully, ifWe, iReckon
|
|
12
|
+
} from '@ibgib/helper-gib/dist/respec-gib/respec-gib.mjs';
|
|
13
|
+
|
|
14
|
+
import { executeInitCmd } from './init-cmd.mjs';
|
|
15
|
+
import { executeAddCmd } from './add-cmd.mjs';
|
|
16
|
+
import { executeCommitCmd } from './commit-cmd.mjs';
|
|
17
|
+
import { executeStatusCmd } from './status-cmd.mjs';
|
|
18
|
+
import { executeResetCmd } from './reset-cmd.mjs';
|
|
19
|
+
import { executeRestoreCmd } from './restore-cmd.mjs';
|
|
20
|
+
|
|
21
|
+
const lc = `[apps/vcs-gib/src/cli/commands/reset-restore-cmd.respec.node.mts]`;
|
|
22
|
+
|
|
23
|
+
await respecfully(lc, `vcs reset and vcs restore Command Handlers`, async () => {
|
|
24
|
+
|
|
25
|
+
await ifWe(lc, `vcs reset clears staged file from index while keeping disk file edits intact`, async () => {
|
|
26
|
+
const testDir = path.join(process.cwd(), '.test_reset_1');
|
|
27
|
+
const vcsFolderName = '.vcsgib_test_reset_1';
|
|
28
|
+
try {
|
|
29
|
+
await executeInitCmd({
|
|
30
|
+
targetDir: testDir,
|
|
31
|
+
vcsFolderName,
|
|
32
|
+
quiet: true,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
await fs.writeFile(path.join(testDir, 'foo.txt'), 'Hello Foo', 'utf8');
|
|
36
|
+
|
|
37
|
+
await executeAddCmd({
|
|
38
|
+
paths: ['foo.txt'],
|
|
39
|
+
targetDir: testDir,
|
|
40
|
+
vcsFolderName,
|
|
41
|
+
quiet: true,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
let statusRes = await executeStatusCmd({
|
|
45
|
+
targetDir: testDir,
|
|
46
|
+
vcsFolderName,
|
|
47
|
+
quiet: true,
|
|
48
|
+
});
|
|
49
|
+
iReckon(lc, statusRes.staged.map(x => x.path)).includes('foo.txt');
|
|
50
|
+
|
|
51
|
+
// Modify file on disk after staging
|
|
52
|
+
await fs.writeFile(path.join(testDir, 'foo.txt'), 'Hello Foo Modified', 'utf8');
|
|
53
|
+
|
|
54
|
+
// Execute reset
|
|
55
|
+
const resetRes = await executeResetCmd({
|
|
56
|
+
paths: ['foo.txt'],
|
|
57
|
+
targetDir: testDir,
|
|
58
|
+
vcsFolderName,
|
|
59
|
+
quiet: true,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
iReckon(lc, resetRes.unstagedPaths).includes('foo.txt');
|
|
63
|
+
|
|
64
|
+
statusRes = await executeStatusCmd({
|
|
65
|
+
targetDir: testDir,
|
|
66
|
+
vcsFolderName,
|
|
67
|
+
quiet: true,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Verify file is no longer staged
|
|
71
|
+
iReckon(lc, statusRes.staged.map(x => x.path)).not.includes('foo.txt');
|
|
72
|
+
iReckon(lc, statusRes.untracked.map(x => x.path)).includes('foo.txt');
|
|
73
|
+
|
|
74
|
+
// Verify disk content is still intact
|
|
75
|
+
const diskContent = await fs.readFile(path.join(testDir, 'foo.txt'), 'utf8');
|
|
76
|
+
iReckon(lc, diskContent).willEqual('Hello Foo Modified');
|
|
77
|
+
} finally {
|
|
78
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await ifWe(lc, `vcs restore --staged unstages file from index while keeping disk edits intact`, async () => {
|
|
83
|
+
const testDir = path.join(process.cwd(), '.test_restore_staged');
|
|
84
|
+
const vcsFolderName = '.vcsgib_test_restore_staged';
|
|
85
|
+
try {
|
|
86
|
+
await executeInitCmd({
|
|
87
|
+
targetDir: testDir,
|
|
88
|
+
vcsFolderName,
|
|
89
|
+
quiet: true,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
await fs.writeFile(path.join(testDir, 'bar.txt'), 'Initial Bar', 'utf8');
|
|
93
|
+
|
|
94
|
+
await executeAddCmd({
|
|
95
|
+
paths: ['bar.txt'],
|
|
96
|
+
targetDir: testDir,
|
|
97
|
+
vcsFolderName,
|
|
98
|
+
quiet: true,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await fs.writeFile(path.join(testDir, 'bar.txt'), 'Edited Bar', 'utf8');
|
|
102
|
+
|
|
103
|
+
const restoreRes = await executeRestoreCmd({
|
|
104
|
+
paths: ['bar.txt'],
|
|
105
|
+
targetDir: testDir,
|
|
106
|
+
vcsFolderName,
|
|
107
|
+
staged: true,
|
|
108
|
+
quiet: true,
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
iReckon(lc, restoreRes.unstagedPaths).includes('bar.txt');
|
|
112
|
+
|
|
113
|
+
const statusRes = await executeStatusCmd({
|
|
114
|
+
targetDir: testDir,
|
|
115
|
+
vcsFolderName,
|
|
116
|
+
quiet: true,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
iReckon(lc, statusRes.staged.map(x => x.path)).not.includes('bar.txt');
|
|
120
|
+
|
|
121
|
+
const diskContent = await fs.readFile(path.join(testDir, 'bar.txt'), 'utf8');
|
|
122
|
+
iReckon(lc, diskContent).willEqual('Edited Bar');
|
|
123
|
+
} finally {
|
|
124
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await ifWe(lc, `vcs restore <file> reverts modified disk file back to committed snapshot content`, async () => {
|
|
129
|
+
const testDir = path.join(process.cwd(), '.test_restore_worktree');
|
|
130
|
+
const vcsFolderName = '.vcsgib_test_restore_worktree';
|
|
131
|
+
try {
|
|
132
|
+
await executeInitCmd({
|
|
133
|
+
targetDir: testDir,
|
|
134
|
+
vcsFolderName,
|
|
135
|
+
quiet: true,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await fs.writeFile(path.join(testDir, 'committed.txt'), 'Original Committed Content', 'utf8');
|
|
139
|
+
|
|
140
|
+
await executeAddCmd({
|
|
141
|
+
paths: ['committed.txt'],
|
|
142
|
+
targetDir: testDir,
|
|
143
|
+
vcsFolderName,
|
|
144
|
+
quiet: true,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
await executeCommitCmd({
|
|
148
|
+
message: 'Initial commit',
|
|
149
|
+
targetDir: testDir,
|
|
150
|
+
vcsFolderName,
|
|
151
|
+
quiet: true,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// Modify file on disk
|
|
155
|
+
await fs.writeFile(path.join(testDir, 'committed.txt'), 'Modified Bad Content', 'utf8');
|
|
156
|
+
|
|
157
|
+
// Restore worktree file
|
|
158
|
+
const restoreRes = await executeRestoreCmd({
|
|
159
|
+
paths: ['committed.txt'],
|
|
160
|
+
targetDir: testDir,
|
|
161
|
+
vcsFolderName,
|
|
162
|
+
quiet: true,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
iReckon(lc, restoreRes.restoredPaths).includes('committed.txt');
|
|
166
|
+
|
|
167
|
+
// Verify disk content is reverted back to committed snapshot content
|
|
168
|
+
const diskContent = await fs.readFile(path.join(testDir, 'committed.txt'), 'utf8');
|
|
169
|
+
iReckon(lc, diskContent).willEqual('Original Committed Content');
|
|
170
|
+
} finally {
|
|
171
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
await ifWe(lc, `vcs reset --all unstages all files from index`, async () => {
|
|
176
|
+
const testDir = path.join(process.cwd(), '.test_reset_all');
|
|
177
|
+
const vcsFolderName = '.vcsgib_test_reset_all';
|
|
178
|
+
try {
|
|
179
|
+
await executeInitCmd({
|
|
180
|
+
targetDir: testDir,
|
|
181
|
+
vcsFolderName,
|
|
182
|
+
quiet: true,
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await fs.writeFile(path.join(testDir, 'f1.txt'), 'F1', 'utf8');
|
|
186
|
+
await fs.writeFile(path.join(testDir, 'f2.txt'), 'F2', 'utf8');
|
|
187
|
+
|
|
188
|
+
await executeAddCmd({
|
|
189
|
+
all: true,
|
|
190
|
+
targetDir: testDir,
|
|
191
|
+
vcsFolderName,
|
|
192
|
+
quiet: true,
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
let statusRes = await executeStatusCmd({
|
|
196
|
+
targetDir: testDir,
|
|
197
|
+
vcsFolderName,
|
|
198
|
+
quiet: true,
|
|
199
|
+
});
|
|
200
|
+
iReckon(lc, statusRes.staged.length).willEqual(2);
|
|
201
|
+
|
|
202
|
+
const resetRes = await executeResetCmd({
|
|
203
|
+
all: true,
|
|
204
|
+
targetDir: testDir,
|
|
205
|
+
vcsFolderName,
|
|
206
|
+
quiet: true,
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
iReckon(lc, resetRes.unstagedPaths.length).willEqual(2);
|
|
210
|
+
|
|
211
|
+
statusRes = await executeStatusCmd({
|
|
212
|
+
targetDir: testDir,
|
|
213
|
+
vcsFolderName,
|
|
214
|
+
quiet: true,
|
|
215
|
+
});
|
|
216
|
+
iReckon(lc, statusRes.staged.length).willEqual(0);
|
|
217
|
+
} finally {
|
|
218
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
});
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module restore-cmd
|
|
3
|
+
*
|
|
4
|
+
* Command handler for `vcs restore [path...]`.
|
|
5
|
+
* Restores working tree files from committed branch snapshot, or unstages files if `--staged` is set.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import fs from 'node:fs/promises';
|
|
10
|
+
|
|
11
|
+
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
12
|
+
import { promptForConfirm } from '@ibgib/helper-gib/dist/helpers/node-helper.mjs';
|
|
13
|
+
import { putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
|
|
14
|
+
|
|
15
|
+
import { bootstrapVcsMetaspace } from '../../bootstrap/node-bootstrap.mjs';
|
|
16
|
+
import { getOrCreateBranchSpace } from '../../engine/branch/branch-space-helper.mjs';
|
|
17
|
+
import { getB2tFSIndexIbGib, unstagePathsFromIndex, restoreWorktreePathsFromSnapshot } from '../../engine/index/index-helper.mjs';
|
|
18
|
+
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
19
|
+
|
|
20
|
+
const lcFile = `[restore-cmd]`;
|
|
21
|
+
const logalot = GLOBAL_LOG_A_LOT;
|
|
22
|
+
|
|
23
|
+
export interface RestoreCmdOpts {
|
|
24
|
+
paths?: string[];
|
|
25
|
+
targetDir?: string;
|
|
26
|
+
vcsFolderName?: string;
|
|
27
|
+
staged?: boolean;
|
|
28
|
+
worktree?: boolean;
|
|
29
|
+
yes?: boolean;
|
|
30
|
+
force?: boolean;
|
|
31
|
+
quiet?: boolean;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface RestoreCmdResult {
|
|
35
|
+
unstagedPaths?: string[];
|
|
36
|
+
restoredPaths?: string[];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function executeRestoreCmd({
|
|
40
|
+
paths = [],
|
|
41
|
+
targetDir = process.cwd(),
|
|
42
|
+
vcsFolderName = '.vcsgib',
|
|
43
|
+
staged = false,
|
|
44
|
+
worktree = false,
|
|
45
|
+
yes = false,
|
|
46
|
+
force = false,
|
|
47
|
+
quiet = false,
|
|
48
|
+
}: RestoreCmdOpts = {}): Promise<RestoreCmdResult> {
|
|
49
|
+
const lc = `${lcFile}[${executeRestoreCmd.name}]`;
|
|
50
|
+
try {
|
|
51
|
+
if (logalot) {
|
|
52
|
+
console.log(`${lc} starting... (I: 6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1e)`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const absTargetDir = path.resolve(targetDir);
|
|
56
|
+
|
|
57
|
+
const { metaspace, localSpace, vcsPath, repoRoot } = await bootstrapVcsMetaspace({
|
|
58
|
+
repoPath: absTargetDir,
|
|
59
|
+
vcsFolderName,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Verify repo exists
|
|
63
|
+
try {
|
|
64
|
+
await fs.access(vcsPath);
|
|
65
|
+
} catch {
|
|
66
|
+
throw new Error(`Not an ibgib repository (directory ${vcsPath} does not exist) (E: 7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2e)`);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Retrieve authoritative B2tFSIndexIbGib_V1 from space
|
|
70
|
+
const indexIbGib = await getB2tFSIndexIbGib({ space: localSpace, vcsPath });
|
|
71
|
+
if (!indexIbGib) {
|
|
72
|
+
throw new Error(`Repository not initialized. Run 'vcs init' first. (E: 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3e)`);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const activeBranch = indexIbGib.data?.activeBranch || 'main';
|
|
76
|
+
const activeWorktreeDir = activeBranch === 'main' ? repoRoot : path.join(repoRoot, 'b', activeBranch);
|
|
77
|
+
|
|
78
|
+
const { space: activeSpace } = await getOrCreateBranchSpace({
|
|
79
|
+
metaspace,
|
|
80
|
+
vcsPath,
|
|
81
|
+
branchName: activeBranch,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const skipPrompt = yes || force || quiet || !process.stdin.isTTY;
|
|
85
|
+
if (!skipPrompt) {
|
|
86
|
+
const msg = staged
|
|
87
|
+
? 'Unstage specified files from index?'
|
|
88
|
+
: 'Revert working tree files to committed snapshot?';
|
|
89
|
+
const confirmed = await promptForConfirm({ msg });
|
|
90
|
+
if (!confirmed) {
|
|
91
|
+
if (!quiet) {
|
|
92
|
+
console.log('Operation cancelled.');
|
|
93
|
+
}
|
|
94
|
+
return { unstagedPaths: [], restoredPaths: [] };
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
let unstagedPaths: string[] | undefined;
|
|
99
|
+
let restoredPaths: string[] | undefined;
|
|
100
|
+
|
|
101
|
+
if (staged) {
|
|
102
|
+
const unstageRes = await unstagePathsFromIndex({
|
|
103
|
+
indexIbGib,
|
|
104
|
+
paths,
|
|
105
|
+
targetDir,
|
|
106
|
+
activeWorktreeDir,
|
|
107
|
+
vcsPath,
|
|
108
|
+
space: activeSpace,
|
|
109
|
+
metaspace,
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
if (localSpace !== activeSpace) {
|
|
113
|
+
await putInSpace({ space: localSpace, ibGib: unstageRes.updatedIndex });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
unstagedPaths = unstageRes.unstagedPaths;
|
|
117
|
+
if (!quiet) {
|
|
118
|
+
for (const p of unstagedPaths) {
|
|
119
|
+
console.log(`unstaged: ${p}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if (!staged || worktree) {
|
|
125
|
+
const restoreRes = await restoreWorktreePathsFromSnapshot({
|
|
126
|
+
paths,
|
|
127
|
+
targetDir,
|
|
128
|
+
activeWorktreeDir,
|
|
129
|
+
activeBranchSpace: activeSpace,
|
|
130
|
+
metaspace,
|
|
131
|
+
indexIbGib,
|
|
132
|
+
vcsPath,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
restoredPaths = restoreRes.restoredPaths;
|
|
136
|
+
if (!quiet) {
|
|
137
|
+
for (const p of restoredPaths) {
|
|
138
|
+
console.log(`restored: ${p}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return {
|
|
144
|
+
unstagedPaths,
|
|
145
|
+
restoredPaths,
|
|
146
|
+
};
|
|
147
|
+
} catch (error) {
|
|
148
|
+
console.error(`${lc} ${extractErrorMsg(error)} (E: 9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4e)`);
|
|
149
|
+
throw error;
|
|
150
|
+
} finally {
|
|
151
|
+
if (logalot) {
|
|
152
|
+
console.log(`${lc} complete. (I: 0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5e)`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
@@ -243,4 +243,31 @@ await respecfully(lc, `vcs status and vcs add Command Handlers`, async () => {
|
|
|
243
243
|
await fs.rm(testDir, { recursive: true, force: true });
|
|
244
244
|
}
|
|
245
245
|
});
|
|
246
|
+
|
|
247
|
+
await ifWe(lc, `stages relative file paths correctly when targetDir is a subdirectory`, async () => {
|
|
248
|
+
const testDir = path.join(process.cwd(), '.test_status_add_subdir');
|
|
249
|
+
const vcsFolderName = '.vcsgib_test_subdir';
|
|
250
|
+
try {
|
|
251
|
+
await executeInitCmd({
|
|
252
|
+
targetDir: testDir,
|
|
253
|
+
vcsFolderName,
|
|
254
|
+
quiet: true,
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
const subDir = path.join(testDir, 'src', 'utils');
|
|
258
|
+
await fs.mkdir(subDir, { recursive: true });
|
|
259
|
+
await fs.writeFile(path.join(subDir, 'math.js'), 'export const add = (a, b) => a + b;', 'utf8');
|
|
260
|
+
|
|
261
|
+
const addRes = await executeAddCmd({
|
|
262
|
+
paths: ['math.js'],
|
|
263
|
+
targetDir: subDir,
|
|
264
|
+
vcsFolderName,
|
|
265
|
+
quiet: true,
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
iReckon(lc, addRes.stagedPaths).includes('src/utils/math.js');
|
|
269
|
+
} finally {
|
|
270
|
+
await fs.rm(testDir, { recursive: true, force: true });
|
|
271
|
+
}
|
|
272
|
+
});
|
|
246
273
|
});
|
package/src/cli/vcs-cli-main.mts
CHANGED
|
@@ -17,6 +17,8 @@ import { executeCommitCmd } from './commands/commit-cmd.mjs';
|
|
|
17
17
|
import { executeLogCmd } from './commands/log-cmd.mjs';
|
|
18
18
|
import { executeBranchCmd } from './commands/branch-cmd.mjs';
|
|
19
19
|
import { executeCheckoutCmd } from './commands/checkout-cmd.mjs';
|
|
20
|
+
import { executeResetCmd } from './commands/reset-cmd.mjs';
|
|
21
|
+
import { executeRestoreCmd } from './commands/restore-cmd.mjs';
|
|
20
22
|
import { AUTO_GENERATED_VERSION } from '../AUTO-GENERATED-version.mjs';
|
|
21
23
|
import { GLOBAL_LOG_A_LOT } from '../vcs-gib-constants.mjs';
|
|
22
24
|
|
|
@@ -42,13 +44,18 @@ Commands:
|
|
|
42
44
|
log Show commit logs
|
|
43
45
|
branch [name] List or create branches
|
|
44
46
|
checkout <branch> Switch to a specified branch and project worktree
|
|
47
|
+
reset [path...] Unstage specified files from index (-a, --all for all)
|
|
48
|
+
restore [path...] Restore working tree files or unstage (--staged)
|
|
45
49
|
|
|
46
50
|
Flags:
|
|
47
51
|
-h, --help Show help information
|
|
48
52
|
-v, --version Show version information
|
|
49
53
|
-m <message> Commit message
|
|
50
54
|
-b <branch> Target branch name
|
|
51
|
-
-a, --all Stage all tracked/untracked files (for add)
|
|
55
|
+
-a, --all Stage all tracked/untracked files (for add/reset)
|
|
56
|
+
-s, --staged Unstage specified files from index (for restore)
|
|
57
|
+
-w, --worktree Revert physical working tree files (for restore)
|
|
58
|
+
-y, --yes Automatically confirm interactive prompts
|
|
52
59
|
-f, --force Force operation execution
|
|
53
60
|
`;
|
|
54
61
|
console.log(helpText.trim());
|
|
@@ -64,7 +71,7 @@ export async function main({
|
|
|
64
71
|
const lc = `${lcFile}[${main.name}]`;
|
|
65
72
|
try {
|
|
66
73
|
if (logalot) {
|
|
67
|
-
console.log(`${lc} starting... (I:
|
|
74
|
+
console.log(`${lc} starting... (I: 4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e)`);
|
|
68
75
|
}
|
|
69
76
|
|
|
70
77
|
const parsed = parseVcsArgs(argv);
|
|
@@ -113,6 +120,25 @@ export async function main({
|
|
|
113
120
|
await executeCheckoutCmd({ branchName });
|
|
114
121
|
break;
|
|
115
122
|
}
|
|
123
|
+
case VCS_SUBCOMMANDS.RESET: {
|
|
124
|
+
await executeResetCmd({
|
|
125
|
+
paths: parsed.positionals,
|
|
126
|
+
all: parsed.flags.all,
|
|
127
|
+
yes: parsed.flags.yes,
|
|
128
|
+
force: parsed.flags.force,
|
|
129
|
+
});
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case VCS_SUBCOMMANDS.RESTORE: {
|
|
133
|
+
await executeRestoreCmd({
|
|
134
|
+
paths: parsed.positionals,
|
|
135
|
+
staged: parsed.flags.staged,
|
|
136
|
+
worktree: parsed.flags.worktree,
|
|
137
|
+
yes: parsed.flags.yes,
|
|
138
|
+
force: parsed.flags.force,
|
|
139
|
+
});
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
116
142
|
case VCS_SUBCOMMANDS.VERSION: {
|
|
117
143
|
showVersion();
|
|
118
144
|
break;
|
|
@@ -126,7 +152,7 @@ export async function main({
|
|
|
126
152
|
|
|
127
153
|
return 0;
|
|
128
154
|
} catch (error) {
|
|
129
|
-
console.error(`Error: ${extractErrorMsg(error)} (E:
|
|
155
|
+
console.error(`Error: ${extractErrorMsg(error)} (E: 8a9b0c1d2e3f4a5b6c7d8e9f0a1b2c3d)`);
|
|
130
156
|
return 1;
|
|
131
157
|
} finally {
|
|
132
158
|
if (logalot) {
|
|
@@ -1,17 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module branch-graph-helper
|
|
3
3
|
*
|
|
4
|
-
* Helper for
|
|
4
|
+
* Helper for populating branch spaces via SyncSagaCoordinator.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
7
|
+
import { clone, extractErrorMsg } from '@ibgib/helper-gib/dist/helpers/utils-helper.mjs';
|
|
8
8
|
import { IbGib_V1 } from '@ibgib/ts-gib/dist/V1/types.mjs';
|
|
9
|
-
import { getDependencyGraph } from '@ibgib/core-gib/dist/common/other/graph-helper.mjs';
|
|
10
9
|
import { IbGibSpaceAny } from '@ibgib/core-gib/dist/witness/space/space-base-v1.mjs';
|
|
11
|
-
import { putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs';
|
|
12
10
|
import { MetaspaceService } from '@ibgib/core-gib/dist/witness/space/metaspace/metaspace-types.mjs';
|
|
11
|
+
import { SyncSagaCoordinator } from '@ibgib/core-gib/dist/sync/sync-saga-coordinator.mjs';
|
|
12
|
+
import { SyncPeerInnerspace_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-v1.mjs';
|
|
13
|
+
import { SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1 } from '@ibgib/core-gib/dist/sync/sync-peer/sync-peer-innerspace/sync-peer-innerspace-constants.mjs';
|
|
13
14
|
|
|
14
15
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
16
|
+
import { B2tFSBranchIbGib_V1 } from './branch-types.mjs';
|
|
17
|
+
import { createB2tFSBranchIbGib } from './branch-helper.mjs';
|
|
15
18
|
|
|
16
19
|
const lcFile = `[branch-graph-helper]`;
|
|
17
20
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
@@ -20,44 +23,88 @@ export interface PopulateBranchSpaceFromGraphOpts {
|
|
|
20
23
|
sourceSpace: IbGibSpaceAny;
|
|
21
24
|
targetBranchSpace: IbGibSpaceAny;
|
|
22
25
|
rootItemIbGib: IbGib_V1;
|
|
26
|
+
branchName?: string;
|
|
23
27
|
metaspace?: MetaspaceService;
|
|
24
28
|
}
|
|
25
29
|
|
|
30
|
+
export interface PopulateBranchSpaceFromGraphResult {
|
|
31
|
+
syncedCount: number;
|
|
32
|
+
branchIbGib?: B2tFSBranchIbGib_V1;
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
/**
|
|
27
|
-
*
|
|
36
|
+
* Executes SSM (Space - Sync - Metadata) for branch space initialization:
|
|
37
|
+
* 1. Space: Target branch space targetBranchSpace (b2s_<branchName>).
|
|
38
|
+
* 2. Sync: Syncs rootItemIbGib from sourceSpace -> targetBranchSpace using SyncSagaCoordinator.
|
|
39
|
+
* 3. Metadata: Creates B2tFSBranchIbGib_V1 metadata node in targetBranchSpace pointing to rootItem.
|
|
28
40
|
*/
|
|
29
41
|
export async function populateBranchSpaceFromGraph({
|
|
30
42
|
sourceSpace,
|
|
31
43
|
targetBranchSpace,
|
|
32
44
|
rootItemIbGib,
|
|
45
|
+
branchName,
|
|
33
46
|
metaspace,
|
|
34
|
-
}: PopulateBranchSpaceFromGraphOpts): Promise<
|
|
47
|
+
}: PopulateBranchSpaceFromGraphOpts): Promise<PopulateBranchSpaceFromGraphResult> {
|
|
35
48
|
const lc = `${lcFile}[${populateBranchSpaceFromGraph.name}]`;
|
|
36
49
|
try {
|
|
37
50
|
if (logalot) {
|
|
38
51
|
console.log(`${lc} starting... (I: 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d)`);
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
if (!sourceSpace || !targetBranchSpace || !rootItemIbGib) {
|
|
42
|
-
throw new Error(`sourceSpace, targetBranchSpace, and
|
|
54
|
+
if (!sourceSpace || !targetBranchSpace || !rootItemIbGib || !metaspace) {
|
|
55
|
+
throw new Error(`sourceSpace, targetBranchSpace, rootItemIbGib, and metaspace are required (E: 2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e)`);
|
|
43
56
|
}
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
58
|
+
// 1. Space: targetBranchSpace provided/instantiated
|
|
59
|
+
|
|
60
|
+
// 2. Sync: Execute SyncSagaCoordinator space-to-space sync (sourceSpace -> targetBranchSpace)
|
|
61
|
+
const senderCoordinator = new SyncSagaCoordinator();
|
|
62
|
+
const receiverCoordinator = new SyncSagaCoordinator();
|
|
63
|
+
|
|
64
|
+
const peer = new SyncPeerInnerspace_V1(clone(SYNC_PEER_INNERSPACE_DEFAULT_DATA_V1));
|
|
65
|
+
await peer.initialized;
|
|
66
|
+
await peer.initializeOpts({
|
|
67
|
+
localMetaspace: metaspace,
|
|
68
|
+
localSpace: sourceSpace,
|
|
69
|
+
receiverSpace: targetBranchSpace,
|
|
70
|
+
receiverCoordinator,
|
|
71
|
+
receiverMetaspace: metaspace,
|
|
49
72
|
});
|
|
50
73
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
74
|
+
const resSync = await senderCoordinator.sync({
|
|
75
|
+
peer,
|
|
76
|
+
localSpace: sourceSpace,
|
|
77
|
+
metaspace,
|
|
78
|
+
domainIbGibs: [rootItemIbGib],
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await resSync.done;
|
|
82
|
+
|
|
83
|
+
if (logalot) {
|
|
84
|
+
console.log(`${lc} SyncSagaCoordinator sync initiated for ${rootItemIbGib.ib} (I: 3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f)`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const syncedCount = 1;
|
|
88
|
+
|
|
89
|
+
// 3. Metadata: Create B2tFSBranchIbGib_V1 metadata node in targetBranchSpace pointing to rootItem
|
|
90
|
+
let branchIbGib: B2tFSBranchIbGib_V1 | undefined;
|
|
91
|
+
if (branchName && metaspace) {
|
|
92
|
+
branchIbGib = await createB2tFSBranchIbGib({
|
|
93
|
+
branchName,
|
|
94
|
+
rootItem: rootItemIbGib as any,
|
|
95
|
+
space: targetBranchSpace,
|
|
96
|
+
metaspace,
|
|
97
|
+
});
|
|
56
98
|
}
|
|
57
99
|
|
|
58
100
|
if (logalot) {
|
|
59
|
-
console.log(`${lc} Populated target branch space
|
|
101
|
+
console.log(`${lc} Populated target branch space via SyncSagaCoordinator (I: 4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f)`);
|
|
60
102
|
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
syncedCount,
|
|
106
|
+
branchIbGib,
|
|
107
|
+
};
|
|
61
108
|
} catch (error) {
|
|
62
109
|
console.error(`${lc} ${extractErrorMsg(error)} (E: 4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a)`);
|
|
63
110
|
throw error;
|
|
@@ -67,3 +114,4 @@ export async function populateBranchSpaceFromGraph({
|
|
|
67
114
|
}
|
|
68
115
|
}
|
|
69
116
|
}
|
|
117
|
+
|
|
@@ -14,6 +14,12 @@ import { putInSpace } from '@ibgib/core-gib/dist/witness/space/space-helper.mjs'
|
|
|
14
14
|
import { GLOBAL_LOG_A_LOT } from '../../vcs-gib-constants.mjs';
|
|
15
15
|
import { getB2tFSBranchSpaceName } from './branch-helper.mjs';
|
|
16
16
|
|
|
17
|
+
export {
|
|
18
|
+
populateBranchSpaceFromGraph,
|
|
19
|
+
PopulateBranchSpaceFromGraphOpts,
|
|
20
|
+
PopulateBranchSpaceFromGraphResult,
|
|
21
|
+
} from './branch-graph-helper.mjs';
|
|
22
|
+
|
|
17
23
|
const lcFile = `[branch-space-helper]`;
|
|
18
24
|
const logalot = GLOBAL_LOG_A_LOT;
|
|
19
25
|
|
|
@@ -136,20 +136,26 @@ await respecfully(lc, `Branch Space & Graph Helper Respecs`, async () => {
|
|
|
136
136
|
branchName: 'main',
|
|
137
137
|
});
|
|
138
138
|
|
|
139
|
-
// Populate target branch space from source localSpace graph
|
|
140
|
-
await populateBranchSpaceFromGraph({
|
|
139
|
+
// Populate target branch space from source localSpace graph and create branch metadata node (SSM)
|
|
140
|
+
const popResult = await populateBranchSpaceFromGraph({
|
|
141
141
|
sourceSpace: localSpace,
|
|
142
142
|
targetBranchSpace,
|
|
143
143
|
rootItemIbGib: rootItem,
|
|
144
|
+
branchName: 'main',
|
|
144
145
|
metaspace,
|
|
145
146
|
});
|
|
146
147
|
|
|
148
|
+
iReckon(lc, popResult.syncedCount > 0).isGonnaBeTrue();
|
|
149
|
+
iReckon(lc, popResult.branchIbGib).isGonnaBeTruthy();
|
|
150
|
+
iReckon(lc, popResult.branchIbGib?.data?.name).willEqual('main');
|
|
151
|
+
iReckon(lc, popResult.branchIbGib?.rel8ns?.b2tfs_item).includes(rootAddr);
|
|
152
|
+
|
|
147
153
|
// Verify items exist in targetBranchSpace
|
|
148
|
-
const rootGet = await getFromSpace({ space: targetBranchSpace,
|
|
149
|
-
iReckon(lc, rootGet).
|
|
154
|
+
const rootGet = await getFromSpace({ space: targetBranchSpace, addrs: [rootAddr] });
|
|
155
|
+
iReckon(lc, rootGet?.ibGibs?.length === 1).isGonnaBeTrue();
|
|
150
156
|
|
|
151
|
-
const childGet = await getFromSpace({ space: targetBranchSpace,
|
|
152
|
-
iReckon(lc, childGet).
|
|
157
|
+
const childGet = await getFromSpace({ space: targetBranchSpace, addrs: [childAddr] });
|
|
158
|
+
iReckon(lc, childGet?.ibGibs?.length === 1).isGonnaBeTrue();
|
|
153
159
|
} finally {
|
|
154
160
|
await fs.rm(testDir, { recursive: true, force: true });
|
|
155
161
|
}
|