git-stack-cli 1.13.2 → 1.15.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 +13 -0
- package/dist/cjs/index.cjs +228 -135
- package/package.json +1 -1
- package/src/app/App.tsx +3 -0
- package/src/app/Debug.tsx +2 -1
- package/src/app/DirtyCheck.tsx +37 -26
- package/src/app/Exit.tsx +45 -8
- package/src/app/HandleCtrlCSigint.tsx +47 -0
- package/src/app/ManualRebase.tsx +12 -30
- package/src/app/SelectCommitRanges.tsx +14 -1
- package/src/app/Store.tsx +24 -2
- package/src/app/SyncGithub.tsx +12 -30
- package/src/command.ts +11 -5
- package/src/commands/Fixup.tsx +2 -2
- package/src/commands/Rebase.tsx +12 -30
- package/src/core/GitReviseTodo.ts +4 -0
- package/src/core/github.tsx +30 -8
- package/src/core/pretty_json.ts +12 -0
- package/src/index.tsx +20 -5
- package/src/types/global.d.ts +1 -0
package/package.json
CHANGED
package/src/app/App.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { DetectInitialPR } from "~/app/DetectInitialPR";
|
|
|
8
8
|
import { DirtyCheck } from "~/app/DirtyCheck";
|
|
9
9
|
import { GatherMetadata } from "~/app/GatherMetadata";
|
|
10
10
|
import { GithubApiError } from "~/app/GithubApiError";
|
|
11
|
+
import { HandleCtrlCSigint } from "~/app/HandleCtrlCSigint";
|
|
11
12
|
import { LocalCommitStatus } from "~/app/LocalCommitStatus";
|
|
12
13
|
import { Main } from "~/app/Main";
|
|
13
14
|
import { Output } from "~/app/Output";
|
|
@@ -65,6 +66,8 @@ export function App() {
|
|
|
65
66
|
</DependencyCheck>
|
|
66
67
|
</VerboseDebugInfo>
|
|
67
68
|
</AutoUpdate>
|
|
69
|
+
|
|
70
|
+
<HandleCtrlCSigint />
|
|
68
71
|
</Providers>
|
|
69
72
|
);
|
|
70
73
|
}
|
package/src/app/Debug.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import * as Ink from "ink-cjs";
|
|
|
8
8
|
import { Store } from "~/app/Store";
|
|
9
9
|
import { colors } from "~/core/colors";
|
|
10
10
|
import * as json from "~/core/json";
|
|
11
|
+
import { pretty_json } from "~/core/pretty_json";
|
|
11
12
|
import { safe_rm } from "~/core/safe_rm";
|
|
12
13
|
|
|
13
14
|
export function Debug() {
|
|
@@ -41,7 +42,7 @@ export function Debug() {
|
|
|
41
42
|
await safe_rm(output_file);
|
|
42
43
|
|
|
43
44
|
const serialized = json.serialize(state);
|
|
44
|
-
const content =
|
|
45
|
+
const content = pretty_json(serialized);
|
|
45
46
|
await fs.writeFile(output_file, content);
|
|
46
47
|
}
|
|
47
48
|
},
|
package/src/app/DirtyCheck.tsx
CHANGED
|
@@ -15,7 +15,7 @@ type Props = {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
type State = {
|
|
18
|
-
status: "init" | "prompt" | "done";
|
|
18
|
+
status: "init" | "prompt" | "stash" | "done";
|
|
19
19
|
};
|
|
20
20
|
|
|
21
21
|
function reducer(state: State, patch: Partial<State>) {
|
|
@@ -35,34 +35,42 @@ export function DirtyCheck(props: Props) {
|
|
|
35
35
|
|
|
36
36
|
case "prompt":
|
|
37
37
|
return (
|
|
38
|
-
<
|
|
39
|
-
|
|
40
|
-
<Ink.
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
38
|
+
<Ink.Box flexDirection="column">
|
|
39
|
+
<FormatText
|
|
40
|
+
wrapper={<Ink.Text color={colors.yellow} />}
|
|
41
|
+
message="⚠️ Uncommitted changes detected. {git_stack} needs a clean working tree."
|
|
42
|
+
values={{
|
|
43
|
+
git: <Command>git</Command>,
|
|
44
|
+
git_stack: <Command>git stack</Command>,
|
|
45
|
+
}}
|
|
46
|
+
/>
|
|
47
|
+
|
|
48
|
+
<YesNoPrompt
|
|
49
|
+
message={
|
|
49
50
|
<FormatText
|
|
50
51
|
wrapper={<Ink.Text color={colors.yellow} />}
|
|
51
|
-
message="
|
|
52
|
+
message="{git_stash} changes to proceed?"
|
|
52
53
|
values={{
|
|
53
|
-
|
|
54
|
-
git_stack: <Command>git stack</Command>,
|
|
54
|
+
git_stash: <Command>git stash</Command>,
|
|
55
55
|
}}
|
|
56
56
|
/>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
57
|
+
}
|
|
58
|
+
onYes={async () => {
|
|
59
|
+
await cli("git stash --include-untracked");
|
|
60
|
+
|
|
61
|
+
actions.output(<Ink.Text>📦 Changes saved to stash</Ink.Text>);
|
|
62
|
+
|
|
63
|
+
actions.set((state) => {
|
|
64
|
+
state.is_dirty_check_stash = true;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
patch({ status: "done" });
|
|
68
|
+
}}
|
|
69
|
+
onNo={async () => {
|
|
70
|
+
actions.exit(0);
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
</Ink.Box>
|
|
66
74
|
);
|
|
67
75
|
|
|
68
76
|
default:
|
|
@@ -84,8 +92,11 @@ export function DirtyCheck(props: Props) {
|
|
|
84
92
|
try {
|
|
85
93
|
const git_dirty = (await cli(`git status --porcelain`)).stdout;
|
|
86
94
|
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
if (!git_dirty) {
|
|
96
|
+
patch({ status: "done" });
|
|
97
|
+
} else {
|
|
98
|
+
patch({ status: "prompt" });
|
|
99
|
+
}
|
|
89
100
|
} catch (err) {
|
|
90
101
|
actions.error("Must be run from within a git repository.");
|
|
91
102
|
|
package/src/app/Exit.tsx
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
+
import * as Ink from "ink-cjs";
|
|
4
|
+
|
|
3
5
|
import { Store } from "~/app/Store";
|
|
6
|
+
import { cli } from "~/core/cli";
|
|
7
|
+
import { colors } from "~/core/colors";
|
|
8
|
+
import { sleep } from "~/core/sleep";
|
|
4
9
|
|
|
5
10
|
type Props = {
|
|
6
11
|
clear: boolean;
|
|
@@ -8,17 +13,49 @@ type Props = {
|
|
|
8
13
|
};
|
|
9
14
|
|
|
10
15
|
export function Exit(props: Props) {
|
|
11
|
-
const actions = Store.useActions();
|
|
12
|
-
|
|
13
16
|
React.useEffect(() => {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
+
// immediately handle exit on mount
|
|
18
|
+
handle_exit().catch((err) => {
|
|
19
|
+
// eslint-disable-next-line no-console
|
|
20
|
+
console.error(err);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
async function handle_exit() {
|
|
24
|
+
const state = Store.getState();
|
|
25
|
+
const actions = state.actions;
|
|
26
|
+
|
|
27
|
+
actions.debug(`[Exit] handle_exit ${JSON.stringify(props)}`);
|
|
28
|
+
|
|
29
|
+
let exit_code = props.code;
|
|
17
30
|
|
|
18
|
-
|
|
31
|
+
// run abort_handler if it exists
|
|
32
|
+
if (state.abort_handler) {
|
|
33
|
+
exit_code = await state.abort_handler();
|
|
34
|
+
}
|
|
19
35
|
|
|
20
|
-
|
|
21
|
-
|
|
36
|
+
// restore git stash if necessary
|
|
37
|
+
if (state.is_dirty_check_stash) {
|
|
38
|
+
await cli("git stash pop");
|
|
39
|
+
actions.output(
|
|
40
|
+
<Ink.Text color={colors.green}>
|
|
41
|
+
✅ Changes restored from stash
|
|
42
|
+
</Ink.Text>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ensure output has a chance to render
|
|
47
|
+
await sleep(1);
|
|
48
|
+
|
|
49
|
+
// finally handle the actual app and process exit
|
|
50
|
+
if (props.clear) {
|
|
51
|
+
actions.clear();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
actions.unmount();
|
|
55
|
+
|
|
56
|
+
process.exitCode = exit_code;
|
|
57
|
+
process.exit();
|
|
58
|
+
}
|
|
22
59
|
}, [props.clear, props.code]);
|
|
23
60
|
|
|
24
61
|
return null;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import * as Ink from "ink-cjs";
|
|
4
|
+
|
|
5
|
+
import { FormatText } from "~/app/FormatText";
|
|
6
|
+
import { Store } from "~/app/Store";
|
|
7
|
+
import { colors } from "~/core/colors";
|
|
8
|
+
import { sleep } from "~/core/sleep";
|
|
9
|
+
|
|
10
|
+
export function HandleCtrlCSigint() {
|
|
11
|
+
const actions = Store.useActions();
|
|
12
|
+
|
|
13
|
+
const [exiting, set_exiting] = React.useState(false);
|
|
14
|
+
|
|
15
|
+
Ink.useInput((input, key) => {
|
|
16
|
+
handle_input().catch((err) => {
|
|
17
|
+
// eslint-disable-next-line no-console
|
|
18
|
+
console.error(err);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
async function handle_input() {
|
|
22
|
+
if (input === "c" && key.ctrl) {
|
|
23
|
+
actions.clear();
|
|
24
|
+
|
|
25
|
+
actions.output(
|
|
26
|
+
<Ink.Text color={colors.red}>
|
|
27
|
+
<FormatText message="🚨 Ctrl+C detected" />
|
|
28
|
+
</Ink.Text>
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
set_exiting(true);
|
|
32
|
+
await sleep(1);
|
|
33
|
+
actions.exit(235);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
if (exiting) {
|
|
39
|
+
return (
|
|
40
|
+
<Ink.Text color={colors.red}>
|
|
41
|
+
<FormatText message="🚨 Exiting…" />
|
|
42
|
+
</Ink.Text>
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null;
|
|
47
|
+
}
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -15,35 +15,15 @@ import { invariant } from "~/core/invariant";
|
|
|
15
15
|
import { short_id } from "~/core/short_id";
|
|
16
16
|
|
|
17
17
|
export function ManualRebase() {
|
|
18
|
-
const abort_handler = React.useRef(() => {});
|
|
19
|
-
|
|
20
|
-
React.useEffect(function listen_sigint() {
|
|
21
|
-
process.once("SIGINT", sigint_handler);
|
|
22
|
-
|
|
23
|
-
return function cleanup() {
|
|
24
|
-
process.removeListener("SIGINT", sigint_handler);
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
async function sigint_handler() {
|
|
28
|
-
abort_handler.current();
|
|
29
|
-
}
|
|
30
|
-
}, []);
|
|
31
|
-
|
|
32
18
|
return (
|
|
33
19
|
<Await
|
|
34
20
|
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
35
|
-
function={
|
|
36
|
-
await run({ abort_handler });
|
|
37
|
-
}}
|
|
21
|
+
function={run}
|
|
38
22
|
/>
|
|
39
23
|
);
|
|
40
24
|
}
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
abort_handler: React.MutableRefObject<() => void>;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
async function run(args: Args) {
|
|
26
|
+
async function run() {
|
|
47
27
|
const state = Store.getState();
|
|
48
28
|
const actions = state.actions;
|
|
49
29
|
const argv = state.argv;
|
|
@@ -57,11 +37,12 @@ async function run(args: Args) {
|
|
|
57
37
|
invariant(commit_map, "commit_map must exist");
|
|
58
38
|
invariant(repo_root, "repo_root must exist");
|
|
59
39
|
|
|
60
|
-
//
|
|
61
|
-
|
|
40
|
+
// immediately register abort_handler in case of ctrl+c exit
|
|
41
|
+
actions.register_abort_handler(async function abort_manual_rebase() {
|
|
62
42
|
actions.output(<Ink.Text color={colors.red}>🚨 Abort</Ink.Text>);
|
|
63
|
-
handle_exit(
|
|
64
|
-
|
|
43
|
+
handle_exit();
|
|
44
|
+
return 15;
|
|
45
|
+
});
|
|
65
46
|
|
|
66
47
|
const temp_branch_name = `${branch_name}_${short_id()}`;
|
|
67
48
|
|
|
@@ -137,6 +118,8 @@ async function run(args: Args) {
|
|
|
137
118
|
|
|
138
119
|
restore_git();
|
|
139
120
|
|
|
121
|
+
actions.unregister_abort_handler();
|
|
122
|
+
|
|
140
123
|
if (argv.sync) {
|
|
141
124
|
actions.set((state) => {
|
|
142
125
|
state.step = "sync-github";
|
|
@@ -157,7 +140,8 @@ async function run(args: Args) {
|
|
|
157
140
|
actions.error("Try again with `--verbose` to see more information.");
|
|
158
141
|
}
|
|
159
142
|
|
|
160
|
-
handle_exit(
|
|
143
|
+
handle_exit();
|
|
144
|
+
actions.exit(16);
|
|
161
145
|
}
|
|
162
146
|
|
|
163
147
|
// cleanup git operations if cancelled during manual rebase
|
|
@@ -185,7 +169,7 @@ async function run(args: Args) {
|
|
|
185
169
|
cli.sync(`pwd`, spawn_options);
|
|
186
170
|
}
|
|
187
171
|
|
|
188
|
-
function handle_exit(
|
|
172
|
+
function handle_exit() {
|
|
189
173
|
actions.output(
|
|
190
174
|
<Ink.Text color={colors.yellow}>
|
|
191
175
|
Restoring <Brackets>{branch_name}</Brackets>…
|
|
@@ -199,7 +183,5 @@ async function run(args: Args) {
|
|
|
199
183
|
Restored <Brackets>{branch_name}</Brackets>.
|
|
200
184
|
</Ink.Text>
|
|
201
185
|
);
|
|
202
|
-
|
|
203
|
-
actions.exit(code);
|
|
204
186
|
}
|
|
205
187
|
}
|
|
@@ -387,8 +387,21 @@ function SelectCommitRangesInternal(props: Props) {
|
|
|
387
387
|
</Ink.Box>
|
|
388
388
|
);
|
|
389
389
|
|
|
390
|
+
function get_group_id() {
|
|
391
|
+
let branch_prefix = "";
|
|
392
|
+
|
|
393
|
+
// branch prefix via cli flag or env var
|
|
394
|
+
// cli flag takes precedence since it is more explicit
|
|
395
|
+
if (argv["branch-prefix"]) {
|
|
396
|
+
branch_prefix = argv["branch-prefix"];
|
|
397
|
+
} else if (process.env.GIT_STACK_BRANCH_PREFIX) {
|
|
398
|
+
branch_prefix = process.env.GIT_STACK_BRANCH_PREFIX;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
return `${branch_prefix}${gs_short_id()}`;
|
|
402
|
+
}
|
|
390
403
|
function submit_group_input(title: string) {
|
|
391
|
-
const id =
|
|
404
|
+
const id = get_group_id();
|
|
392
405
|
|
|
393
406
|
actions.output(
|
|
394
407
|
<FormatText
|
package/src/app/Store.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { immer } from "zustand/middleware/immer";
|
|
|
7
7
|
import { Exit } from "~/app/Exit";
|
|
8
8
|
import { LogTimestamp } from "~/app/LogTimestamp";
|
|
9
9
|
import { colors } from "~/core/colors";
|
|
10
|
+
import { pretty_json } from "~/core/pretty_json";
|
|
10
11
|
|
|
11
12
|
import type { Instance as InkInstance } from "ink-cjs";
|
|
12
13
|
import type { Argv } from "~/command";
|
|
@@ -29,6 +30,9 @@ type SyncGithubState = {
|
|
|
29
30
|
rebase_group_index: number;
|
|
30
31
|
};
|
|
31
32
|
|
|
33
|
+
// async function that returns exit code
|
|
34
|
+
type AbortHandler = () => Promise<number>;
|
|
35
|
+
|
|
32
36
|
export type State = {
|
|
33
37
|
// set immediately in `index.tsx` so no `null` scenario
|
|
34
38
|
process_argv: Array<string>;
|
|
@@ -47,6 +51,8 @@ export type State = {
|
|
|
47
51
|
pr_templates: Array<string>;
|
|
48
52
|
pr_template_body: null | string;
|
|
49
53
|
sync_github: null | SyncGithubState;
|
|
54
|
+
is_dirty_check_stash: boolean;
|
|
55
|
+
abort_handler: null | AbortHandler;
|
|
50
56
|
|
|
51
57
|
step:
|
|
52
58
|
| "github-api-error"
|
|
@@ -71,7 +77,7 @@ export type State = {
|
|
|
71
77
|
clear(): void;
|
|
72
78
|
unmount(): void;
|
|
73
79
|
newline(): void;
|
|
74
|
-
json(value:
|
|
80
|
+
json(value: pretty_json.JSONValue): void;
|
|
75
81
|
error(message: string): void;
|
|
76
82
|
output(node: React.ReactNode): void;
|
|
77
83
|
debug(node: React.ReactNode, id?: string): void;
|
|
@@ -79,6 +85,8 @@ export type State = {
|
|
|
79
85
|
isDebug(): boolean;
|
|
80
86
|
|
|
81
87
|
reset_pr(): void;
|
|
88
|
+
register_abort_handler(abort_handler: AbortHandler): void;
|
|
89
|
+
unregister_abort_handler(): void;
|
|
82
90
|
|
|
83
91
|
set(setter: Setter): void;
|
|
84
92
|
};
|
|
@@ -113,6 +121,8 @@ const BaseStore = createStore<State>()(
|
|
|
113
121
|
pr_templates: [],
|
|
114
122
|
pr_template_body: null,
|
|
115
123
|
sync_github: null,
|
|
124
|
+
is_dirty_check_stash: false,
|
|
125
|
+
abort_handler: null,
|
|
116
126
|
|
|
117
127
|
step: "loading",
|
|
118
128
|
|
|
@@ -146,7 +156,7 @@ const BaseStore = createStore<State>()(
|
|
|
146
156
|
|
|
147
157
|
json(value) {
|
|
148
158
|
set((state) => {
|
|
149
|
-
const node =
|
|
159
|
+
const node = pretty_json(value);
|
|
150
160
|
state.mutate.output(state, { node });
|
|
151
161
|
});
|
|
152
162
|
},
|
|
@@ -189,6 +199,18 @@ const BaseStore = createStore<State>()(
|
|
|
189
199
|
});
|
|
190
200
|
},
|
|
191
201
|
|
|
202
|
+
register_abort_handler(abort_handler) {
|
|
203
|
+
set((state) => {
|
|
204
|
+
state.abort_handler = abort_handler;
|
|
205
|
+
});
|
|
206
|
+
},
|
|
207
|
+
|
|
208
|
+
unregister_abort_handler() {
|
|
209
|
+
set((state) => {
|
|
210
|
+
state.abort_handler = null;
|
|
211
|
+
});
|
|
212
|
+
},
|
|
213
|
+
|
|
192
214
|
set(setter) {
|
|
193
215
|
set((state) => {
|
|
194
216
|
setter(state);
|
package/src/app/SyncGithub.tsx
CHANGED
|
@@ -14,35 +14,15 @@ import { invariant } from "~/core/invariant";
|
|
|
14
14
|
import type * as CommitMetadata from "~/core/CommitMetadata";
|
|
15
15
|
|
|
16
16
|
export function SyncGithub() {
|
|
17
|
-
const abort_handler = React.useRef(() => {});
|
|
18
|
-
|
|
19
|
-
React.useEffect(function listen_sigint() {
|
|
20
|
-
process.once("SIGINT", sigint_handler);
|
|
21
|
-
|
|
22
|
-
return function cleanup() {
|
|
23
|
-
process.removeListener("SIGINT", sigint_handler);
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function sigint_handler() {
|
|
27
|
-
abort_handler.current();
|
|
28
|
-
}
|
|
29
|
-
}, []);
|
|
30
|
-
|
|
31
17
|
return (
|
|
32
18
|
<Await
|
|
33
19
|
fallback={<Ink.Text color={colors.yellow}>Syncing…</Ink.Text>}
|
|
34
|
-
function={
|
|
35
|
-
await run({ abort_handler });
|
|
36
|
-
}}
|
|
20
|
+
function={run}
|
|
37
21
|
/>
|
|
38
22
|
);
|
|
39
23
|
}
|
|
40
24
|
|
|
41
|
-
|
|
42
|
-
abort_handler: React.MutableRefObject<() => void>;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
async function run(args: Args) {
|
|
25
|
+
async function run() {
|
|
46
26
|
const state = Store.getState();
|
|
47
27
|
const actions = state.actions;
|
|
48
28
|
const argv = state.argv;
|
|
@@ -60,11 +40,12 @@ async function run(args: Args) {
|
|
|
60
40
|
const commit_range = sync_github.commit_range;
|
|
61
41
|
const rebase_group_index = sync_github.rebase_group_index;
|
|
62
42
|
|
|
63
|
-
//
|
|
64
|
-
|
|
43
|
+
// immediately register abort_handler in case of ctrl+c exit
|
|
44
|
+
actions.register_abort_handler(async function abort_sync_github() {
|
|
65
45
|
actions.output(<Ink.Text color={colors.red}>🚨 Abort</Ink.Text>);
|
|
66
|
-
handle_exit(
|
|
67
|
-
|
|
46
|
+
handle_exit();
|
|
47
|
+
return 17;
|
|
48
|
+
});
|
|
68
49
|
|
|
69
50
|
let DEFAULT_PR_BODY = "";
|
|
70
51
|
if (state.pr_template_body) {
|
|
@@ -151,6 +132,8 @@ async function run(args: Args) {
|
|
|
151
132
|
|
|
152
133
|
await Promise.all(update_pr_body_tasks);
|
|
153
134
|
|
|
135
|
+
actions.unregister_abort_handler();
|
|
136
|
+
|
|
154
137
|
actions.set((state) => {
|
|
155
138
|
state.step = "post-rebase-status";
|
|
156
139
|
});
|
|
@@ -164,7 +147,8 @@ async function run(args: Args) {
|
|
|
164
147
|
actions.error("Try again with `--verbose` to see more information.");
|
|
165
148
|
}
|
|
166
149
|
|
|
167
|
-
|
|
150
|
+
handle_exit();
|
|
151
|
+
actions.exit(18);
|
|
168
152
|
}
|
|
169
153
|
|
|
170
154
|
function get_push_group_list() {
|
|
@@ -305,7 +289,7 @@ async function run(args: Args) {
|
|
|
305
289
|
}
|
|
306
290
|
}
|
|
307
291
|
|
|
308
|
-
function handle_exit(
|
|
292
|
+
function handle_exit() {
|
|
309
293
|
actions.output(
|
|
310
294
|
<Ink.Text color={colors.yellow}>Restoring PR state…</Ink.Text>
|
|
311
295
|
);
|
|
@@ -329,8 +313,6 @@ async function run(args: Args) {
|
|
|
329
313
|
actions.output(
|
|
330
314
|
<Ink.Text color={colors.yellow}>Restored PR state.</Ink.Text>
|
|
331
315
|
);
|
|
332
|
-
|
|
333
|
-
actions.exit(code);
|
|
334
316
|
}
|
|
335
317
|
}
|
|
336
318
|
|
package/src/command.ts
CHANGED
|
@@ -111,11 +111,10 @@ const DefaultOptions = {
|
|
|
111
111
|
description: "Open all PRs as drafts",
|
|
112
112
|
},
|
|
113
113
|
|
|
114
|
-
"
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
description: "Write state to local json file for debugging",
|
|
114
|
+
"branch-prefix": {
|
|
115
|
+
type: "string",
|
|
116
|
+
default: "",
|
|
117
|
+
description: "Prefix for generated branch names, e.g. dev/magus/",
|
|
119
118
|
},
|
|
120
119
|
|
|
121
120
|
"template": {
|
|
@@ -125,6 +124,13 @@ const DefaultOptions = {
|
|
|
125
124
|
"Use automatic Github PR template, e.g. .github/pull_request_template.md, disable with --no-template",
|
|
126
125
|
},
|
|
127
126
|
|
|
127
|
+
"write-state-json": {
|
|
128
|
+
hidden: true,
|
|
129
|
+
type: "boolean",
|
|
130
|
+
default: false,
|
|
131
|
+
description: "Write state to local json file for debugging",
|
|
132
|
+
},
|
|
133
|
+
|
|
128
134
|
"mock-metadata": {
|
|
129
135
|
hidden: true,
|
|
130
136
|
type: "boolean",
|
package/src/commands/Fixup.tsx
CHANGED
|
@@ -97,7 +97,7 @@ async function run() {
|
|
|
97
97
|
if (diff_cmd.code) {
|
|
98
98
|
save_stash = true;
|
|
99
99
|
|
|
100
|
-
await cli("git stash -
|
|
100
|
+
await cli("git stash --include-untracked");
|
|
101
101
|
|
|
102
102
|
actions.output(<Ink.Text>📦 Changes saved to stash</Ink.Text>);
|
|
103
103
|
}
|
|
@@ -118,7 +118,7 @@ async function run() {
|
|
|
118
118
|
await cli("git reset --soft HEAD~1");
|
|
119
119
|
} finally {
|
|
120
120
|
if (save_stash) {
|
|
121
|
-
await cli("git stash pop
|
|
121
|
+
await cli("git stash pop");
|
|
122
122
|
|
|
123
123
|
actions.output(
|
|
124
124
|
<Ink.Text color={colors.green}>✅ Changes restored from stash</Ink.Text>
|
package/src/commands/Rebase.tsx
CHANGED
|
@@ -16,35 +16,15 @@ import { invariant } from "~/core/invariant";
|
|
|
16
16
|
import { short_id } from "~/core/short_id";
|
|
17
17
|
|
|
18
18
|
export function Rebase() {
|
|
19
|
-
const abort_handler = React.useRef(() => {});
|
|
20
|
-
|
|
21
|
-
React.useEffect(function listen_sigint() {
|
|
22
|
-
process.once("SIGINT", sigint_handler);
|
|
23
|
-
|
|
24
|
-
return function cleanup() {
|
|
25
|
-
process.removeListener("SIGINT", sigint_handler);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
function sigint_handler() {
|
|
29
|
-
abort_handler.current();
|
|
30
|
-
}
|
|
31
|
-
}, []);
|
|
32
|
-
|
|
33
19
|
return (
|
|
34
20
|
<Await
|
|
35
21
|
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
36
|
-
function={
|
|
37
|
-
await Rebase.run({ abort_handler });
|
|
38
|
-
}}
|
|
22
|
+
function={Rebase.run}
|
|
39
23
|
/>
|
|
40
24
|
);
|
|
41
25
|
}
|
|
42
26
|
|
|
43
|
-
|
|
44
|
-
abort_handler: React.MutableRefObject<() => void>;
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
Rebase.run = async function run(args: Args) {
|
|
27
|
+
Rebase.run = async function run() {
|
|
48
28
|
const state = Store.getState();
|
|
49
29
|
const actions = state.actions;
|
|
50
30
|
const branch_name = state.branch_name;
|
|
@@ -57,11 +37,12 @@ Rebase.run = async function run(args: Args) {
|
|
|
57
37
|
invariant(commit_range, "commit_range must exist");
|
|
58
38
|
invariant(repo_root, "repo_root must exist");
|
|
59
39
|
|
|
60
|
-
//
|
|
61
|
-
|
|
40
|
+
// immediately register abort_handler in case of ctrl+c exit
|
|
41
|
+
actions.register_abort_handler(async function abort_rebase() {
|
|
62
42
|
actions.output(<Ink.Text color={colors.red}>🚨 Abort</Ink.Text>);
|
|
63
|
-
handle_exit(
|
|
64
|
-
|
|
43
|
+
handle_exit();
|
|
44
|
+
return 19;
|
|
45
|
+
});
|
|
65
46
|
|
|
66
47
|
const temp_branch_name = `${branch_name}_${short_id()}`;
|
|
67
48
|
|
|
@@ -153,6 +134,8 @@ Rebase.run = async function run(args: Args) {
|
|
|
153
134
|
/>
|
|
154
135
|
);
|
|
155
136
|
|
|
137
|
+
actions.unregister_abort_handler();
|
|
138
|
+
|
|
156
139
|
actions.set((state) => {
|
|
157
140
|
state.commit_range = next_commit_range;
|
|
158
141
|
state.step = "status";
|
|
@@ -166,7 +149,8 @@ Rebase.run = async function run(args: Args) {
|
|
|
166
149
|
}
|
|
167
150
|
}
|
|
168
151
|
|
|
169
|
-
handle_exit(
|
|
152
|
+
handle_exit();
|
|
153
|
+
actions.exit(20);
|
|
170
154
|
}
|
|
171
155
|
|
|
172
156
|
// cleanup git operations if cancelled during manual rebase
|
|
@@ -194,7 +178,7 @@ Rebase.run = async function run(args: Args) {
|
|
|
194
178
|
cli.sync(`pwd`, spawn_options);
|
|
195
179
|
}
|
|
196
180
|
|
|
197
|
-
function handle_exit(
|
|
181
|
+
function handle_exit() {
|
|
198
182
|
actions.output(
|
|
199
183
|
<Ink.Text color={colors.yellow}>
|
|
200
184
|
Restoring <Brackets>{branch_name}</Brackets>…
|
|
@@ -208,7 +192,5 @@ Rebase.run = async function run(args: Args) {
|
|
|
208
192
|
Restored <Brackets>{branch_name}</Brackets>.
|
|
209
193
|
</Ink.Text>
|
|
210
194
|
);
|
|
211
|
-
|
|
212
|
-
actions.exit(code);
|
|
213
195
|
}
|
|
214
196
|
};
|