git-stack-cli 1.11.7 → 1.13.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 +11 -1
- package/dist/cjs/index.cjs +204 -203
- package/package.json +1 -1
- package/src/app/AutoUpdate.tsx +5 -3
- package/src/app/CherryPickCheck.tsx +4 -4
- package/src/app/Debug.tsx +12 -9
- package/src/app/DependencyCheck.tsx +0 -6
- package/src/app/ManualRebase.tsx +134 -180
- package/src/app/PreManualRebase.tsx +6 -5
- package/src/app/RebaseCheck.tsx +3 -3
- package/src/command.ts +0 -16
- package/src/commands/Rebase.tsx +2 -15
- package/src/core/GitReviseTodo.test.ts +16 -0
- package/src/core/GitReviseTodo.ts +3 -3
- package/src/core/github.tsx +65 -10
- package/src/core/read_json.ts +3 -3
- package/src/core/safe_exists.ts +10 -0
- package/src/core/safe_rm.ts +10 -0
package/package.json
CHANGED
package/src/app/AutoUpdate.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
@@ -90,7 +90,8 @@ export function AutoUpdate(props: Props) {
|
|
|
90
90
|
throw new Error("Unable to retrieve latest version from npm");
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
const
|
|
93
|
+
const script_path = await fs.realpath(process.argv[1]);
|
|
94
|
+
const script_dir = path.dirname(script_path);
|
|
94
95
|
|
|
95
96
|
// dist/ts/index.js
|
|
96
97
|
const package_json_path = path.join(
|
|
@@ -100,7 +101,8 @@ export function AutoUpdate(props: Props) {
|
|
|
100
101
|
"package.json"
|
|
101
102
|
);
|
|
102
103
|
|
|
103
|
-
|
|
104
|
+
type PackageJson = { version: string };
|
|
105
|
+
const package_json = await read_json<PackageJson>(package_json_path);
|
|
104
106
|
|
|
105
107
|
if (!package_json) {
|
|
106
108
|
// unable to find read package.json, skip auto update
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
|
|
6
5
|
import * as Ink from "ink-cjs";
|
|
@@ -11,6 +10,7 @@ import { Store } from "~/app/Store";
|
|
|
11
10
|
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
12
11
|
import { cli } from "~/core/cli";
|
|
13
12
|
import { colors } from "~/core/colors";
|
|
13
|
+
import { safe_exists } from "~/core/safe_exists";
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
children: React.ReactNode;
|
|
@@ -73,11 +73,11 @@ export function CherryPickCheck(props: Props) {
|
|
|
73
73
|
try {
|
|
74
74
|
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
75
75
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
);
|
|
76
|
+
const cherry_pick_file = path.join(git_dir, "CHERRY_PICK_HEAD");
|
|
77
|
+
const is_cherry_pick = await safe_exists(cherry_pick_file);
|
|
79
78
|
|
|
80
79
|
const status = is_cherry_pick ? "prompt" : "done";
|
|
80
|
+
|
|
81
81
|
patch({ status });
|
|
82
82
|
} catch (err) {
|
|
83
83
|
actions.error("Must be run from within a git repository.");
|
package/src/app/Debug.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
@@ -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 { safe_rm } from "~/core/safe_rm";
|
|
11
12
|
|
|
12
13
|
export function Debug() {
|
|
13
14
|
const actions = Store.useActions();
|
|
@@ -27,20 +28,22 @@ export function Debug() {
|
|
|
27
28
|
);
|
|
28
29
|
|
|
29
30
|
React.useEffect(
|
|
30
|
-
function
|
|
31
|
+
function sync_state_json() {
|
|
31
32
|
if (!argv?.["write-state-json"]) {
|
|
32
33
|
return;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
|
|
36
|
+
sync().catch(actions.error);
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
async function sync() {
|
|
39
|
+
const output_file = path.join(state.cwd, "git-stack-state.json");
|
|
40
|
+
|
|
41
|
+
await safe_rm(output_file);
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
const serialized = json.serialize(state);
|
|
44
|
+
const content = JSON.stringify(serialized, null, 2);
|
|
45
|
+
await fs.writeFile(output_file, content);
|
|
46
|
+
}
|
|
44
47
|
},
|
|
45
48
|
[argv, state]
|
|
46
49
|
);
|
|
@@ -163,12 +163,6 @@ function CheckGithubCliAuth(props: Props) {
|
|
|
163
163
|
|
|
164
164
|
function CheckGitRevise(props: Props) {
|
|
165
165
|
const actions = Store.useActions();
|
|
166
|
-
const argv = Store.useState((state) => state.argv);
|
|
167
|
-
|
|
168
|
-
// skip git revise check when `rebase` is not git-revise
|
|
169
|
-
if (argv?.["rebase"] !== "git-revise") {
|
|
170
|
-
return props.children;
|
|
171
|
-
}
|
|
172
166
|
|
|
173
167
|
return (
|
|
174
168
|
<Await
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -10,7 +10,6 @@ import { FormatText } from "~/app/FormatText";
|
|
|
10
10
|
import { Store } from "~/app/Store";
|
|
11
11
|
import * as CommitMetadata from "~/core/CommitMetadata";
|
|
12
12
|
import { GitReviseTodo } from "~/core/GitReviseTodo";
|
|
13
|
-
import * as Metadata from "~/core/Metadata";
|
|
14
13
|
import * as StackSummaryTable from "~/core/StackSummaryTable";
|
|
15
14
|
import { cli } from "~/core/cli";
|
|
16
15
|
import { colors } from "~/core/colors";
|
|
@@ -107,37 +106,6 @@ async function run() {
|
|
|
107
106
|
process.chdir(repo_root);
|
|
108
107
|
await cli(`pwd`);
|
|
109
108
|
|
|
110
|
-
if (argv["rebase"] === "git-revise") {
|
|
111
|
-
await rebase_git_revise();
|
|
112
|
-
} else {
|
|
113
|
-
await rebase_cherry_pick();
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
// after all commits have been cherry-picked and amended
|
|
117
|
-
// move the branch pointer to the newly created temporary branch
|
|
118
|
-
// now we are in locally in sync with github and on the original branch
|
|
119
|
-
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
120
|
-
|
|
121
|
-
restore_git();
|
|
122
|
-
|
|
123
|
-
actions.set((state) => {
|
|
124
|
-
state.step = "post-rebase-status";
|
|
125
|
-
});
|
|
126
|
-
} catch (err) {
|
|
127
|
-
actions.error("Unable to rebase.");
|
|
128
|
-
|
|
129
|
-
if (err instanceof Error) {
|
|
130
|
-
if (actions.isDebug()) {
|
|
131
|
-
actions.error(err.message);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
handle_exit();
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
async function rebase_git_revise() {
|
|
139
|
-
actions.debug(`rebase_git_revise`);
|
|
140
|
-
|
|
141
109
|
actions.output(
|
|
142
110
|
<Ink.Text color={colors.yellow} wrap="truncate-end">
|
|
143
111
|
Rebasing…
|
|
@@ -153,11 +121,33 @@ async function run() {
|
|
|
153
121
|
commit_range,
|
|
154
122
|
});
|
|
155
123
|
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
124
|
+
// after all commits have been modified move the pointer
|
|
125
|
+
// of original branch to the newly created temporary branch
|
|
126
|
+
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
127
|
+
|
|
128
|
+
if (argv.sync) {
|
|
129
|
+
await sync_github();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
restore_git();
|
|
133
|
+
|
|
134
|
+
actions.set((state) => {
|
|
135
|
+
state.step = "post-rebase-status";
|
|
136
|
+
});
|
|
137
|
+
} catch (err) {
|
|
138
|
+
if (err instanceof Error) {
|
|
139
|
+
actions.error(err.message);
|
|
159
140
|
}
|
|
160
141
|
|
|
142
|
+
actions.error("Unable to rebase.");
|
|
143
|
+
if (!argv.verbose) {
|
|
144
|
+
actions.error("Try again with `--verbose` to see more information.");
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
handle_exit();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
async function sync_github() {
|
|
161
151
|
// in order to sync we walk from rebase_group_index to HEAD
|
|
162
152
|
// checking out each group and syncing to github
|
|
163
153
|
|
|
@@ -186,128 +176,140 @@ async function run() {
|
|
|
186
176
|
push_group_list.unshift({ group, lookback_index });
|
|
187
177
|
}
|
|
188
178
|
|
|
189
|
-
|
|
179
|
+
actions.output(
|
|
180
|
+
<FormatText
|
|
181
|
+
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
182
|
+
message="Syncing {group_list}…"
|
|
183
|
+
values={{
|
|
184
|
+
group_list: (
|
|
185
|
+
<React.Fragment>
|
|
186
|
+
{push_group_list.map((push_group) => {
|
|
187
|
+
const group = push_group.group;
|
|
188
|
+
|
|
189
|
+
return (
|
|
190
|
+
<Brackets key={group.id}>
|
|
191
|
+
{group.pr?.title || group.title || group.id}
|
|
192
|
+
</Brackets>
|
|
193
|
+
);
|
|
194
|
+
})}
|
|
195
|
+
</React.Fragment>
|
|
196
|
+
),
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
);
|
|
190
200
|
|
|
191
|
-
//
|
|
201
|
+
// for all push targets in push_group_list
|
|
202
|
+
// things that can be done in parallel are grouped by numbers
|
|
203
|
+
//
|
|
204
|
+
// -----------------------------------
|
|
205
|
+
// 1 (before_push) temp mark draft
|
|
206
|
+
// --------------------------------------
|
|
207
|
+
// 2 push simultaneously to github
|
|
208
|
+
// --------------------------------------
|
|
209
|
+
// 2 create PR / edit PR
|
|
210
|
+
// 2 (after_push) undo temp mark draft
|
|
211
|
+
// --------------------------------------
|
|
212
|
+
|
|
213
|
+
const before_push_tasks = [];
|
|
192
214
|
for (const push_group of push_group_list) {
|
|
193
|
-
|
|
215
|
+
before_push_tasks.push(before_push(push_group));
|
|
216
|
+
}
|
|
194
217
|
|
|
195
|
-
|
|
196
|
-
await cli(`git checkout -b ${group.id}`);
|
|
218
|
+
await Promise.all(before_push_tasks);
|
|
197
219
|
|
|
198
|
-
|
|
199
|
-
|
|
220
|
+
const push_target_list = push_group_list.map((push_group) => {
|
|
221
|
+
return `HEAD~${push_group.lookback_index}:${push_group.group.id}`;
|
|
222
|
+
});
|
|
200
223
|
|
|
201
|
-
|
|
224
|
+
const push_target_args = push_target_list.join(" ");
|
|
202
225
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
226
|
+
const git_push_command = [`git push -f origin ${push_target_args}`];
|
|
227
|
+
|
|
228
|
+
if (argv.verify === false) {
|
|
229
|
+
git_push_command.push("--no-verify");
|
|
206
230
|
}
|
|
207
231
|
|
|
208
|
-
|
|
209
|
-
await update_pr_tables(pr_url_list);
|
|
210
|
-
}
|
|
232
|
+
await cli(git_push_command);
|
|
211
233
|
|
|
212
|
-
|
|
213
|
-
actions.debug("rebase_cherry_pick");
|
|
234
|
+
const pr_url_list = commit_range.group_list.map(get_group_url);
|
|
214
235
|
|
|
215
|
-
|
|
216
|
-
|
|
236
|
+
const after_push_tasks = [];
|
|
237
|
+
for (const push_group of push_group_list) {
|
|
238
|
+
const group = push_group.group;
|
|
239
|
+
after_push_tasks.push(after_push({ group, pr_url_list }));
|
|
240
|
+
}
|
|
217
241
|
|
|
218
|
-
|
|
242
|
+
await Promise.all(after_push_tasks);
|
|
219
243
|
|
|
220
|
-
|
|
244
|
+
// finally, ensure all prs have the updated stack table from updated pr_url_list
|
|
245
|
+
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
221
246
|
const group = commit_range.group_list[i];
|
|
222
247
|
|
|
223
|
-
|
|
248
|
+
// use the updated pr_url_list to get the actual selected_url
|
|
249
|
+
const selected_url = pr_url_list[i];
|
|
224
250
|
|
|
225
|
-
|
|
226
|
-
<FormatText
|
|
227
|
-
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
228
|
-
message="Rebasing {group}…"
|
|
229
|
-
values={{
|
|
230
|
-
group: (
|
|
231
|
-
<Brackets>{group.pr?.title || group.title || group.id}</Brackets>
|
|
232
|
-
),
|
|
233
|
-
}}
|
|
234
|
-
/>
|
|
235
|
-
);
|
|
236
|
-
|
|
237
|
-
// cherry-pick and amend commits one by one
|
|
238
|
-
for (const commit of group.commits) {
|
|
239
|
-
// ensure clean base to avoid conflicts when applying patch
|
|
240
|
-
await cli(`git clean -fd`);
|
|
241
|
-
|
|
242
|
-
// create, apply and cleanup patch
|
|
243
|
-
await cli(`git format-patch -1 ${commit.sha} --stdout > ${PATCH_FILE}`);
|
|
244
|
-
await cli(`git apply ${PATCH_FILE}`);
|
|
245
|
-
await cli(`rm ${PATCH_FILE}`);
|
|
246
|
-
|
|
247
|
-
// add all changes to stage
|
|
248
|
-
await cli(`git add --all`);
|
|
249
|
-
|
|
250
|
-
const metadata = { id: group.id, title: group.title };
|
|
251
|
-
const new_message = Metadata.write(commit.full_message, metadata);
|
|
252
|
-
const git_commit_comand = [`git commit -m "${new_message}"`];
|
|
253
|
-
|
|
254
|
-
if (argv.verify === false) {
|
|
255
|
-
git_commit_comand.push("--no-verify");
|
|
256
|
-
}
|
|
251
|
+
invariant(group.base, "group.base must exist");
|
|
257
252
|
|
|
258
|
-
|
|
259
|
-
}
|
|
253
|
+
const body = group.pr?.body || DEFAULT_PR_BODY;
|
|
260
254
|
|
|
261
|
-
|
|
262
|
-
|
|
255
|
+
const update_body = StackSummaryTable.write({
|
|
256
|
+
body,
|
|
257
|
+
pr_url_list,
|
|
258
|
+
selected_url,
|
|
259
|
+
});
|
|
263
260
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
261
|
+
if (update_body === body) {
|
|
262
|
+
actions.debug(`Skipping body update for ${selected_url}`);
|
|
263
|
+
} else {
|
|
264
|
+
actions.debug(`Update body for ${selected_url}`);
|
|
267
265
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
return;
|
|
266
|
+
await github.pr_edit({
|
|
267
|
+
branch: group.id,
|
|
268
|
+
base: group.base,
|
|
269
|
+
body: update_body,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
275
272
|
}
|
|
273
|
+
}
|
|
276
274
|
|
|
277
|
-
|
|
275
|
+
async function before_push(args: { group: CommitMetadataGroup }) {
|
|
276
|
+
const { group } = args;
|
|
278
277
|
|
|
279
278
|
invariant(group.base, "group.base must exist");
|
|
280
279
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
message="Syncing {group}…"
|
|
285
|
-
values={{
|
|
286
|
-
group: (
|
|
287
|
-
<Brackets>{group.pr?.title || group.title || group.id}</Brackets>
|
|
288
|
-
),
|
|
289
|
-
}}
|
|
290
|
-
/>
|
|
291
|
-
);
|
|
280
|
+
// we may temporarily mark PR as a draft before editing it
|
|
281
|
+
// if it is not already a draft PR, to avoid notification spam
|
|
282
|
+
let is_temp_draft = !group.pr?.isDraft;
|
|
292
283
|
|
|
293
284
|
// before pushing reset base to master temporarily
|
|
294
285
|
// avoid accidentally pointing to orphaned parent commit
|
|
295
286
|
// should hopefully fix issues where a PR includes a bunch of commits after pushing
|
|
296
287
|
if (group.pr) {
|
|
288
|
+
if (!group.pr.isDraft) {
|
|
289
|
+
is_temp_draft = true;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (is_temp_draft) {
|
|
293
|
+
await github.pr_draft({
|
|
294
|
+
branch: group.id,
|
|
295
|
+
draft: true,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
|
|
297
299
|
await github.pr_edit({
|
|
298
300
|
branch: group.id,
|
|
299
301
|
base: master_branch,
|
|
300
302
|
});
|
|
301
303
|
}
|
|
304
|
+
}
|
|
302
305
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
}
|
|
306
|
+
async function after_push(args: {
|
|
307
|
+
group: CommitMetadataGroup;
|
|
308
|
+
pr_url_list: Array<string>;
|
|
309
|
+
}) {
|
|
310
|
+
const { group, pr_url_list } = args;
|
|
309
311
|
|
|
310
|
-
|
|
312
|
+
invariant(group.base, "group.base must exist");
|
|
311
313
|
|
|
312
314
|
const selected_url = get_group_url(group);
|
|
313
315
|
|
|
@@ -322,15 +324,19 @@ async function run() {
|
|
|
322
324
|
selected_url,
|
|
323
325
|
}),
|
|
324
326
|
});
|
|
325
|
-
} else {
|
|
326
|
-
if (!args.skip_checkout) {
|
|
327
|
-
// delete local group branch if leftover
|
|
328
|
-
await cli(`git branch -D ${group.id}`, { ignoreExitCode: true });
|
|
329
327
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
328
|
+
// we may temporarily mark PR as a draft before editing it
|
|
329
|
+
// if it is not already a draft PR, to avoid notification spam
|
|
330
|
+
let is_temp_draft = !group.pr?.isDraft;
|
|
333
331
|
|
|
332
|
+
if (is_temp_draft) {
|
|
333
|
+
// mark pr as ready for review again
|
|
334
|
+
await github.pr_draft({
|
|
335
|
+
branch: group.id,
|
|
336
|
+
draft: false,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
} else {
|
|
334
340
|
// create pr in github
|
|
335
341
|
const pr_url = await github.pr_create({
|
|
336
342
|
branch: group.id,
|
|
@@ -351,46 +357,6 @@ async function run() {
|
|
|
351
357
|
pr_url_list[i] = pr_url;
|
|
352
358
|
}
|
|
353
359
|
}
|
|
354
|
-
|
|
355
|
-
// move back to temp branch
|
|
356
|
-
if (!args.skip_checkout) {
|
|
357
|
-
await cli(`git checkout ${temp_branch_name}`);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
async function update_pr_tables(pr_url_list: Array<string>) {
|
|
363
|
-
if (!argv.sync) {
|
|
364
|
-
return;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
368
|
-
const group = commit_range.group_list[i];
|
|
369
|
-
|
|
370
|
-
// use the updated pr_url_list to get the actual selected_url
|
|
371
|
-
const selected_url = pr_url_list[i];
|
|
372
|
-
|
|
373
|
-
invariant(group.base, "group.base must exist");
|
|
374
|
-
|
|
375
|
-
const body = group.pr?.body || DEFAULT_PR_BODY;
|
|
376
|
-
|
|
377
|
-
const update_body = StackSummaryTable.write({
|
|
378
|
-
body,
|
|
379
|
-
pr_url_list,
|
|
380
|
-
selected_url,
|
|
381
|
-
});
|
|
382
|
-
|
|
383
|
-
if (update_body === body) {
|
|
384
|
-
actions.debug(`Skipping body update for ${selected_url}`);
|
|
385
|
-
} else {
|
|
386
|
-
actions.debug(`Update body for ${selected_url}`);
|
|
387
|
-
|
|
388
|
-
await github.pr_edit({
|
|
389
|
-
branch: group.id,
|
|
390
|
-
base: group.base,
|
|
391
|
-
body: update_body,
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
360
|
}
|
|
395
361
|
}
|
|
396
362
|
|
|
@@ -401,9 +367,6 @@ async function run() {
|
|
|
401
367
|
// all children processes receive the SIGINT signal
|
|
402
368
|
const spawn_options = { ignoreExitCode: true };
|
|
403
369
|
|
|
404
|
-
// always clean up any patch files
|
|
405
|
-
cli.sync(`rm ${PATCH_FILE}`, spawn_options);
|
|
406
|
-
|
|
407
370
|
// always hard reset and clean to allow subsequent checkout
|
|
408
371
|
// if there are files checkout will fail and cascade fail subsequent commands
|
|
409
372
|
cli.sync(`git reset --hard`, spawn_options);
|
|
@@ -415,13 +378,6 @@ async function run() {
|
|
|
415
378
|
// ...and cleanup temporary branch
|
|
416
379
|
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
417
380
|
|
|
418
|
-
if (commit_range) {
|
|
419
|
-
// ...and cleanup pr group branches
|
|
420
|
-
for (const group of commit_range.group_list) {
|
|
421
|
-
cli.sync(`git branch -D ${group.id}`, spawn_options);
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
|
|
425
381
|
// restore back to original dir
|
|
426
382
|
if (fs.existsSync(cwd)) {
|
|
427
383
|
process.chdir(cwd);
|
|
@@ -450,5 +406,3 @@ async function run() {
|
|
|
450
406
|
|
|
451
407
|
type CommitMetadataGroup = CommitMetadata.CommitRange["group_list"][number];
|
|
452
408
|
const get_group_url = (group: CommitMetadataGroup) => group.pr?.url || group.id;
|
|
453
|
-
|
|
454
|
-
const PATCH_FILE = "git-stack-cli-patch.patch";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import * as Ink from "ink-cjs";
|
|
@@ -11,6 +11,7 @@ import { FormatText } from "~/app/FormatText";
|
|
|
11
11
|
import { Store } from "~/app/Store";
|
|
12
12
|
import { colors } from "~/core/colors";
|
|
13
13
|
import { invariant } from "~/core/invariant";
|
|
14
|
+
import { safe_exists } from "~/core/safe_exists";
|
|
14
15
|
|
|
15
16
|
export function PreManualRebase() {
|
|
16
17
|
return <Await fallback={null} function={run} />;
|
|
@@ -40,8 +41,8 @@ async function run() {
|
|
|
40
41
|
for (const key of PR_TEMPLATE_KEY_LIST) {
|
|
41
42
|
const pr_template_fn = PR_TEMPLATE[key as keyof typeof PR_TEMPLATE];
|
|
42
43
|
|
|
43
|
-
if (
|
|
44
|
-
pr_template_body = fs.
|
|
44
|
+
if (await safe_exists(pr_template_fn(repo_root))) {
|
|
45
|
+
pr_template_body = await fs.readFile(pr_template_fn(repo_root), "utf-8");
|
|
45
46
|
|
|
46
47
|
actions.output(
|
|
47
48
|
<FormatText
|
|
@@ -59,8 +60,8 @@ async function run() {
|
|
|
59
60
|
|
|
60
61
|
// ./.github/PULL_REQUEST_TEMPLATE/*.md
|
|
61
62
|
let pr_templates: Array<string> = [];
|
|
62
|
-
if (
|
|
63
|
-
pr_templates = fs.
|
|
63
|
+
if (await safe_exists(PR_TEMPLATE.TemplateDir(repo_root))) {
|
|
64
|
+
pr_templates = await fs.readdir(PR_TEMPLATE.TemplateDir(repo_root));
|
|
64
65
|
}
|
|
65
66
|
|
|
66
67
|
// check if repo has multiple pr templates
|
package/src/app/RebaseCheck.tsx
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import fs from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
5
4
|
|
|
6
5
|
import * as Ink from "ink-cjs";
|
|
@@ -11,6 +10,7 @@ import { Store } from "~/app/Store";
|
|
|
11
10
|
import { YesNoPrompt } from "~/app/YesNoPrompt";
|
|
12
11
|
import { cli } from "~/core/cli";
|
|
13
12
|
import { colors } from "~/core/colors";
|
|
13
|
+
import { safe_exists } from "~/core/safe_exists";
|
|
14
14
|
|
|
15
15
|
type Props = {
|
|
16
16
|
children: React.ReactNode;
|
|
@@ -74,8 +74,8 @@ export function RebaseCheck(props: Props) {
|
|
|
74
74
|
const git_dir = (await cli(`git rev-parse --absolute-git-dir`)).stdout;
|
|
75
75
|
|
|
76
76
|
let is_rebase = false;
|
|
77
|
-
is_rebase ||=
|
|
78
|
-
is_rebase ||=
|
|
77
|
+
is_rebase ||= await safe_exists(path.join(git_dir, "rebase-apply"));
|
|
78
|
+
is_rebase ||= await safe_exists(path.join(git_dir, "rebase-merge"));
|
|
79
79
|
|
|
80
80
|
const status = is_rebase ? "prompt" : "done";
|
|
81
81
|
patch({ status });
|
package/src/command.ts
CHANGED
|
@@ -52,11 +52,6 @@ export async function command() {
|
|
|
52
52
|
);
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const Rebase = Object.freeze({
|
|
56
|
-
"git-revise": "git-revise",
|
|
57
|
-
"cherry-pick": "cherry-pick",
|
|
58
|
-
});
|
|
59
|
-
|
|
60
55
|
const GlobalOptions = {
|
|
61
56
|
verbose: {
|
|
62
57
|
type: "boolean",
|
|
@@ -95,17 +90,6 @@ const DefaultOptions = {
|
|
|
95
90
|
"Run git hooks such as pre-commit and pre-push, disable with --no-verify",
|
|
96
91
|
},
|
|
97
92
|
|
|
98
|
-
"rebase": {
|
|
99
|
-
type: "string",
|
|
100
|
-
choices: [Rebase["git-revise"], Rebase["cherry-pick"]],
|
|
101
|
-
default: Rebase["git-revise"],
|
|
102
|
-
description: [
|
|
103
|
-
"Strategy used for syncing branches",
|
|
104
|
-
`${Rebase["git-revise"]}: perform faster in-memory rebase`,
|
|
105
|
-
`${Rebase["cherry-pick"]}: use disk and incrementally rebase each commit`,
|
|
106
|
-
].join(" | "),
|
|
107
|
-
},
|
|
108
|
-
|
|
109
93
|
"update": {
|
|
110
94
|
type: "boolean",
|
|
111
95
|
alias: ["u", "upgrade"],
|
package/src/commands/Rebase.tsx
CHANGED
|
@@ -111,9 +111,8 @@ Rebase.run = async function run() {
|
|
|
111
111
|
await cli(`git cherry-pick --keep-redundant-commits ${sha_list}`);
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
// after all commits have been cherry-picked
|
|
115
|
-
//
|
|
116
|
-
// now we are locally in sync with github and on the original branch
|
|
114
|
+
// after all commits have been cherry-picked move the pointer
|
|
115
|
+
// of original branch to the newly created temporary branch
|
|
117
116
|
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
118
117
|
|
|
119
118
|
restore_git();
|
|
@@ -154,9 +153,6 @@ Rebase.run = async function run() {
|
|
|
154
153
|
// all children processes receive the SIGINT signal
|
|
155
154
|
const spawn_options = { ignoreExitCode: true };
|
|
156
155
|
|
|
157
|
-
// always clean up any patch files
|
|
158
|
-
cli.sync(`rm ${PATCH_FILE}`, spawn_options);
|
|
159
|
-
|
|
160
156
|
// always hard reset and clean to allow subsequent checkout
|
|
161
157
|
// if there are files checkout will fail and cascade fail subsequent commands
|
|
162
158
|
cli.sync(`git reset --hard`, spawn_options);
|
|
@@ -168,13 +164,6 @@ Rebase.run = async function run() {
|
|
|
168
164
|
// ...and cleanup temporary branch
|
|
169
165
|
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
170
166
|
|
|
171
|
-
if (commit_range) {
|
|
172
|
-
// ...and cleanup pr group branches
|
|
173
|
-
for (const group of commit_range.group_list) {
|
|
174
|
-
cli.sync(`git branch -D ${group.id}`, spawn_options);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
167
|
// restore back to original dir
|
|
179
168
|
if (fs.existsSync(cwd)) {
|
|
180
169
|
process.chdir(cwd);
|
|
@@ -200,5 +189,3 @@ Rebase.run = async function run() {
|
|
|
200
189
|
actions.exit(6);
|
|
201
190
|
}
|
|
202
191
|
};
|
|
203
|
-
|
|
204
|
-
const PATCH_FILE = "git-stack-cli-patch.patch";
|