git-stack-cli 2.9.3 → 2.9.4
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/dist/js/index.js +76 -76
- package/package.json +1 -1
- package/src/app/DebugOutput.tsx +40 -0
- package/src/app/GithubApiError.tsx +31 -28
- package/src/app/ManualRebase.tsx +6 -1
- package/src/app/Output.tsx +8 -17
- package/src/app/Store.tsx +30 -71
- package/src/app/SyncGithub.tsx +31 -30
- package/src/app/VerboseDebugInfo.tsx +8 -0
- package/src/core/CommitMetadata.ts +88 -58
- package/src/core/cli.ts +12 -5
- package/src/core/git.ts +1 -1
- package/src/core/github.tsx +135 -46
- package/src/index.tsx +0 -5
- package/src/types/global.d.ts +1 -0
- package/src/app/LogTimestamp.tsx +0 -8
package/package.json
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import * as Ink from "ink-cjs";
|
|
4
|
+
import { DateTime } from "luxon";
|
|
5
|
+
|
|
6
|
+
type Props = {
|
|
7
|
+
node: React.ReactNode;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export function DebugOutput(props: Props) {
|
|
11
|
+
const { stdout } = Ink.useStdout();
|
|
12
|
+
const available_width = stdout.columns;
|
|
13
|
+
|
|
14
|
+
const timestamp = DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
|
15
|
+
const content_width = available_width - timestamp.length - 2;
|
|
16
|
+
|
|
17
|
+
const content = (function () {
|
|
18
|
+
switch (typeof props.node) {
|
|
19
|
+
case "boolean":
|
|
20
|
+
case "number":
|
|
21
|
+
case "string": {
|
|
22
|
+
return <Ink.Text dimColor>{String(props.node)}</Ink.Text>;
|
|
23
|
+
}
|
|
24
|
+
default:
|
|
25
|
+
return props.node;
|
|
26
|
+
}
|
|
27
|
+
})();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Ink.Box flexDirection="column">
|
|
31
|
+
<Ink.Box flexDirection="row" gap={1} width={available_width}>
|
|
32
|
+
<Ink.Box width={timestamp.length} flexDirection="column">
|
|
33
|
+
<Ink.Text dimColor>{timestamp}</Ink.Text>
|
|
34
|
+
</Ink.Box>
|
|
35
|
+
|
|
36
|
+
<Ink.Box width={content_width}>{content}</Ink.Box>
|
|
37
|
+
</Ink.Box>
|
|
38
|
+
</Ink.Box>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -4,6 +4,7 @@ import * as Ink from "ink-cjs";
|
|
|
4
4
|
|
|
5
5
|
import { Await } from "~/app/Await";
|
|
6
6
|
import { Brackets } from "~/app/Brackets";
|
|
7
|
+
import { FormatText } from "~/app/FormatText";
|
|
7
8
|
import { Parens } from "~/app/Parens";
|
|
8
9
|
import { Store } from "~/app/Store";
|
|
9
10
|
import { cli } from "~/core/cli";
|
|
@@ -51,34 +52,36 @@ async function run(props: Props) {
|
|
|
51
52
|
}
|
|
52
53
|
|
|
53
54
|
actions.output(
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
55
|
+
<FormatText
|
|
56
|
+
message="Github {graphql} API rate limit {ratio} will reset at {reset_time} {time_until}"
|
|
57
|
+
values={{
|
|
58
|
+
graphql: <Brackets>graphql</Brackets>,
|
|
59
|
+
ratio: (
|
|
60
|
+
<Brackets>
|
|
61
|
+
<FormatText message="{used}/{limit}" values={{ used, limit }} />
|
|
62
|
+
</Brackets>
|
|
63
|
+
),
|
|
64
|
+
reset_time: (
|
|
65
|
+
<Ink.Text bold color={colors.yellow}>
|
|
66
|
+
{reset_time}
|
|
67
|
+
</Ink.Text>
|
|
68
|
+
),
|
|
69
|
+
time_until: (
|
|
70
|
+
<Parens>
|
|
71
|
+
<FormatText
|
|
72
|
+
message="in {time_until}"
|
|
73
|
+
values={{
|
|
74
|
+
time_until: (
|
|
75
|
+
<Ink.Text bold color={colors.yellow}>
|
|
76
|
+
{time_until}
|
|
77
|
+
</Ink.Text>
|
|
78
|
+
),
|
|
79
|
+
}}
|
|
80
|
+
/>
|
|
81
|
+
</Parens>
|
|
82
|
+
),
|
|
83
|
+
}}
|
|
84
|
+
/>,
|
|
82
85
|
);
|
|
83
86
|
|
|
84
87
|
if (props.exit) {
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -47,6 +47,11 @@ async function run() {
|
|
|
47
47
|
// get latest merge_base relative to local master
|
|
48
48
|
const merge_base = (await cli(`git merge-base HEAD ${master_branch}`)).stdout;
|
|
49
49
|
|
|
50
|
+
// ensure merge_base is updated
|
|
51
|
+
actions.set((state) => {
|
|
52
|
+
state.merge_base = merge_base;
|
|
53
|
+
});
|
|
54
|
+
|
|
50
55
|
// immediately paint all commit to preserve selected commit ranges
|
|
51
56
|
let commit_range = await CommitMetadata.range(commit_map);
|
|
52
57
|
|
|
@@ -116,7 +121,7 @@ async function run() {
|
|
|
116
121
|
if (argv.sync) {
|
|
117
122
|
actions.set((state) => {
|
|
118
123
|
state.step = "sync-github";
|
|
119
|
-
state.sync_github = { commit_range
|
|
124
|
+
state.sync_github = { commit_range };
|
|
120
125
|
});
|
|
121
126
|
} else {
|
|
122
127
|
actions.set((state) => {
|
package/src/app/Output.tsx
CHANGED
|
@@ -2,35 +2,26 @@ import * as React from "react";
|
|
|
2
2
|
|
|
3
3
|
import * as Ink from "ink-cjs";
|
|
4
4
|
|
|
5
|
+
import { DebugOutput } from "~/app/DebugOutput";
|
|
5
6
|
import { Store } from "~/app/Store";
|
|
6
7
|
|
|
7
8
|
export function Output() {
|
|
8
9
|
const output = Store.useState((state) => state.output);
|
|
9
10
|
const pending_output = Store.useState((state) => state.pending_output);
|
|
10
|
-
const pending_output_items = Object.values(pending_output);
|
|
11
11
|
|
|
12
12
|
return (
|
|
13
13
|
<React.Fragment>
|
|
14
14
|
<Ink.Static items={output}>
|
|
15
|
-
{(
|
|
16
|
-
|
|
15
|
+
{(entry) => {
|
|
16
|
+
const [id, node] = entry;
|
|
17
|
+
return <Ink.Box key={id}>{node}</Ink.Box>;
|
|
17
18
|
}}
|
|
18
19
|
</Ink.Static>
|
|
19
20
|
|
|
20
|
-
{
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
{node_list.map((text, j) => {
|
|
25
|
-
return (
|
|
26
|
-
<React.Fragment key={j}>
|
|
27
|
-
<Ink.Text>{text}</Ink.Text>
|
|
28
|
-
</React.Fragment>
|
|
29
|
-
);
|
|
30
|
-
})}
|
|
31
|
-
</Ink.Text>
|
|
32
|
-
</Ink.Box>
|
|
33
|
-
);
|
|
21
|
+
{Object.entries(pending_output).map((entry) => {
|
|
22
|
+
const [id, content_list] = entry;
|
|
23
|
+
const content = content_list.join("");
|
|
24
|
+
return <DebugOutput key={id} node={content} />;
|
|
34
25
|
})}
|
|
35
26
|
</React.Fragment>
|
|
36
27
|
);
|
package/src/app/Store.tsx
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
|
|
3
5
|
import * as Ink from "ink-cjs";
|
|
4
6
|
import { createStore, useStore } from "zustand";
|
|
5
7
|
import { immer } from "zustand/middleware/immer";
|
|
6
8
|
|
|
9
|
+
import { DebugOutput } from "~/app/DebugOutput";
|
|
7
10
|
import { Exit } from "~/app/Exit";
|
|
8
|
-
import { LogTimestamp } from "~/app/LogTimestamp";
|
|
9
11
|
import { colors } from "~/core/colors";
|
|
10
12
|
import { pretty_json } from "~/core/pretty_json";
|
|
11
13
|
|
|
@@ -21,13 +23,10 @@ type CommitMap = Parameters<typeof CommitMetadata.range>[0];
|
|
|
21
23
|
type MutateOutputArgs = {
|
|
22
24
|
node: React.ReactNode;
|
|
23
25
|
id?: string;
|
|
24
|
-
debug?: boolean;
|
|
25
|
-
withoutTimestamp?: boolean;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
type SyncGithubState = {
|
|
29
29
|
commit_range: CommitMetadata.CommitRange;
|
|
30
|
-
rebase_group_index: number;
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
// async function that returns exit code
|
|
@@ -73,12 +72,12 @@ export type State = {
|
|
|
73
72
|
| "sync-github"
|
|
74
73
|
| "post-rebase-status";
|
|
75
74
|
|
|
76
|
-
output: Array<React.ReactNode>;
|
|
77
|
-
pending_output: Record<string, Array<
|
|
75
|
+
output: Array<[string, React.ReactNode]>;
|
|
76
|
+
pending_output: Record<string, Array<string>>;
|
|
78
77
|
|
|
79
78
|
// cache
|
|
80
79
|
pr: { [branch: string]: PullRequest };
|
|
81
|
-
|
|
80
|
+
cache_gh_cli_by_branch: { [branch: string]: { [command: string]: string } };
|
|
82
81
|
|
|
83
82
|
actions: {
|
|
84
83
|
exit(code: number, args?: ExitArgs): void;
|
|
@@ -88,7 +87,9 @@ export type State = {
|
|
|
88
87
|
json(value: pretty_json.JSONValue): void;
|
|
89
88
|
error(error: unknown): void;
|
|
90
89
|
output(node: React.ReactNode): void;
|
|
91
|
-
debug(node: React.ReactNode
|
|
90
|
+
debug(node: React.ReactNode): void;
|
|
91
|
+
debug_pending(id: string, content: string): void;
|
|
92
|
+
debug_pending_end(id: string): void;
|
|
92
93
|
|
|
93
94
|
isDebug(): boolean;
|
|
94
95
|
|
|
@@ -100,8 +101,6 @@ export type State = {
|
|
|
100
101
|
|
|
101
102
|
mutate: {
|
|
102
103
|
output(state: State, args: MutateOutputArgs): void;
|
|
103
|
-
pending_output(state: State, args: MutateOutputArgs): void;
|
|
104
|
-
end_pending_output(state: State, id: string): void;
|
|
105
104
|
};
|
|
106
105
|
|
|
107
106
|
select: {
|
|
@@ -139,7 +138,7 @@ const BaseStore = createStore<State>()(
|
|
|
139
138
|
pending_output: {},
|
|
140
139
|
|
|
141
140
|
pr: {},
|
|
142
|
-
|
|
141
|
+
cache_gh_cli_by_branch: {},
|
|
143
142
|
|
|
144
143
|
actions: {
|
|
145
144
|
exit(code, args) {
|
|
@@ -211,20 +210,32 @@ const BaseStore = createStore<State>()(
|
|
|
211
210
|
});
|
|
212
211
|
},
|
|
213
212
|
|
|
214
|
-
debug(node
|
|
213
|
+
debug(node) {
|
|
215
214
|
if (get().actions.isDebug()) {
|
|
216
|
-
|
|
215
|
+
set((state) => {
|
|
216
|
+
state.mutate.output(state, { node: <DebugOutput node={node} /> });
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
},
|
|
217
220
|
|
|
221
|
+
debug_pending(id, content) {
|
|
222
|
+
if (get().actions.isDebug()) {
|
|
218
223
|
set((state) => {
|
|
219
|
-
if (id) {
|
|
220
|
-
state.
|
|
221
|
-
} else {
|
|
222
|
-
state.mutate.output(state, { node, debug });
|
|
224
|
+
if (!state.pending_output[id]) {
|
|
225
|
+
state.pending_output[id] = [];
|
|
223
226
|
}
|
|
227
|
+
|
|
228
|
+
state.pending_output[id].push(content);
|
|
224
229
|
});
|
|
225
230
|
}
|
|
226
231
|
},
|
|
227
232
|
|
|
233
|
+
debug_pending_end(id) {
|
|
234
|
+
set((state) => {
|
|
235
|
+
delete state.pending_output[id];
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
|
|
228
239
|
isDebug() {
|
|
229
240
|
const state = get();
|
|
230
241
|
return state.select.debug(state);
|
|
@@ -251,38 +262,8 @@ const BaseStore = createStore<State>()(
|
|
|
251
262
|
|
|
252
263
|
mutate: {
|
|
253
264
|
output(state, args) {
|
|
254
|
-
const
|
|
255
|
-
state.output.push(
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
pending_output(state, args) {
|
|
259
|
-
const { id } = args;
|
|
260
|
-
|
|
261
|
-
if (!id) {
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
// set `withoutTimestamp` to skip <LogTimestamp> for all subsequent pending outputs
|
|
266
|
-
// we only want to timestamp for the first part (when we initialize the [])
|
|
267
|
-
// if we have many incremental outputs on the same line we do not want multiple timestamps
|
|
268
|
-
//
|
|
269
|
-
// await Promise.all([
|
|
270
|
-
// cli(`for i in $(seq 1 5); do echo $i; sleep 1; done`),
|
|
271
|
-
// cli(`for i in $(seq 5 1); do printf "$i "; sleep 1; done; echo`),
|
|
272
|
-
// ]);
|
|
273
|
-
//
|
|
274
|
-
let withoutTimestamp = true;
|
|
275
|
-
if (!state.pending_output[id]) {
|
|
276
|
-
withoutTimestamp = false;
|
|
277
|
-
state.pending_output[id] = [];
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
const renderOutput = renderOutputArgs({ ...args, withoutTimestamp });
|
|
281
|
-
state.pending_output[id].push(renderOutput);
|
|
282
|
-
},
|
|
283
|
-
|
|
284
|
-
end_pending_output(state, id) {
|
|
285
|
-
delete state.pending_output[id];
|
|
265
|
+
const id = crypto.randomUUID();
|
|
266
|
+
state.output.push([id, args.node]);
|
|
286
267
|
},
|
|
287
268
|
},
|
|
288
269
|
|
|
@@ -294,28 +275,6 @@ const BaseStore = createStore<State>()(
|
|
|
294
275
|
})),
|
|
295
276
|
);
|
|
296
277
|
|
|
297
|
-
function renderOutputArgs(args: MutateOutputArgs) {
|
|
298
|
-
let output = args.node;
|
|
299
|
-
|
|
300
|
-
switch (typeof args.node) {
|
|
301
|
-
case "boolean":
|
|
302
|
-
case "number":
|
|
303
|
-
case "string":
|
|
304
|
-
output = <Ink.Text dimColor={args.debug}>{String(args.node)}</Ink.Text>;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (args.debug) {
|
|
308
|
-
return (
|
|
309
|
-
<React.Fragment>
|
|
310
|
-
{args.withoutTimestamp ? null : <LogTimestamp />}
|
|
311
|
-
{output}
|
|
312
|
-
</React.Fragment>
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
return output;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
278
|
function useState<R>(selector: (state: State) => R): R {
|
|
320
279
|
return useStore(BaseStore, selector);
|
|
321
280
|
}
|
package/src/app/SyncGithub.tsx
CHANGED
|
@@ -26,18 +26,18 @@ async function run() {
|
|
|
26
26
|
const actions = state.actions;
|
|
27
27
|
const argv = state.argv;
|
|
28
28
|
const branch_name = state.branch_name;
|
|
29
|
+
const merge_base = state.merge_base;
|
|
29
30
|
const commit_map = state.commit_map;
|
|
30
31
|
const master_branch = state.master_branch;
|
|
31
|
-
const
|
|
32
|
+
const repo_path = state.repo_path;
|
|
32
33
|
const sync_github = state.sync_github;
|
|
33
34
|
|
|
34
35
|
invariant(branch_name, "branch_name must exist");
|
|
35
36
|
invariant(commit_map, "commit_map must exist");
|
|
36
|
-
invariant(
|
|
37
|
+
invariant(repo_path, "repo_path must exist");
|
|
37
38
|
invariant(sync_github, "sync_github must exist");
|
|
38
39
|
|
|
39
40
|
const commit_range = sync_github.commit_range;
|
|
40
|
-
const rebase_group_index = sync_github.rebase_group_index;
|
|
41
41
|
|
|
42
42
|
let DEFAULT_PR_BODY = "";
|
|
43
43
|
if (state.pr_template_body) {
|
|
@@ -46,9 +46,6 @@ async function run() {
|
|
|
46
46
|
|
|
47
47
|
const push_group_list = get_push_group_list();
|
|
48
48
|
|
|
49
|
-
// console.debug({ push_group_list });
|
|
50
|
-
// throw new Error("STOP");
|
|
51
|
-
|
|
52
49
|
// for all push targets in push_group_list
|
|
53
50
|
// things that can be done in parallel are grouped by numbers
|
|
54
51
|
//
|
|
@@ -165,7 +162,7 @@ async function run() {
|
|
|
165
162
|
for (const group of push_group_list) {
|
|
166
163
|
if (group.pr) {
|
|
167
164
|
delete state.pr[group.pr.headRefName];
|
|
168
|
-
delete state.
|
|
165
|
+
delete state.cache_gh_cli_by_branch[group.pr.headRefName];
|
|
169
166
|
}
|
|
170
167
|
}
|
|
171
168
|
});
|
|
@@ -192,24 +189,14 @@ async function run() {
|
|
|
192
189
|
}
|
|
193
190
|
|
|
194
191
|
function get_push_group_list() {
|
|
195
|
-
// start from HEAD and work backward to rebase_group_index
|
|
196
192
|
const push_group_list = [];
|
|
197
193
|
|
|
198
|
-
for (let
|
|
199
|
-
const index = commit_range.group_list.length - 1 - i;
|
|
200
|
-
|
|
201
|
-
// do not go past rebase_group_index
|
|
202
|
-
if (index < rebase_group_index) {
|
|
203
|
-
break;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const group = commit_range.group_list[index];
|
|
207
|
-
|
|
194
|
+
for (let group of commit_range.group_list) {
|
|
208
195
|
// skip the unassigned commits group
|
|
209
196
|
if (group.id === commit_range.UNASSIGNED) continue;
|
|
210
197
|
|
|
211
|
-
// if not --force, skip non-dirty
|
|
212
|
-
if (
|
|
198
|
+
// if not --force, skip non-dirty groups
|
|
199
|
+
if (!group.dirty && !argv.force) continue;
|
|
213
200
|
|
|
214
201
|
push_group_list.unshift(group);
|
|
215
202
|
}
|
|
@@ -240,7 +227,7 @@ async function run() {
|
|
|
240
227
|
// Unable to sync.
|
|
241
228
|
// ```
|
|
242
229
|
//
|
|
243
|
-
if (!
|
|
230
|
+
if (!is_pr_master_base(group)) {
|
|
244
231
|
await github.pr_edit({
|
|
245
232
|
branch: group.id,
|
|
246
233
|
base: master_branch,
|
|
@@ -258,7 +245,15 @@ async function run() {
|
|
|
258
245
|
invariant(group.base, "group.base must exist");
|
|
259
246
|
|
|
260
247
|
if (group.pr) {
|
|
261
|
-
|
|
248
|
+
// there are two scenarios where we should restore the base after push
|
|
249
|
+
// 1. if we aren't master base and pr is master base we should fix it
|
|
250
|
+
const base_mismatch = !group.master_base && is_pr_master_base(group);
|
|
251
|
+
// 2. if group pr was not master before the push we set it to master before pushing
|
|
252
|
+
// now we need to restore it back to how it was before the before_push
|
|
253
|
+
const was_modified_before_push = !is_pr_master_base(group);
|
|
254
|
+
|
|
255
|
+
const needs_base_fix = base_mismatch || was_modified_before_push;
|
|
256
|
+
if (needs_base_fix) {
|
|
262
257
|
// ensure base matches pr in github
|
|
263
258
|
await github.pr_edit({ branch: group.id, base: group.base });
|
|
264
259
|
}
|
|
@@ -313,25 +308,31 @@ async function run() {
|
|
|
313
308
|
}
|
|
314
309
|
}
|
|
315
310
|
|
|
316
|
-
function
|
|
311
|
+
function is_pr_master_base(group: CommitMetadataGroup) {
|
|
317
312
|
if (!group.pr) {
|
|
318
313
|
return false;
|
|
319
314
|
}
|
|
320
315
|
|
|
321
|
-
return
|
|
316
|
+
return `origin/${group.pr.baseRefName}` === master_branch;
|
|
322
317
|
}
|
|
323
318
|
|
|
324
319
|
async function push_master_group(group: CommitMetadataGroup) {
|
|
325
|
-
invariant(
|
|
320
|
+
invariant(repo_path, "repo_path must exist");
|
|
326
321
|
|
|
327
|
-
const
|
|
328
|
-
|
|
322
|
+
const worktree_path = path.join(
|
|
323
|
+
process.env.HOME,
|
|
324
|
+
".cache",
|
|
325
|
+
"git-stack",
|
|
326
|
+
"worktrees",
|
|
327
|
+
repo_path,
|
|
328
|
+
"push_master_group",
|
|
329
|
+
);
|
|
329
330
|
|
|
330
331
|
// ensure worktree for pushing master groups
|
|
331
332
|
if (!(await safe_exists(worktree_path))) {
|
|
332
333
|
actions.output(
|
|
333
334
|
<Ink.Text color={colors.white}>
|
|
334
|
-
Creating <Ink.Text color={colors.yellow}>{
|
|
335
|
+
Creating <Ink.Text color={colors.yellow}>{worktree_path}</Ink.Text>
|
|
335
336
|
</Ink.Text>,
|
|
336
337
|
);
|
|
337
338
|
actions.output(
|
|
@@ -342,13 +343,13 @@ async function run() {
|
|
|
342
343
|
|
|
343
344
|
// ensure worktree is clean + on the right base before applying commits
|
|
344
345
|
// - abort any in-progress cherry-pick/rebase
|
|
345
|
-
// - drop local changes/untracked files
|
|
346
|
+
// - drop local changes/untracked files to fresh state
|
|
346
347
|
// - reset to the desired base
|
|
347
348
|
await cli(`git -C ${worktree_path} cherry-pick --abort`, { ignoreExitCode: true });
|
|
348
349
|
await cli(`git -C ${worktree_path} rebase --abort`, { ignoreExitCode: true });
|
|
349
350
|
await cli(`git -C ${worktree_path} merge --abort`, { ignoreExitCode: true });
|
|
350
351
|
await cli(`git -C ${worktree_path} checkout -f ${master_branch}`);
|
|
351
|
-
await cli(`git -C ${worktree_path} reset --hard ${
|
|
352
|
+
await cli(`git -C ${worktree_path} reset --hard ${merge_base}`);
|
|
352
353
|
await cli(`git -C ${worktree_path} clean -fd`);
|
|
353
354
|
|
|
354
355
|
// cherry-pick the group commits onto that base
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
|
|
3
5
|
import * as Ink from "ink-cjs";
|
|
4
6
|
|
|
5
7
|
import { Await } from "~/app/Await";
|
|
6
8
|
import { Store } from "~/app/Store";
|
|
7
9
|
import { cli } from "~/core/cli";
|
|
8
10
|
import { colors } from "~/core/colors";
|
|
11
|
+
import { pretty_json } from "~/core/pretty_json";
|
|
9
12
|
|
|
10
13
|
type Props = {
|
|
11
14
|
children: React.ReactNode;
|
|
@@ -29,6 +32,11 @@ async function run() {
|
|
|
29
32
|
await cli(`echo USER=$USER`);
|
|
30
33
|
await cli(`echo GIT_AUTHOR_NAME=$GIT_AUTHOR_NAME`);
|
|
31
34
|
await cli(`echo GIT_AUTHOR_EMAIL=$GIT_AUTHOR_EMAIL`);
|
|
35
|
+
|
|
36
|
+
const PATH = process.env["PATH"];
|
|
37
|
+
const PATH_LIST = pretty_json(PATH.split(path.delimiter));
|
|
38
|
+
actions.debug(`process.env.PATH ${PATH_LIST}`);
|
|
39
|
+
|
|
32
40
|
await cli(`git config --list --show-origin`);
|
|
33
41
|
} catch (err) {
|
|
34
42
|
actions.error("Unable to log verbose debug information.");
|