git-stack-cli 1.0.6 → 1.1.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 +4 -7
- package/dist/cjs/index.cjs +355 -129
- package/package.json +4 -4
- package/{rollup.config.mjs → rollup.config.js} +11 -3
- package/scripts/git-sequence-editor.sh +35 -0
- package/scripts/release-brew.ts +7 -1
- package/src/app/DependencyCheck.tsx +150 -95
- package/src/app/LocalMergeRebase.tsx +1 -4
- package/src/app/ManualRebase.tsx +221 -87
- package/src/app/SelectCommitRanges.tsx +1 -0
- package/src/app/Store.tsx +14 -2
- package/src/command.ts +6 -0
- package/src/core/GitReviseTodo.test.ts +572 -0
- package/src/core/GitReviseTodo.ts +79 -0
- package/src/types/global.d.ts +2 -0
package/README.md
CHANGED
|
@@ -87,14 +87,11 @@ npm run build:standalone
|
|
|
87
87
|
>
|
|
88
88
|
> **You must update the `version` in `package.json` and commit all changes first!**
|
|
89
89
|
|
|
90
|
-
### NPM
|
|
91
|
-
|
|
92
90
|
```bash
|
|
93
|
-
npm run release
|
|
94
|
-
```
|
|
91
|
+
npm run release
|
|
95
92
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
93
|
+
# release individually
|
|
94
|
+
npm run release:npm
|
|
95
|
+
npm run release:github
|
|
99
96
|
npm run release:brew
|
|
100
97
|
```
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -26287,10 +26287,21 @@ const BaseStore = createStore()(immer((set, get) => ({
|
|
|
26287
26287
|
if (!id) {
|
|
26288
26288
|
return;
|
|
26289
26289
|
}
|
|
26290
|
+
// set `withoutTimestamp` to skip <LogTimestamp> for all subsequent pending outputs
|
|
26291
|
+
// we only want to timestamp for the first part (when we initialize the [])
|
|
26292
|
+
// if we have many incremental outputs on the same line we do not want multiple timestamps
|
|
26293
|
+
//
|
|
26294
|
+
// await Promise.all([
|
|
26295
|
+
// cli(`for i in $(seq 1 5); do echo $i; sleep 1; done`),
|
|
26296
|
+
// cli(`for i in $(seq 5 1); do printf "$i "; sleep 1; done; echo`),
|
|
26297
|
+
// ]);
|
|
26298
|
+
//
|
|
26299
|
+
let withoutTimestamp = true;
|
|
26290
26300
|
if (!state.pending_output[id]) {
|
|
26301
|
+
withoutTimestamp = false;
|
|
26291
26302
|
state.pending_output[id] = [];
|
|
26292
26303
|
}
|
|
26293
|
-
const renderOutput = renderOutputArgs(args);
|
|
26304
|
+
const renderOutput = renderOutputArgs({ ...args, withoutTimestamp });
|
|
26294
26305
|
state.pending_output[id].push(renderOutput);
|
|
26295
26306
|
},
|
|
26296
26307
|
end_pending_output(state, id) {
|
|
@@ -26313,7 +26324,7 @@ function renderOutputArgs(args) {
|
|
|
26313
26324
|
}
|
|
26314
26325
|
if (args.debug) {
|
|
26315
26326
|
return (reactExports.createElement(reactExports.Fragment, null,
|
|
26316
|
-
reactExports.createElement(LogTimestamp, null),
|
|
26327
|
+
args.withoutTimestamp ? null : reactExports.createElement(LogTimestamp, null),
|
|
26317
26328
|
output));
|
|
26318
26329
|
}
|
|
26319
26330
|
return output;
|
|
@@ -26872,6 +26883,12 @@ const RE$4 = {
|
|
|
26872
26883
|
};
|
|
26873
26884
|
|
|
26874
26885
|
function DependencyCheck(props) {
|
|
26886
|
+
return (reactExports.createElement(CheckGit, null,
|
|
26887
|
+
reactExports.createElement(CheckGithubCli, null,
|
|
26888
|
+
reactExports.createElement(CheckGithubCliAuth, null,
|
|
26889
|
+
reactExports.createElement(CheckGitRevise, null, props.children)))));
|
|
26890
|
+
}
|
|
26891
|
+
function CheckGit(props) {
|
|
26875
26892
|
const actions = Store.useActions();
|
|
26876
26893
|
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26877
26894
|
"Checking ",
|
|
@@ -26888,65 +26905,84 @@ function DependencyCheck(props) {
|
|
|
26888
26905
|
reactExports.createElement(Command, null, "git"),
|
|
26889
26906
|
" must be installed."));
|
|
26890
26907
|
actions.exit(2);
|
|
26891
|
-
} },
|
|
26892
|
-
|
|
26908
|
+
} }, props.children));
|
|
26909
|
+
}
|
|
26910
|
+
function CheckGithubCli(props) {
|
|
26911
|
+
const actions = Store.useActions();
|
|
26912
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26913
|
+
reactExports.createElement(Text, null,
|
|
26893
26914
|
"Checking ",
|
|
26894
|
-
reactExports.createElement(Command, null, "
|
|
26895
|
-
" install..."), function: async () => {
|
|
26896
|
-
|
|
26897
|
-
|
|
26898
|
-
|
|
26915
|
+
reactExports.createElement(Command, null, "gh"),
|
|
26916
|
+
" install...")), function: async () => {
|
|
26917
|
+
if (is_command_available("gh")) {
|
|
26918
|
+
return;
|
|
26919
|
+
}
|
|
26920
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26921
|
+
reactExports.createElement(Command, null, "gh"),
|
|
26922
|
+
" must be installed."));
|
|
26923
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26924
|
+
reactExports.createElement(Text, null, "Visit "),
|
|
26925
|
+
reactExports.createElement(Url, null, "https://cli.github.com"),
|
|
26926
|
+
reactExports.createElement(Text, null, " to install the github cli "),
|
|
26927
|
+
reactExports.createElement(Parens, null,
|
|
26928
|
+
reactExports.createElement(Command, null, "gh"))));
|
|
26929
|
+
actions.exit(3);
|
|
26930
|
+
} }, props.children));
|
|
26931
|
+
}
|
|
26932
|
+
function CheckGithubCliAuth(props) {
|
|
26933
|
+
const actions = Store.useActions();
|
|
26934
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26935
|
+
reactExports.createElement(Text, null,
|
|
26936
|
+
"Checking ",
|
|
26937
|
+
reactExports.createElement(Command, null, "gh auth status"),
|
|
26938
|
+
"...")), function: async () => {
|
|
26939
|
+
const options = { ignoreExitCode: true };
|
|
26940
|
+
const auth_status$1 = await cli(`gh auth status`, options);
|
|
26941
|
+
if (auth_status$1.code === 0) {
|
|
26942
|
+
const username = auth_status(auth_status$1.stdout);
|
|
26943
|
+
if (username) {
|
|
26944
|
+
actions.set((state) => {
|
|
26945
|
+
state.username = username;
|
|
26946
|
+
});
|
|
26899
26947
|
return;
|
|
26900
26948
|
}
|
|
26901
|
-
|
|
26902
|
-
|
|
26903
|
-
|
|
26904
|
-
|
|
26905
|
-
|
|
26906
|
-
|
|
26907
|
-
|
|
26908
|
-
|
|
26909
|
-
|
|
26910
|
-
|
|
26911
|
-
|
|
26912
|
-
|
|
26913
|
-
|
|
26914
|
-
|
|
26915
|
-
|
|
26916
|
-
|
|
26917
|
-
|
|
26918
|
-
|
|
26919
|
-
|
|
26920
|
-
|
|
26921
|
-
|
|
26922
|
-
|
|
26923
|
-
|
|
26924
|
-
|
|
26925
|
-
|
|
26926
|
-
|
|
26927
|
-
|
|
26928
|
-
|
|
26929
|
-
|
|
26930
|
-
|
|
26931
|
-
|
|
26932
|
-
|
|
26933
|
-
|
|
26934
|
-
|
|
26935
|
-
|
|
26936
|
-
|
|
26937
|
-
|
|
26938
|
-
return;
|
|
26939
|
-
}
|
|
26940
|
-
}
|
|
26941
|
-
if (actions.isDebug()) {
|
|
26942
|
-
actions.error("gh auth status could not find username");
|
|
26943
|
-
}
|
|
26944
|
-
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26945
|
-
reactExports.createElement(Command, null, "gh"),
|
|
26946
|
-
reactExports.createElement(Text, null, " requires login, please run "),
|
|
26947
|
-
reactExports.createElement(Command, null, "gh auth login")));
|
|
26948
|
-
actions.exit(4);
|
|
26949
|
-
} }, props.children)))));
|
|
26949
|
+
}
|
|
26950
|
+
if (actions.isDebug()) {
|
|
26951
|
+
actions.error("gh auth status could not find username");
|
|
26952
|
+
}
|
|
26953
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26954
|
+
reactExports.createElement(Command, null, "gh"),
|
|
26955
|
+
reactExports.createElement(Text, null, " requires login, please run "),
|
|
26956
|
+
reactExports.createElement(Command, null, "gh auth login")));
|
|
26957
|
+
actions.exit(4);
|
|
26958
|
+
} }, props.children));
|
|
26959
|
+
}
|
|
26960
|
+
function CheckGitRevise(props) {
|
|
26961
|
+
const actions = Store.useActions();
|
|
26962
|
+
const argv = Store.useState((state) => state.argv);
|
|
26963
|
+
// skip git revise check when `--git-revise` flag is not present
|
|
26964
|
+
if (!argv?.["git-revise"]) {
|
|
26965
|
+
return props.children;
|
|
26966
|
+
}
|
|
26967
|
+
return (reactExports.createElement(Await, { fallback: reactExports.createElement(Text, { color: colors.yellow },
|
|
26968
|
+
reactExports.createElement(Text, null,
|
|
26969
|
+
"Checking ",
|
|
26970
|
+
reactExports.createElement(Command, null, "git-revise"),
|
|
26971
|
+
" install...")), function: async () => {
|
|
26972
|
+
if (is_command_available("git-revise")) {
|
|
26973
|
+
return;
|
|
26974
|
+
}
|
|
26975
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26976
|
+
reactExports.createElement(Command, null, "git-revise"),
|
|
26977
|
+
" must be installed."));
|
|
26978
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow },
|
|
26979
|
+
reactExports.createElement(Text, null, "Visit "),
|
|
26980
|
+
reactExports.createElement(Url, null, "https://github.com/mystor/git-revise#install"),
|
|
26981
|
+
reactExports.createElement(Text, null, " to install the git revise cli "),
|
|
26982
|
+
reactExports.createElement(Parens, null,
|
|
26983
|
+
reactExports.createElement(Command, null, "git-revise"))));
|
|
26984
|
+
actions.exit(10);
|
|
26985
|
+
} }, props.children));
|
|
26950
26986
|
}
|
|
26951
26987
|
|
|
26952
26988
|
function GatherMetadata(props) {
|
|
@@ -27555,7 +27591,7 @@ async function run$3() {
|
|
|
27555
27591
|
await cli(`git add --all`);
|
|
27556
27592
|
let new_message;
|
|
27557
27593
|
if (commit.branch_id) {
|
|
27558
|
-
new_message =
|
|
27594
|
+
new_message = write$1(commit.full_message, commit.branch_id);
|
|
27559
27595
|
}
|
|
27560
27596
|
else {
|
|
27561
27597
|
new_message = commit.full_message;
|
|
@@ -27640,6 +27676,69 @@ async function run$3() {
|
|
|
27640
27676
|
}
|
|
27641
27677
|
const PATCH_FILE$1 = "git-stack-cli-patch.patch";
|
|
27642
27678
|
|
|
27679
|
+
// https://git-revise.readthedocs.io/en/latest/man.html#interactive-mode
|
|
27680
|
+
//
|
|
27681
|
+
// # Interactive Revise Todos(4 commands)
|
|
27682
|
+
// #
|
|
27683
|
+
// # Commands:
|
|
27684
|
+
// # p, pick <commit> = use commit
|
|
27685
|
+
// # r, reword <commit> = use commit, but edit the commit message
|
|
27686
|
+
// # s, squash <commit> = use commit, but meld into previous commit
|
|
27687
|
+
// # f, fixup <commit> = like squash, but discard this commit's message
|
|
27688
|
+
// # c, cut <commit> = interactively split commit into two smaller commits
|
|
27689
|
+
// # i, index <commit> = leave commit changes staged, but uncommitted
|
|
27690
|
+
// #
|
|
27691
|
+
// # Each command block is prefixed by a '++' marker, followed by the command to
|
|
27692
|
+
// # run, the commit hash and after a newline the complete commit message until
|
|
27693
|
+
// # the next '++' marker or the end of the file.
|
|
27694
|
+
// #
|
|
27695
|
+
// # Commit messages will be reworded to match the provided message before the
|
|
27696
|
+
// # command is performed.
|
|
27697
|
+
// #
|
|
27698
|
+
// # These blocks are executed from top to bottom. They can be re-ordered and
|
|
27699
|
+
// # their commands can be changed, however the number of blocks must remain
|
|
27700
|
+
// # identical. If present, index blocks must be at the bottom of the list,
|
|
27701
|
+
// # i.e. they can not be followed by non-index blocks.
|
|
27702
|
+
// #
|
|
27703
|
+
// #
|
|
27704
|
+
// # If you remove everything, the revising process will be aborted.
|
|
27705
|
+
// calculate git-revise-todo from commit_range and rebase_group_index
|
|
27706
|
+
//
|
|
27707
|
+
// Example
|
|
27708
|
+
// ----------------------------
|
|
27709
|
+
// ++ pick d36d63499425
|
|
27710
|
+
// cantaloupe color
|
|
27711
|
+
//
|
|
27712
|
+
// git-stack-id: E63ytp5dj
|
|
27713
|
+
//
|
|
27714
|
+
// ++ pick 4f98dd3e67d0
|
|
27715
|
+
// banana sweet
|
|
27716
|
+
//
|
|
27717
|
+
// git-stack-id: E63ytp5dj
|
|
27718
|
+
//
|
|
27719
|
+
// ++ pick f143d03c723c
|
|
27720
|
+
// apple sweet
|
|
27721
|
+
//
|
|
27722
|
+
function GitReviseTodo(args) {
|
|
27723
|
+
const entry_list = [];
|
|
27724
|
+
const group_list = args.commit_range.group_list;
|
|
27725
|
+
for (let i = args.rebase_group_index; i < group_list.length; i++) {
|
|
27726
|
+
const group = group_list[i];
|
|
27727
|
+
for (const commit of group.commits) {
|
|
27728
|
+
// update git commit message with stack id
|
|
27729
|
+
const message_with_id = write$1(commit.full_message, group.id);
|
|
27730
|
+
// get first 12 characters of commit sha
|
|
27731
|
+
const sha = commit.sha.slice(0, 12);
|
|
27732
|
+
// generate git revise entry
|
|
27733
|
+
const entry_lines = [`++ pick ${sha}`, message_with_id];
|
|
27734
|
+
const entry = entry_lines.join("\n");
|
|
27735
|
+
entry_list.push(entry);
|
|
27736
|
+
}
|
|
27737
|
+
}
|
|
27738
|
+
const todo = entry_list.join("\n\n");
|
|
27739
|
+
return todo;
|
|
27740
|
+
}
|
|
27741
|
+
|
|
27643
27742
|
function write(args) {
|
|
27644
27743
|
const stack_table = table(args);
|
|
27645
27744
|
let result = args.body;
|
|
@@ -27759,17 +27858,141 @@ async function run$2(props) {
|
|
|
27759
27858
|
continue;
|
|
27760
27859
|
}
|
|
27761
27860
|
if (i > 0) {
|
|
27762
|
-
const
|
|
27763
|
-
const
|
|
27764
|
-
rebase_merge_base =
|
|
27861
|
+
const prev_group = commit_range.group_list[i - 1];
|
|
27862
|
+
const prev_commit = prev_group.commits[prev_group.commits.length - 1];
|
|
27863
|
+
rebase_merge_base = prev_commit.sha;
|
|
27765
27864
|
rebase_group_index = i;
|
|
27766
27865
|
}
|
|
27767
27866
|
break;
|
|
27768
27867
|
}
|
|
27868
|
+
actions.debug(`rebase_merge_base=${rebase_merge_base}`);
|
|
27869
|
+
actions.debug(`rebase_group_index=${rebase_group_index}`);
|
|
27870
|
+
actions.debug(`commit_range=${JSON.stringify(commit_range, null, 2)}`);
|
|
27769
27871
|
try {
|
|
27770
27872
|
// must perform rebase from repo root for applying git patch
|
|
27771
27873
|
process.chdir(repo_root);
|
|
27772
27874
|
await cli(`pwd`);
|
|
27875
|
+
if (argv["git-revise"]) {
|
|
27876
|
+
await rebase_git_revise();
|
|
27877
|
+
}
|
|
27878
|
+
else {
|
|
27879
|
+
await rebase_cherry_pick();
|
|
27880
|
+
}
|
|
27881
|
+
// after all commits have been cherry-picked and amended
|
|
27882
|
+
// move the branch pointer to the newly created temporary branch
|
|
27883
|
+
// now we are in locally in sync with github and on the original branch
|
|
27884
|
+
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
27885
|
+
restore_git();
|
|
27886
|
+
actions.set((state) => {
|
|
27887
|
+
state.step = "post-rebase-status";
|
|
27888
|
+
});
|
|
27889
|
+
}
|
|
27890
|
+
catch (err) {
|
|
27891
|
+
actions.error("Unable to rebase.");
|
|
27892
|
+
if (err instanceof Error) {
|
|
27893
|
+
if (actions.isDebug()) {
|
|
27894
|
+
actions.error(err.message);
|
|
27895
|
+
}
|
|
27896
|
+
}
|
|
27897
|
+
handle_exit();
|
|
27898
|
+
}
|
|
27899
|
+
async function rebase_git_revise() {
|
|
27900
|
+
invariant(argv, "argv must exist");
|
|
27901
|
+
actions.debug(`rebase_git_revise`);
|
|
27902
|
+
actions.output(reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }, "Rebasing\u2026"));
|
|
27903
|
+
// generate temporary directory and drop sequence editor script
|
|
27904
|
+
const tmp_git_sequence_editor_path = path.join(os.tmpdir(), "git-sequence-editor.sh");
|
|
27905
|
+
actions.debug(`tmp_git_sequence_editor_path=${tmp_git_sequence_editor_path}`);
|
|
27906
|
+
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
27907
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
|
|
27908
|
+
|
|
27909
|
+
# Example
|
|
27910
|
+
#
|
|
27911
|
+
# GIT_REVISE_TODO="abc" GIT_EDITOR="$(pwd)/scripts/git-sequence-editor.sh" git revise --edit -i head~4
|
|
27912
|
+
#
|
|
27913
|
+
# Note
|
|
27914
|
+
# ----------------
|
|
27915
|
+
# Use \`GIT_EDITOR\` above instead of \`GIT_SEQUENCE_EDITOR\` because \`git revise\` does not use
|
|
27916
|
+
# \`GIT_SEQUENCE_EDITOR\` when passing the \`--edit\` flag, but does work without the \`--edit\` flag
|
|
27917
|
+
#
|
|
27918
|
+
#
|
|
27919
|
+
|
|
27920
|
+
# debug print env variables
|
|
27921
|
+
echo "GIT_REVISE_TODO=$GIT_REVISE_TODO"
|
|
27922
|
+
echo "CLI=$0 $*"
|
|
27923
|
+
echo "PWD=$(pwd)"
|
|
27924
|
+
|
|
27925
|
+
# ensure \`GIT_REVISE_TODO\` is not empty
|
|
27926
|
+
if [ -z "$GIT_REVISE_TODO" ]; then
|
|
27927
|
+
echo "🚨 GIT_REVISE_TODO environment variable is empty" >&2
|
|
27928
|
+
exit 1
|
|
27929
|
+
fi
|
|
27930
|
+
|
|
27931
|
+
# first argument into git sequence editor is git-revise-todo file
|
|
27932
|
+
git_revise_todo_path="$1"
|
|
27933
|
+
|
|
27934
|
+
# debug print git-revise-todo file passed into command
|
|
27935
|
+
echo "$git_revise_todo_path"
|
|
27936
|
+
echo "----- START -----"
|
|
27937
|
+
cat "$git_revise_todo_path"
|
|
27938
|
+
echo "------ END ------"
|
|
27939
|
+
|
|
27940
|
+
# write content of \`GIT_REVISE_TODO\` env variable to \`git_revise_todo_path\`
|
|
27941
|
+
echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
27942
|
+
`;
|
|
27943
|
+
// write script to temporary path
|
|
27944
|
+
fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
27945
|
+
// ensure script is executable
|
|
27946
|
+
fs.chmodSync(tmp_git_sequence_editor_path, "755");
|
|
27947
|
+
// create temporary branch
|
|
27948
|
+
await cli(`git checkout -b ${temp_branch_name}`);
|
|
27949
|
+
const git_revise_todo = GitReviseTodo({ rebase_group_index, commit_range });
|
|
27950
|
+
// execute cli with temporary git sequence editor script
|
|
27951
|
+
// revise from merge base to pick correct commits
|
|
27952
|
+
await cli([
|
|
27953
|
+
`GIT_EDITOR="${tmp_git_sequence_editor_path}"`,
|
|
27954
|
+
`GIT_REVISE_TODO="${git_revise_todo}"`,
|
|
27955
|
+
`git`,
|
|
27956
|
+
`revise --edit -i ${rebase_merge_base}`,
|
|
27957
|
+
]);
|
|
27958
|
+
// start from HEAD and work backward to rebase_group_index
|
|
27959
|
+
const push_group_list = [];
|
|
27960
|
+
let lookback_index = 0;
|
|
27961
|
+
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
27962
|
+
const index = commit_range.group_list.length - 1 - i;
|
|
27963
|
+
// do not go past rebase_group_index
|
|
27964
|
+
if (index < rebase_group_index) {
|
|
27965
|
+
break;
|
|
27966
|
+
}
|
|
27967
|
+
const group = commit_range.group_list[index];
|
|
27968
|
+
// console.debug({ i, index, group });
|
|
27969
|
+
if (i > 0) {
|
|
27970
|
+
const prev_group = commit_range.group_list[index + 1];
|
|
27971
|
+
lookback_index += prev_group.commits.length;
|
|
27972
|
+
}
|
|
27973
|
+
// console.debug(`git show head~${lookback_index}`);
|
|
27974
|
+
// push group and lookback_index onto front of push_group_list
|
|
27975
|
+
push_group_list.unshift({ group, lookback_index });
|
|
27976
|
+
}
|
|
27977
|
+
const pr_url_list = commit_range.group_list.map(get_group_url);
|
|
27978
|
+
// use push_group_list to sync each group HEAD to github
|
|
27979
|
+
for (const push_group of push_group_list) {
|
|
27980
|
+
const { group } = push_group;
|
|
27981
|
+
// move to temporary branch for resetting to lookback_index to create PR
|
|
27982
|
+
await cli(`git checkout -b ${group.id}`);
|
|
27983
|
+
// prepare branch for sync, reset to commit at lookback index
|
|
27984
|
+
await cli(`git reset --hard HEAD~${push_group.lookback_index}`);
|
|
27985
|
+
await sync_group_github({ group, pr_url_list, skip_checkout: true });
|
|
27986
|
+
// done, remove temp push branch and move back to temp branch
|
|
27987
|
+
await cli(`git checkout ${temp_branch_name}`);
|
|
27988
|
+
await cli(`git branch -D ${group.id}`);
|
|
27989
|
+
}
|
|
27990
|
+
// finally, ensure all prs have the updated stack table from updated pr_url_list
|
|
27991
|
+
await update_pr_tables(pr_url_list);
|
|
27992
|
+
}
|
|
27993
|
+
async function rebase_cherry_pick() {
|
|
27994
|
+
invariant(argv, "argv must exist");
|
|
27995
|
+
actions.debug("rebase_cherry_pick");
|
|
27773
27996
|
// create temporary branch based on merge base
|
|
27774
27997
|
await cli(`git checkout -b ${temp_branch_name} ${rebase_merge_base}`);
|
|
27775
27998
|
const pr_url_list = commit_range.group_list.map(get_group_url);
|
|
@@ -27779,7 +28002,6 @@ async function run$2(props) {
|
|
|
27779
28002
|
actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Rebasing {group}\u2026", values: {
|
|
27780
28003
|
group: (reactExports.createElement(Brackets, null, group.pr?.title || group.title || group.id)),
|
|
27781
28004
|
} }));
|
|
27782
|
-
const selected_url = get_group_url(group);
|
|
27783
28005
|
// cherry-pick and amend commits one by one
|
|
27784
28006
|
for (const commit of group.commits) {
|
|
27785
28007
|
// ensure clean base to avoid conflicts when applying patch
|
|
@@ -27790,63 +28012,78 @@ async function run$2(props) {
|
|
|
27790
28012
|
await cli(`rm ${PATCH_FILE}`);
|
|
27791
28013
|
// add all changes to stage
|
|
27792
28014
|
await cli(`git add --all`);
|
|
27793
|
-
const new_message =
|
|
28015
|
+
const new_message = write$1(commit.full_message, group.id);
|
|
27794
28016
|
const git_commit_comand = [`git commit -m "${new_message}"`];
|
|
27795
28017
|
if (argv.verify === false) {
|
|
27796
28018
|
git_commit_comand.push("--no-verify");
|
|
27797
28019
|
}
|
|
27798
28020
|
await cli(git_commit_comand);
|
|
27799
28021
|
}
|
|
27800
|
-
|
|
27801
|
-
|
|
27802
|
-
|
|
27803
|
-
|
|
27804
|
-
|
|
27805
|
-
|
|
27806
|
-
|
|
27807
|
-
|
|
27808
|
-
|
|
27809
|
-
|
|
27810
|
-
|
|
27811
|
-
|
|
27812
|
-
|
|
27813
|
-
|
|
27814
|
-
|
|
27815
|
-
|
|
27816
|
-
|
|
27817
|
-
|
|
27818
|
-
|
|
27819
|
-
|
|
27820
|
-
|
|
27821
|
-
|
|
27822
|
-
|
|
27823
|
-
|
|
27824
|
-
|
|
27825
|
-
|
|
27826
|
-
|
|
27827
|
-
|
|
27828
|
-
|
|
27829
|
-
|
|
27830
|
-
|
|
27831
|
-
|
|
27832
|
-
|
|
27833
|
-
|
|
27834
|
-
|
|
27835
|
-
|
|
27836
|
-
|
|
27837
|
-
|
|
27838
|
-
|
|
27839
|
-
|
|
27840
|
-
|
|
27841
|
-
|
|
27842
|
-
|
|
27843
|
-
|
|
27844
|
-
|
|
27845
|
-
|
|
28022
|
+
await sync_group_github({ group, pr_url_list, skip_checkout: false });
|
|
28023
|
+
}
|
|
28024
|
+
// finally, ensure all prs have the updated stack table from updated pr_url_list
|
|
28025
|
+
await update_pr_tables(pr_url_list);
|
|
28026
|
+
}
|
|
28027
|
+
async function sync_group_github(args) {
|
|
28028
|
+
if (props.skipSync) {
|
|
28029
|
+
return;
|
|
28030
|
+
}
|
|
28031
|
+
const { group, pr_url_list } = args;
|
|
28032
|
+
invariant(argv, "argv must exist");
|
|
28033
|
+
invariant(group.base, "group.base must exist");
|
|
28034
|
+
actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Syncing {group}\u2026", values: {
|
|
28035
|
+
group: (reactExports.createElement(Brackets, null, group.pr?.title || group.title || group.id)),
|
|
28036
|
+
} }));
|
|
28037
|
+
// push to origin since github requires commit shas to line up perfectly
|
|
28038
|
+
const git_push_command = [`git push -f origin HEAD:${group.id}`];
|
|
28039
|
+
if (argv.verify === false) {
|
|
28040
|
+
git_push_command.push("--no-verify");
|
|
28041
|
+
}
|
|
28042
|
+
await cli(git_push_command);
|
|
28043
|
+
const selected_url = get_group_url(group);
|
|
28044
|
+
if (group.pr) {
|
|
28045
|
+
// ensure base matches pr in github
|
|
28046
|
+
await pr_edit({
|
|
28047
|
+
branch: group.id,
|
|
28048
|
+
base: group.base,
|
|
28049
|
+
body: write({
|
|
28050
|
+
body: group.pr.body,
|
|
28051
|
+
pr_url_list,
|
|
28052
|
+
selected_url,
|
|
28053
|
+
}),
|
|
28054
|
+
});
|
|
28055
|
+
}
|
|
28056
|
+
else {
|
|
28057
|
+
if (!args.skip_checkout) {
|
|
28058
|
+
// delete local group branch if leftover
|
|
28059
|
+
await cli(`git branch -D ${group.id}`, { ignoreExitCode: true });
|
|
28060
|
+
// move to temporary branch for creating pr
|
|
28061
|
+
await cli(`git checkout -b ${group.id}`);
|
|
28062
|
+
}
|
|
28063
|
+
// create pr in github
|
|
28064
|
+
const pr_url = await pr_create({
|
|
28065
|
+
branch: group.id,
|
|
28066
|
+
base: group.base,
|
|
28067
|
+
title: group.title,
|
|
28068
|
+
body: "",
|
|
28069
|
+
});
|
|
28070
|
+
if (!pr_url) {
|
|
28071
|
+
throw new Error("unable to create pr");
|
|
28072
|
+
}
|
|
28073
|
+
// update pr_url_list with created pr_url
|
|
28074
|
+
for (let i = 0; i < pr_url_list.length; i++) {
|
|
28075
|
+
const url = pr_url_list[i];
|
|
28076
|
+
if (url === selected_url) {
|
|
28077
|
+
pr_url_list[i] = pr_url;
|
|
27846
28078
|
}
|
|
27847
28079
|
}
|
|
28080
|
+
// move back to temp branch
|
|
28081
|
+
if (!args.skip_checkout) {
|
|
28082
|
+
await cli(`git checkout ${temp_branch_name}`);
|
|
28083
|
+
}
|
|
27848
28084
|
}
|
|
27849
|
-
|
|
28085
|
+
}
|
|
28086
|
+
async function update_pr_tables(pr_url_list) {
|
|
27850
28087
|
for (let i = 0; i < commit_range.group_list.length; i++) {
|
|
27851
28088
|
const group = commit_range.group_list[i];
|
|
27852
28089
|
// use the updated pr_url_list to get the actual selected_url
|
|
@@ -27870,23 +28107,6 @@ async function run$2(props) {
|
|
|
27870
28107
|
});
|
|
27871
28108
|
}
|
|
27872
28109
|
}
|
|
27873
|
-
// after all commits have been cherry-picked and amended
|
|
27874
|
-
// move the branch pointer to the newly created temporary branch
|
|
27875
|
-
// now we are in locally in sync with github and on the original branch
|
|
27876
|
-
await cli(`git branch -f ${branch_name} ${temp_branch_name}`);
|
|
27877
|
-
restore_git();
|
|
27878
|
-
actions.set((state) => {
|
|
27879
|
-
state.step = "post-rebase-status";
|
|
27880
|
-
});
|
|
27881
|
-
}
|
|
27882
|
-
catch (err) {
|
|
27883
|
-
actions.error("Unable to rebase.");
|
|
27884
|
-
if (err instanceof Error) {
|
|
27885
|
-
if (actions.isDebug()) {
|
|
27886
|
-
actions.error(err.message);
|
|
27887
|
-
}
|
|
27888
|
-
}
|
|
27889
|
-
handle_exit();
|
|
27890
28110
|
}
|
|
27891
28111
|
// cleanup git operations if cancelled during manual rebase
|
|
27892
28112
|
function restore_git() {
|
|
@@ -28440,6 +28660,7 @@ function SelectCommitRangesInternal(props) {
|
|
|
28440
28660
|
switch (inputLower) {
|
|
28441
28661
|
case "s":
|
|
28442
28662
|
state.step = "manual-rebase";
|
|
28663
|
+
// state.step = "manual-rebase-no-sync";
|
|
28443
28664
|
break;
|
|
28444
28665
|
}
|
|
28445
28666
|
});
|
|
@@ -34069,6 +34290,11 @@ async function command() {
|
|
|
34069
34290
|
type: "boolean",
|
|
34070
34291
|
default: true,
|
|
34071
34292
|
description: "Skip git hooks such as pre-commit and pre-push",
|
|
34293
|
+
})
|
|
34294
|
+
.option("git-revise", {
|
|
34295
|
+
type: "boolean",
|
|
34296
|
+
default: false,
|
|
34297
|
+
description: `Use git-revise to perform in-memory rebase, (macOS + Linux only)`,
|
|
34072
34298
|
})
|
|
34073
34299
|
.option("verbose", {
|
|
34074
34300
|
type: "boolean",
|
|
@@ -34104,7 +34330,7 @@ async function command() {
|
|
|
34104
34330
|
.wrap(null)
|
|
34105
34331
|
// disallow unknown options
|
|
34106
34332
|
.strict()
|
|
34107
|
-
.version("1.0
|
|
34333
|
+
.version("1.1.0" )
|
|
34108
34334
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
34109
34335
|
.help("help", "Show usage via `git stack help`").argv);
|
|
34110
34336
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-stack-cli",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "magus",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,13 +17,13 @@
|
|
|
17
17
|
"scripts",
|
|
18
18
|
"src",
|
|
19
19
|
"package-lock.json",
|
|
20
|
-
"rollup.config.
|
|
20
|
+
"rollup.config.js",
|
|
21
21
|
"tsconfig.json"
|
|
22
22
|
],
|
|
23
23
|
"scripts": {
|
|
24
24
|
"dev": "npm run build -- --watch",
|
|
25
|
-
"build": "rollup -c rollup.config.
|
|
26
|
-
"build:standalone": "bun run scripts/build-standalone.ts",
|
|
25
|
+
"build": "rollup -c rollup.config.js",
|
|
26
|
+
"build:standalone": "GIT_STACK_STANDALONE=true bun run scripts/build-standalone.ts",
|
|
27
27
|
"release:npm": "bun run scripts/release-npm.ts",
|
|
28
28
|
"release:github": "bun run scripts/release-github.ts",
|
|
29
29
|
"release:brew": "bun run scripts/release-brew.ts",
|