git-stack-cli 1.10.0 → 1.11.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/dist/cjs/index.cjs +25 -11
- package/package.json +1 -1
- package/src/app/App.tsx +9 -0
- package/src/app/LocalMergeRebase.tsx +2 -188
- package/src/command.ts +6 -0
- package/src/commands/Rebase.tsx +204 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -30220,9 +30220,9 @@ function DirtyCheck(props) {
|
|
|
30220
30220
|
|
|
30221
30221
|
function GatherMetadata(props) {
|
|
30222
30222
|
const fallback = (reactExports.createElement(Text, { color: colors.yellow }, "Gathering local git information\u2026"));
|
|
30223
|
-
return (reactExports.createElement(Await, { fallback: fallback, function: run$
|
|
30223
|
+
return (reactExports.createElement(Await, { fallback: fallback, function: run$8 }, props.children));
|
|
30224
30224
|
}
|
|
30225
|
-
async function run$
|
|
30225
|
+
async function run$8() {
|
|
30226
30226
|
const actions = Store.getState().actions;
|
|
30227
30227
|
const argv = Store.getState().argv;
|
|
30228
30228
|
try {
|
|
@@ -30316,9 +30316,9 @@ function format_time(date) {
|
|
|
30316
30316
|
}
|
|
30317
30317
|
|
|
30318
30318
|
function GithubApiError() {
|
|
30319
|
-
return reactExports.createElement(Await, { fallback: null, function: run$
|
|
30319
|
+
return reactExports.createElement(Await, { fallback: null, function: run$7 });
|
|
30320
30320
|
}
|
|
30321
|
-
async function run$
|
|
30321
|
+
async function run$7() {
|
|
30322
30322
|
const actions = Store.getState().actions;
|
|
30323
30323
|
const res = await cli(`gh api https://api.github.com/rate_limit`);
|
|
30324
30324
|
const res_json = JSON.parse(res.stdout);
|
|
@@ -30360,7 +30360,7 @@ function LocalCommitStatus(props) {
|
|
|
30360
30360
|
if (argv["mock-metadata"]) {
|
|
30361
30361
|
return (reactExports.createElement(Await, { fallback: fallback, function: mock_metadata }, props.children));
|
|
30362
30362
|
}
|
|
30363
|
-
return (reactExports.createElement(Await, { fallback: fallback, function: run$
|
|
30363
|
+
return (reactExports.createElement(Await, { fallback: fallback, function: run$6 }, props.children));
|
|
30364
30364
|
}
|
|
30365
30365
|
async function mock_metadata() {
|
|
30366
30366
|
const module = await Promise.resolve().then(function () { return metadata; });
|
|
@@ -30370,7 +30370,7 @@ async function mock_metadata() {
|
|
|
30370
30370
|
state.step = "status";
|
|
30371
30371
|
});
|
|
30372
30372
|
}
|
|
30373
|
-
async function run$
|
|
30373
|
+
async function run$6() {
|
|
30374
30374
|
const actions = Store.getState().actions;
|
|
30375
30375
|
try {
|
|
30376
30376
|
const commit_range = await range();
|
|
@@ -30449,10 +30449,10 @@ function encode(value) {
|
|
|
30449
30449
|
return result.padStart(max_char_size, "=");
|
|
30450
30450
|
}
|
|
30451
30451
|
|
|
30452
|
-
function
|
|
30453
|
-
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026")
|
|
30452
|
+
function Rebase$1() {
|
|
30453
|
+
return (reactExports.createElement(Await, { function: Rebase$1.run, fallback: reactExports.createElement(Text, { color: colors.yellow }, "Rebasing commits\u2026") }));
|
|
30454
30454
|
}
|
|
30455
|
-
async function run
|
|
30455
|
+
Rebase$1.run = async function run() {
|
|
30456
30456
|
const state = Store.getState();
|
|
30457
30457
|
const actions = state.actions;
|
|
30458
30458
|
const branch_name = state.branch_name;
|
|
@@ -30512,6 +30512,10 @@ async function run$6() {
|
|
|
30512
30512
|
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
30513
30513
|
restore_git();
|
|
30514
30514
|
const next_commit_range = await range();
|
|
30515
|
+
actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.green }), message: "\u2705 {branch_name} in sync with {origin_branch}", values: {
|
|
30516
|
+
branch_name: reactExports.createElement(Brackets, null, branch_name),
|
|
30517
|
+
origin_branch: reactExports.createElement(Brackets, null, `origin/${master_branch}`),
|
|
30518
|
+
} }));
|
|
30515
30519
|
actions.set((state) => {
|
|
30516
30520
|
state.commit_range = next_commit_range;
|
|
30517
30521
|
state.step = "status";
|
|
@@ -30566,9 +30570,13 @@ async function run$6() {
|
|
|
30566
30570
|
"."));
|
|
30567
30571
|
actions.exit(6);
|
|
30568
30572
|
}
|
|
30569
|
-
}
|
|
30573
|
+
};
|
|
30570
30574
|
const PATCH_FILE$1 = "git-stack-cli-patch.patch";
|
|
30571
30575
|
|
|
30576
|
+
function LocalMergeRebase() {
|
|
30577
|
+
return reactExports.createElement(Rebase$1, null);
|
|
30578
|
+
}
|
|
30579
|
+
|
|
30572
30580
|
function write(args) {
|
|
30573
30581
|
const stack_table = table(args);
|
|
30574
30582
|
let result = args.body;
|
|
@@ -32042,6 +32050,11 @@ function MaybeMain() {
|
|
|
32042
32050
|
else if (positional_list.has("log")) {
|
|
32043
32051
|
return reactExports.createElement(Log, null);
|
|
32044
32052
|
}
|
|
32053
|
+
else if (positional_list.has("rebase")) {
|
|
32054
|
+
return (reactExports.createElement(GatherMetadata, null,
|
|
32055
|
+
reactExports.createElement(LocalCommitStatus, null,
|
|
32056
|
+
reactExports.createElement(Rebase$1, null))));
|
|
32057
|
+
}
|
|
32045
32058
|
return (reactExports.createElement(DirtyCheck, null,
|
|
32046
32059
|
!argv.verbose ? null : reactExports.createElement(GithubApiError, null),
|
|
32047
32060
|
reactExports.createElement(GatherMetadata, null,
|
|
@@ -37360,6 +37373,7 @@ async function command() {
|
|
|
37360
37373
|
.command("$0", "Sync commit ranges to Github", (yargs) => yargs.options(DefaultOptions))
|
|
37361
37374
|
.command("fixup [commit]", "Amend staged changes to a specific commit in history", (yargs) => yargs.positional("commit", FixupOptions.commit))
|
|
37362
37375
|
.command("log [args...]", "Print an abbreviated log with numbered commits, useful for git stack fixup", (yargs) => yargs.strict(false))
|
|
37376
|
+
.command("rebase", "Update local branch via rebase with latest changes from origin master branch", (yargs) => yargs)
|
|
37363
37377
|
.option("verbose", GlobalOptions.verbose)
|
|
37364
37378
|
// yargs default wraps to 80 columns
|
|
37365
37379
|
// passing null will wrap to terminal width
|
|
@@ -37367,7 +37381,7 @@ async function command() {
|
|
|
37367
37381
|
.wrap(123)
|
|
37368
37382
|
// disallow unknown options
|
|
37369
37383
|
.strict()
|
|
37370
|
-
.version("1.
|
|
37384
|
+
.version("1.11.0" )
|
|
37371
37385
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
37372
37386
|
.help("help", "Show usage via `git stack help`")
|
|
37373
37387
|
.argv;
|
package/package.json
CHANGED
package/src/app/App.tsx
CHANGED
|
@@ -16,6 +16,7 @@ import { RebaseCheck } from "~/app/RebaseCheck";
|
|
|
16
16
|
import { Store } from "~/app/Store";
|
|
17
17
|
import { Fixup } from "~/commands/Fixup";
|
|
18
18
|
import { Log } from "~/commands/Log";
|
|
19
|
+
import { Rebase } from "~/commands/Rebase";
|
|
19
20
|
|
|
20
21
|
export function App() {
|
|
21
22
|
const actions = Store.useActions();
|
|
@@ -73,6 +74,14 @@ function MaybeMain() {
|
|
|
73
74
|
return <Fixup />;
|
|
74
75
|
} else if (positional_list.has("log")) {
|
|
75
76
|
return <Log />;
|
|
77
|
+
} else if (positional_list.has("rebase")) {
|
|
78
|
+
return (
|
|
79
|
+
<GatherMetadata>
|
|
80
|
+
<LocalCommitStatus>
|
|
81
|
+
<Rebase />
|
|
82
|
+
</LocalCommitStatus>
|
|
83
|
+
</GatherMetadata>
|
|
84
|
+
);
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
return (
|
|
@@ -1,193 +1,7 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
import * as Ink from "ink-cjs";
|
|
6
|
-
|
|
7
|
-
import { Await } from "~/app/Await";
|
|
8
|
-
import { Brackets } from "~/app/Brackets";
|
|
9
|
-
import { FormatText } from "~/app/FormatText";
|
|
10
|
-
import { Parens } from "~/app/Parens";
|
|
11
|
-
import { Store } from "~/app/Store";
|
|
12
|
-
import * as CommitMetadata from "~/core/CommitMetadata";
|
|
13
|
-
import { cli } from "~/core/cli";
|
|
14
|
-
import { colors } from "~/core/colors";
|
|
15
|
-
import { invariant } from "~/core/invariant";
|
|
16
|
-
import { short_id } from "~/core/short_id";
|
|
3
|
+
import { Rebase } from "~/commands/Rebase";
|
|
17
4
|
|
|
18
5
|
export function LocalMergeRebase() {
|
|
19
|
-
return
|
|
20
|
-
<Await
|
|
21
|
-
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
22
|
-
function={run}
|
|
23
|
-
/>
|
|
24
|
-
);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async function run() {
|
|
28
|
-
const state = Store.getState();
|
|
29
|
-
const actions = state.actions;
|
|
30
|
-
const branch_name = state.branch_name;
|
|
31
|
-
const commit_range = state.commit_range;
|
|
32
|
-
const master_branch = state.master_branch;
|
|
33
|
-
const cwd = state.cwd;
|
|
34
|
-
const repo_root = state.repo_root;
|
|
35
|
-
|
|
36
|
-
invariant(branch_name, "branch_name must exist");
|
|
37
|
-
invariant(commit_range, "commit_range must exist");
|
|
38
|
-
invariant(repo_root, "repo_root must exist");
|
|
39
|
-
|
|
40
|
-
// always listen for SIGINT event and restore git state
|
|
41
|
-
process.once("SIGINT", handle_exit);
|
|
42
|
-
|
|
43
|
-
const temp_branch_name = `${branch_name}_${short_id()}`;
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
// actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
|
|
47
|
-
|
|
48
|
-
// must perform rebase from repo root for applying git patch
|
|
49
|
-
process.chdir(repo_root);
|
|
50
|
-
await cli(`pwd`);
|
|
51
|
-
|
|
52
|
-
// update local master to match remote
|
|
53
|
-
await cli(
|
|
54
|
-
`git fetch --no-tags -v origin ${master_branch}:${master_branch}`
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
const master_sha = (await cli(`git rev-parse ${master_branch}`)).stdout;
|
|
58
|
-
const rebase_merge_base = master_sha;
|
|
59
|
-
|
|
60
|
-
// create temporary branch based on merge base
|
|
61
|
-
await cli(`git checkout -b ${temp_branch_name} ${rebase_merge_base}`);
|
|
62
|
-
|
|
63
|
-
const picked_commit_list = [];
|
|
64
|
-
|
|
65
|
-
for (let i = 0; i < commit_range.commit_list.length; i++) {
|
|
66
|
-
const commit = commit_range.commit_list[i];
|
|
67
|
-
const commit_pr = commit_range.pr_lookup[commit.branch_id || ""];
|
|
68
|
-
|
|
69
|
-
// drop commits that are in groups of merged PRs
|
|
70
|
-
const merged_pr = commit_pr?.state === "MERGED";
|
|
71
|
-
|
|
72
|
-
if (merged_pr) {
|
|
73
|
-
if (actions.isDebug()) {
|
|
74
|
-
actions.output(
|
|
75
|
-
<FormatText
|
|
76
|
-
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
77
|
-
message="Dropping {commit_message} {pr_status}"
|
|
78
|
-
values={{
|
|
79
|
-
commit_message: <Brackets>{commit.subject_line}</Brackets>,
|
|
80
|
-
pr_status: <Parens>MERGED</Parens>,
|
|
81
|
-
}}
|
|
82
|
-
/>
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (actions.isDebug()) {
|
|
90
|
-
actions.output(
|
|
91
|
-
<FormatText
|
|
92
|
-
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
93
|
-
message="Picking {commit_message}"
|
|
94
|
-
values={{
|
|
95
|
-
commit_message: <Brackets>{commit.subject_line}</Brackets>,
|
|
96
|
-
}}
|
|
97
|
-
/>
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
picked_commit_list.push(commit);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (picked_commit_list.length > 0) {
|
|
105
|
-
// ensure clean base to avoid conflicts when applying patch
|
|
106
|
-
await cli(`git clean -fd`);
|
|
107
|
-
|
|
108
|
-
// create list of sha for cherry-pick
|
|
109
|
-
const sha_list = picked_commit_list.map((commit) => commit.sha).join(" ");
|
|
110
|
-
|
|
111
|
-
await cli(`git cherry-pick --keep-redundant-commits ${sha_list}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// after all commits have been cherry-picked and amended
|
|
115
|
-
// move the branch pointer to the newly created temporary branch
|
|
116
|
-
// now we are locally in sync with github and on the original branch
|
|
117
|
-
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
118
|
-
|
|
119
|
-
restore_git();
|
|
120
|
-
|
|
121
|
-
const next_commit_range = await CommitMetadata.range();
|
|
122
|
-
|
|
123
|
-
actions.set((state) => {
|
|
124
|
-
state.commit_range = next_commit_range;
|
|
125
|
-
state.step = "status";
|
|
126
|
-
});
|
|
127
|
-
} catch (err) {
|
|
128
|
-
actions.error("Unable to rebase.");
|
|
129
|
-
|
|
130
|
-
if (err instanceof Error) {
|
|
131
|
-
if (actions.isDebug()) {
|
|
132
|
-
actions.error(err.message);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
handle_exit();
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// cleanup git operations if cancelled during manual rebase
|
|
140
|
-
function restore_git() {
|
|
141
|
-
// signint handler MUST run synchronously
|
|
142
|
-
// trying to use `await cli(...)` here will silently fail since
|
|
143
|
-
// all children processes receive the SIGINT signal
|
|
144
|
-
const spawn_options = { ignoreExitCode: true };
|
|
145
|
-
|
|
146
|
-
// always clean up any patch files
|
|
147
|
-
cli.sync(`rm ${PATCH_FILE}`, spawn_options);
|
|
148
|
-
|
|
149
|
-
// always hard reset and clean to allow subsequent checkout
|
|
150
|
-
// if there are files checkout will fail and cascade fail subsequent commands
|
|
151
|
-
cli.sync(`git reset --hard`, spawn_options);
|
|
152
|
-
cli.sync(`git clean -df`, spawn_options);
|
|
153
|
-
|
|
154
|
-
// always put self back in original branch
|
|
155
|
-
cli.sync(`git checkout ${branch_name}`, spawn_options);
|
|
156
|
-
|
|
157
|
-
// ...and cleanup temporary branch
|
|
158
|
-
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
159
|
-
|
|
160
|
-
if (commit_range) {
|
|
161
|
-
// ...and cleanup pr group branches
|
|
162
|
-
for (const group of commit_range.group_list) {
|
|
163
|
-
cli.sync(`git branch -D ${group.id}`, spawn_options);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
// restore back to original dir
|
|
168
|
-
if (fs.existsSync(cwd)) {
|
|
169
|
-
process.chdir(cwd);
|
|
170
|
-
}
|
|
171
|
-
cli.sync(`pwd`, spawn_options);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
function handle_exit() {
|
|
175
|
-
actions.output(
|
|
176
|
-
<Ink.Text color={colors.yellow}>
|
|
177
|
-
Restoring <Brackets>{branch_name}</Brackets>…
|
|
178
|
-
</Ink.Text>
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
restore_git();
|
|
182
|
-
|
|
183
|
-
actions.output(
|
|
184
|
-
<Ink.Text color={colors.yellow}>
|
|
185
|
-
Restored <Brackets>{branch_name}</Brackets>.
|
|
186
|
-
</Ink.Text>
|
|
187
|
-
);
|
|
188
|
-
|
|
189
|
-
actions.exit(6);
|
|
190
|
-
}
|
|
6
|
+
return <Rebase />;
|
|
191
7
|
}
|
|
192
|
-
|
|
193
|
-
const PATCH_FILE = "git-stack-cli-patch.patch";
|
package/src/command.ts
CHANGED
|
@@ -27,6 +27,12 @@ export async function command() {
|
|
|
27
27
|
(yargs) => yargs.strict(false)
|
|
28
28
|
)
|
|
29
29
|
|
|
30
|
+
.command(
|
|
31
|
+
"rebase",
|
|
32
|
+
"Update local branch via rebase with latest changes from origin master branch",
|
|
33
|
+
(yargs) => yargs
|
|
34
|
+
)
|
|
35
|
+
|
|
30
36
|
.option("verbose", GlobalOptions.verbose)
|
|
31
37
|
|
|
32
38
|
// yargs default wraps to 80 columns
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
|
|
5
|
+
import * as Ink from "ink-cjs";
|
|
6
|
+
|
|
7
|
+
import { Await } from "~/app/Await";
|
|
8
|
+
import { Brackets } from "~/app/Brackets";
|
|
9
|
+
import { FormatText } from "~/app/FormatText";
|
|
10
|
+
import { Parens } from "~/app/Parens";
|
|
11
|
+
import { Store } from "~/app/Store";
|
|
12
|
+
import * as CommitMetadata from "~/core/CommitMetadata";
|
|
13
|
+
import { cli } from "~/core/cli";
|
|
14
|
+
import { colors } from "~/core/colors";
|
|
15
|
+
import { invariant } from "~/core/invariant";
|
|
16
|
+
import { short_id } from "~/core/short_id";
|
|
17
|
+
|
|
18
|
+
export function Rebase() {
|
|
19
|
+
return (
|
|
20
|
+
<Await
|
|
21
|
+
function={Rebase.run}
|
|
22
|
+
fallback={<Ink.Text color={colors.yellow}>Rebasing commits…</Ink.Text>}
|
|
23
|
+
/>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Rebase.run = async function run() {
|
|
28
|
+
const state = Store.getState();
|
|
29
|
+
const actions = state.actions;
|
|
30
|
+
const branch_name = state.branch_name;
|
|
31
|
+
const commit_range = state.commit_range;
|
|
32
|
+
const master_branch = state.master_branch;
|
|
33
|
+
const cwd = state.cwd;
|
|
34
|
+
const repo_root = state.repo_root;
|
|
35
|
+
|
|
36
|
+
invariant(branch_name, "branch_name must exist");
|
|
37
|
+
invariant(commit_range, "commit_range must exist");
|
|
38
|
+
invariant(repo_root, "repo_root must exist");
|
|
39
|
+
|
|
40
|
+
// always listen for SIGINT event and restore git state
|
|
41
|
+
process.once("SIGINT", handle_exit);
|
|
42
|
+
|
|
43
|
+
const temp_branch_name = `${branch_name}_${short_id()}`;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
// actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
|
|
47
|
+
|
|
48
|
+
// must perform rebase from repo root for applying git patch
|
|
49
|
+
process.chdir(repo_root);
|
|
50
|
+
await cli(`pwd`);
|
|
51
|
+
|
|
52
|
+
// update local master to match remote
|
|
53
|
+
await cli(
|
|
54
|
+
`git fetch --no-tags -v origin ${master_branch}:${master_branch}`
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const master_sha = (await cli(`git rev-parse ${master_branch}`)).stdout;
|
|
58
|
+
const rebase_merge_base = master_sha;
|
|
59
|
+
|
|
60
|
+
// create temporary branch based on merge base
|
|
61
|
+
await cli(`git checkout -b ${temp_branch_name} ${rebase_merge_base}`);
|
|
62
|
+
|
|
63
|
+
const picked_commit_list = [];
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < commit_range.commit_list.length; i++) {
|
|
66
|
+
const commit = commit_range.commit_list[i];
|
|
67
|
+
const commit_pr = commit_range.pr_lookup[commit.branch_id || ""];
|
|
68
|
+
|
|
69
|
+
// drop commits that are in groups of merged PRs
|
|
70
|
+
const merged_pr = commit_pr?.state === "MERGED";
|
|
71
|
+
|
|
72
|
+
if (merged_pr) {
|
|
73
|
+
if (actions.isDebug()) {
|
|
74
|
+
actions.output(
|
|
75
|
+
<FormatText
|
|
76
|
+
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
77
|
+
message="Dropping {commit_message} {pr_status}"
|
|
78
|
+
values={{
|
|
79
|
+
commit_message: <Brackets>{commit.subject_line}</Brackets>,
|
|
80
|
+
pr_status: <Parens>MERGED</Parens>,
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (actions.isDebug()) {
|
|
90
|
+
actions.output(
|
|
91
|
+
<FormatText
|
|
92
|
+
wrapper={<Ink.Text color={colors.yellow} wrap="truncate-end" />}
|
|
93
|
+
message="Picking {commit_message}"
|
|
94
|
+
values={{
|
|
95
|
+
commit_message: <Brackets>{commit.subject_line}</Brackets>,
|
|
96
|
+
}}
|
|
97
|
+
/>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
picked_commit_list.push(commit);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (picked_commit_list.length > 0) {
|
|
105
|
+
// ensure clean base to avoid conflicts when applying patch
|
|
106
|
+
await cli(`git clean -fd`);
|
|
107
|
+
|
|
108
|
+
// create list of sha for cherry-pick
|
|
109
|
+
const sha_list = picked_commit_list.map((commit) => commit.sha).join(" ");
|
|
110
|
+
|
|
111
|
+
await cli(`git cherry-pick --keep-redundant-commits ${sha_list}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// after all commits have been cherry-picked and amended
|
|
115
|
+
// move the branch pointer to the newly created temporary branch
|
|
116
|
+
// now we are locally in sync with github and on the original branch
|
|
117
|
+
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
118
|
+
|
|
119
|
+
restore_git();
|
|
120
|
+
|
|
121
|
+
const next_commit_range = await CommitMetadata.range();
|
|
122
|
+
|
|
123
|
+
actions.output(
|
|
124
|
+
<FormatText
|
|
125
|
+
wrapper={<Ink.Text color={colors.green} />}
|
|
126
|
+
message="✅ {branch_name} in sync with {origin_branch}"
|
|
127
|
+
values={{
|
|
128
|
+
branch_name: <Brackets>{branch_name}</Brackets>,
|
|
129
|
+
origin_branch: <Brackets>{`origin/${master_branch}`}</Brackets>,
|
|
130
|
+
}}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
actions.set((state) => {
|
|
135
|
+
state.commit_range = next_commit_range;
|
|
136
|
+
state.step = "status";
|
|
137
|
+
});
|
|
138
|
+
} catch (err) {
|
|
139
|
+
actions.error("Unable to rebase.");
|
|
140
|
+
|
|
141
|
+
if (err instanceof Error) {
|
|
142
|
+
if (actions.isDebug()) {
|
|
143
|
+
actions.error(err.message);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
handle_exit();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// cleanup git operations if cancelled during manual rebase
|
|
151
|
+
function restore_git() {
|
|
152
|
+
// signint handler MUST run synchronously
|
|
153
|
+
// trying to use `await cli(...)` here will silently fail since
|
|
154
|
+
// all children processes receive the SIGINT signal
|
|
155
|
+
const spawn_options = { ignoreExitCode: true };
|
|
156
|
+
|
|
157
|
+
// always clean up any patch files
|
|
158
|
+
cli.sync(`rm ${PATCH_FILE}`, spawn_options);
|
|
159
|
+
|
|
160
|
+
// always hard reset and clean to allow subsequent checkout
|
|
161
|
+
// if there are files checkout will fail and cascade fail subsequent commands
|
|
162
|
+
cli.sync(`git reset --hard`, spawn_options);
|
|
163
|
+
cli.sync(`git clean -df`, spawn_options);
|
|
164
|
+
|
|
165
|
+
// always put self back in original branch
|
|
166
|
+
cli.sync(`git checkout ${branch_name}`, spawn_options);
|
|
167
|
+
|
|
168
|
+
// ...and cleanup temporary branch
|
|
169
|
+
cli.sync(`git branch -D ${temp_branch_name}`, spawn_options);
|
|
170
|
+
|
|
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
|
+
// restore back to original dir
|
|
179
|
+
if (fs.existsSync(cwd)) {
|
|
180
|
+
process.chdir(cwd);
|
|
181
|
+
}
|
|
182
|
+
cli.sync(`pwd`, spawn_options);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function handle_exit() {
|
|
186
|
+
actions.output(
|
|
187
|
+
<Ink.Text color={colors.yellow}>
|
|
188
|
+
Restoring <Brackets>{branch_name}</Brackets>…
|
|
189
|
+
</Ink.Text>
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
restore_git();
|
|
193
|
+
|
|
194
|
+
actions.output(
|
|
195
|
+
<Ink.Text color={colors.yellow}>
|
|
196
|
+
Restored <Brackets>{branch_name}</Brackets>.
|
|
197
|
+
</Ink.Text>
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
actions.exit(6);
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const PATCH_FILE = "git-stack-cli-patch.patch";
|