|
1 | | -import { changeLabel, filterRootChanges, JJ } from "@array/core"; |
2 | | -import { cyan, dim, formatError, formatSuccess } from "../utils/output"; |
| 1 | +import { changeLabel } from "@array/core"; |
| 2 | +import { cyan, dim, formatSuccess } from "../utils/output"; |
| 3 | +import { createJJ, findChange, requireArg, unwrap } from "../utils/run"; |
3 | 4 |
|
4 | 5 | export async function checkout(id: string): Promise<void> { |
5 | | - if (!id) { |
6 | | - console.error(formatError("Usage: arr checkout <id>")); |
7 | | - process.exit(1); |
8 | | - } |
9 | | - |
10 | | - const jj = new JJ({ cwd: process.cwd() }); |
| 6 | + requireArg(id, "Usage: arr checkout <id>"); |
| 7 | + const jj = createJJ(); |
11 | 8 |
|
12 | | - // Handle "main" or trunk checkout - creates new empty change on main |
| 9 | + // Handle trunk checkout - creates new empty change on main |
13 | 10 | if (id === "main" || id === "master" || id === "trunk") { |
14 | | - const result = await jj.new({ parents: [id === "trunk" ? "trunk()" : id] }); |
15 | | - if (!result.ok) { |
16 | | - console.error(formatError(result.error.message)); |
17 | | - process.exit(1); |
18 | | - } |
| 11 | + unwrap(await jj.new({ parents: [id === "trunk" ? "trunk()" : id] })); |
19 | 12 | console.log(formatSuccess(`Switched to ${cyan(id)}`)); |
20 | 13 | return; |
21 | 14 | } |
22 | 15 |
|
23 | | - // Search by: description substring OR bookmark/branch name substring (case-insensitive) |
24 | | - const escaped = id.replace(/"/g, '\\"'); |
25 | | - const revset = `description(substring-i:"${escaped}") | bookmarks(substring-i:"${escaped}")`; |
26 | | - |
27 | | - const listResult = await jj.list({ revset }); |
28 | | - if (!listResult.ok) { |
29 | | - console.error(formatError(`No changes matching: ${id}`)); |
30 | | - process.exit(1); |
31 | | - } |
32 | | - |
33 | | - const matches = filterRootChanges(listResult.value); |
34 | | - |
35 | | - if (matches.length === 0) { |
36 | | - console.error(formatError(`No changes matching: ${id}`)); |
37 | | - process.exit(1); |
38 | | - } |
39 | | - |
40 | | - if (matches.length > 1) { |
41 | | - console.log(`Multiple matches for "${id}":\n`); |
42 | | - for (const cs of matches) { |
43 | | - const label = changeLabel(cs.description, cs.changeId); |
44 | | - console.log( |
45 | | - ` ${cyan(label)}: ${cs.description || dim("(no description)")}`, |
46 | | - ); |
47 | | - } |
48 | | - console.log(dim("\nUse a more specific query or the full change ID.")); |
49 | | - process.exit(1); |
50 | | - } |
51 | | - |
52 | | - const changeset = matches[0]; |
53 | | - |
54 | | - const result = await jj.edit(changeset.changeId); |
55 | | - if (!result.ok) { |
56 | | - console.error(formatError(result.error.message)); |
57 | | - process.exit(1); |
58 | | - } |
59 | | - |
60 | | - const label = changeLabel(changeset.description, changeset.changeId); |
61 | | - const desc = changeset.description || dim("(no description)"); |
| 16 | + const change = await findChange(jj, id, { includeBookmarks: true }); |
| 17 | + unwrap(await jj.edit(change.changeId)); |
62 | 18 |
|
63 | | - console.log(formatSuccess(`Switched to ${cyan(label)}: ${desc}`)); |
| 19 | + const label = changeLabel(change.description, change.changeId); |
| 20 | + console.log( |
| 21 | + formatSuccess( |
| 22 | + `Switched to ${cyan(label)}: ${change.description || dim("(no description)")}`, |
| 23 | + ), |
| 24 | + ); |
64 | 25 | } |
0 commit comments