git-stack-cli 1.11.1 → 1.11.3
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 +20 -1
- package/dist/cjs/index.cjs +55 -48
- package/package.json +1 -1
- package/scripts/release-npm.ts +7 -0
- package/src/app/ManualRebase.tsx +10 -21
- package/src/core/GitReviseTodo.ts +6 -0
- package/src/core/github.tsx +10 -5
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
## Demo
|
|
15
15
|
|
|
16
|
-
> <img src="https://github.com/magus/git-multi-diff-playground/assets/290084/069c304b-80cb-49a9-9dc6-4ed3b061a5bc">
|
|
16
|
+
> <img alt="git stack demo" src="https://github.com/magus/git-multi-diff-playground/assets/290084/069c304b-80cb-49a9-9dc6-4ed3b061a5bc">
|
|
17
17
|
|
|
18
18
|
## Install
|
|
19
19
|
|
|
@@ -54,6 +54,25 @@ git stack --no-verify # skip git hooks such as pre-commit and pre-push
|
|
|
54
54
|
git stack help # print a table of all CLI arguments
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
### Editing existing commits and pull requests
|
|
58
|
+
|
|
59
|
+
Sometimes you want to add changes to an existing commit or pull request.
|
|
60
|
+
With `git-stack` this is as simple as amending the commit.
|
|
61
|
+
|
|
62
|
+
1. `git add` your changes to the stage
|
|
63
|
+
2. `git stack log` to find the relative commit number you want to amend
|
|
64
|
+
3. `git stack fixup <number>` to amend the specific commit with your staged changes.
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git add -p
|
|
68
|
+
git stack log
|
|
69
|
+
git stack fixup 2
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
> <img alt="git stack fixup demo" src="https://github.com/user-attachments/assets/2cdfaa5b-00be-4ed3-8bed-4a24c412979b">
|
|
73
|
+
|
|
74
|
+
Running `git stack` afterward will update any existing pull requests with your changes.
|
|
75
|
+
|
|
57
76
|
## Why?
|
|
58
77
|
|
|
59
78
|
The goal of `git stack` is to combine the **simplicity of developing in a single branch** in order to **preserve your commit history** while also **grouping commits into pull requests for code review**.
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -29774,9 +29774,12 @@ async function pr_create(args) {
|
|
|
29774
29774
|
return cli_result.stdout;
|
|
29775
29775
|
}
|
|
29776
29776
|
async function pr_edit(args) {
|
|
29777
|
-
const
|
|
29778
|
-
|
|
29779
|
-
|
|
29777
|
+
const command_parts = [`gh pr edit ${args.branch} --base ${args.base}`];
|
|
29778
|
+
if (args.body) {
|
|
29779
|
+
command_parts.push(`--body-file="${body_file(args.body)}"`);
|
|
29780
|
+
}
|
|
29781
|
+
const command = command_parts.join(" ");
|
|
29782
|
+
const cli_result = await cli(command);
|
|
29780
29783
|
if (cli_result.code !== 0) {
|
|
29781
29784
|
handle_error(cli_result.output);
|
|
29782
29785
|
}
|
|
@@ -30056,6 +30059,45 @@ GitReviseTodo.todo = function todo(args) {
|
|
|
30056
30059
|
GitReviseTodo.execute = async function grt_execute(args) {
|
|
30057
30060
|
// generate temporary directory and drop sequence editor script
|
|
30058
30061
|
const tmp_git_sequence_editor_path = path.join(os.tmpdir(), "git-sequence-editor.sh");
|
|
30062
|
+
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
30063
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
|
|
30064
|
+
|
|
30065
|
+
# Example
|
|
30066
|
+
#
|
|
30067
|
+
# GIT_REVISE_TODO="abc" GIT_EDITOR="$(pwd)/scripts/git-sequence-editor.sh" git revise --edit -i head~4
|
|
30068
|
+
#
|
|
30069
|
+
# Note
|
|
30070
|
+
# ----------------
|
|
30071
|
+
# Use \`GIT_EDITOR\` above instead of \`GIT_SEQUENCE_EDITOR\` because \`git revise\` does not use
|
|
30072
|
+
# \`GIT_SEQUENCE_EDITOR\` when passing the \`--edit\` flag, but does work without the \`--edit\` flag
|
|
30073
|
+
#
|
|
30074
|
+
#
|
|
30075
|
+
|
|
30076
|
+
# debug print env variables
|
|
30077
|
+
echo "GIT_REVISE_TODO=$GIT_REVISE_TODO"
|
|
30078
|
+
echo "CLI=$0 $*"
|
|
30079
|
+
echo "PWD=$(pwd)"
|
|
30080
|
+
|
|
30081
|
+
# ensure \`GIT_REVISE_TODO\` is not empty
|
|
30082
|
+
if [ -z "$GIT_REVISE_TODO" ]; then
|
|
30083
|
+
echo "🚨 GIT_REVISE_TODO environment variable is empty" >&2
|
|
30084
|
+
exit 1
|
|
30085
|
+
fi
|
|
30086
|
+
|
|
30087
|
+
# first argument into git sequence editor is git-revise-todo file
|
|
30088
|
+
git_revise_todo_path="$1"
|
|
30089
|
+
|
|
30090
|
+
# debug print git-revise-todo file passed into command
|
|
30091
|
+
echo "$git_revise_todo_path"
|
|
30092
|
+
echo "----- START -----"
|
|
30093
|
+
cat "$git_revise_todo_path"
|
|
30094
|
+
echo "------ END ------"
|
|
30095
|
+
|
|
30096
|
+
# write content of \`GIT_REVISE_TODO\` env variable to \`git_revise_todo_path\`
|
|
30097
|
+
echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
30098
|
+
`;
|
|
30099
|
+
// write script to temporary path
|
|
30100
|
+
fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
30059
30101
|
// ensure script is executable
|
|
30060
30102
|
fs.chmodSync(tmp_git_sequence_editor_path, "755");
|
|
30061
30103
|
const git_revise_todo = GitReviseTodo(args);
|
|
@@ -30778,50 +30820,6 @@ async function run$5() {
|
|
|
30778
30820
|
async function rebase_git_revise() {
|
|
30779
30821
|
actions.debug(`rebase_git_revise`);
|
|
30780
30822
|
actions.output(reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }, "Rebasing\u2026"));
|
|
30781
|
-
// generate temporary directory and drop sequence editor script
|
|
30782
|
-
const tmp_git_sequence_editor_path = path.join(os.tmpdir(), "git-sequence-editor.sh");
|
|
30783
|
-
actions.debug(`tmp_git_sequence_editor_path=${tmp_git_sequence_editor_path}`);
|
|
30784
|
-
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
30785
|
-
const GIT_SEQUENCE_EDITOR_SCRIPT = `#!/bin/sh
|
|
30786
|
-
|
|
30787
|
-
# Example
|
|
30788
|
-
#
|
|
30789
|
-
# GIT_REVISE_TODO="abc" GIT_EDITOR="$(pwd)/scripts/git-sequence-editor.sh" git revise --edit -i head~4
|
|
30790
|
-
#
|
|
30791
|
-
# Note
|
|
30792
|
-
# ----------------
|
|
30793
|
-
# Use \`GIT_EDITOR\` above instead of \`GIT_SEQUENCE_EDITOR\` because \`git revise\` does not use
|
|
30794
|
-
# \`GIT_SEQUENCE_EDITOR\` when passing the \`--edit\` flag, but does work without the \`--edit\` flag
|
|
30795
|
-
#
|
|
30796
|
-
#
|
|
30797
|
-
|
|
30798
|
-
# debug print env variables
|
|
30799
|
-
echo "GIT_REVISE_TODO=$GIT_REVISE_TODO"
|
|
30800
|
-
echo "CLI=$0 $*"
|
|
30801
|
-
echo "PWD=$(pwd)"
|
|
30802
|
-
|
|
30803
|
-
# ensure \`GIT_REVISE_TODO\` is not empty
|
|
30804
|
-
if [ -z "$GIT_REVISE_TODO" ]; then
|
|
30805
|
-
echo "🚨 GIT_REVISE_TODO environment variable is empty" >&2
|
|
30806
|
-
exit 1
|
|
30807
|
-
fi
|
|
30808
|
-
|
|
30809
|
-
# first argument into git sequence editor is git-revise-todo file
|
|
30810
|
-
git_revise_todo_path="$1"
|
|
30811
|
-
|
|
30812
|
-
# debug print git-revise-todo file passed into command
|
|
30813
|
-
echo "$git_revise_todo_path"
|
|
30814
|
-
echo "----- START -----"
|
|
30815
|
-
cat "$git_revise_todo_path"
|
|
30816
|
-
echo "------ END ------"
|
|
30817
|
-
|
|
30818
|
-
# write content of \`GIT_REVISE_TODO\` env variable to \`git_revise_todo_path\`
|
|
30819
|
-
echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
30820
|
-
`;
|
|
30821
|
-
// write script to temporary path
|
|
30822
|
-
fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
30823
|
-
// ensure script is executable
|
|
30824
|
-
fs.chmodSync(tmp_git_sequence_editor_path, "755");
|
|
30825
30823
|
// create temporary branch
|
|
30826
30824
|
await cli(`git checkout -b ${temp_branch_name}`);
|
|
30827
30825
|
await GitReviseTodo.execute({
|
|
@@ -30913,6 +30911,15 @@ echo "$GIT_REVISE_TODO" > "$git_revise_todo_path"
|
|
|
30913
30911
|
actions.output(reactExports.createElement(FormatText, { wrapper: reactExports.createElement(Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Syncing {group}\u2026", values: {
|
|
30914
30912
|
group: (reactExports.createElement(Brackets, null, group.pr?.title || group.title || group.id)),
|
|
30915
30913
|
} }));
|
|
30914
|
+
// before pushing reset base to master temporarily
|
|
30915
|
+
// avoid accidentally pointing to orphaned parent commit
|
|
30916
|
+
// should hopefully fix issues where a PR includes a bunch of commits after pushing
|
|
30917
|
+
if (group.pr) {
|
|
30918
|
+
await pr_edit({
|
|
30919
|
+
branch: group.id,
|
|
30920
|
+
base: master_branch,
|
|
30921
|
+
});
|
|
30922
|
+
}
|
|
30916
30923
|
// push to origin since github requires commit shas to line up perfectly
|
|
30917
30924
|
const git_push_command = [`git push -f origin HEAD:${group.id}`];
|
|
30918
30925
|
if (argv.verify === false) {
|
|
@@ -37385,7 +37392,7 @@ async function command() {
|
|
|
37385
37392
|
.wrap(123)
|
|
37386
37393
|
// disallow unknown options
|
|
37387
37394
|
.strict()
|
|
37388
|
-
.version("1.11.
|
|
37395
|
+
.version("1.11.3" )
|
|
37389
37396
|
.showHidden("show-hidden", "Show hidden options via `git stack help --show-hidden`")
|
|
37390
37397
|
.help("help", "Show usage via `git stack help`")
|
|
37391
37398
|
.argv;
|
package/package.json
CHANGED
package/scripts/release-npm.ts
CHANGED
|
@@ -17,6 +17,13 @@ await fs.mkdir(DIST_DIR, { recursive: true });
|
|
|
17
17
|
|
|
18
18
|
process.chdir(PROJECT_DIR);
|
|
19
19
|
|
|
20
|
+
// require clean git status besides changes to package.json version
|
|
21
|
+
const git_status = await spawn.sync("git status --porcelain");
|
|
22
|
+
if (!/^M\s+package.json/.test(git_status.stdout)) {
|
|
23
|
+
console.error("please commit local changes before running release");
|
|
24
|
+
process.exit(4);
|
|
25
|
+
}
|
|
26
|
+
|
|
20
27
|
const package_json = await file.read_json(
|
|
21
28
|
path.join(PROJECT_DIR, "package.json")
|
|
22
29
|
);
|
package/src/app/ManualRebase.tsx
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
-
import os from "node:os";
|
|
5
|
-
import path from "node:path";
|
|
6
4
|
|
|
7
5
|
import * as Ink from "ink-cjs";
|
|
8
6
|
import cloneDeep from "lodash/cloneDeep";
|
|
@@ -145,25 +143,6 @@ async function run() {
|
|
|
145
143
|
</Ink.Text>
|
|
146
144
|
);
|
|
147
145
|
|
|
148
|
-
// generate temporary directory and drop sequence editor script
|
|
149
|
-
const tmp_git_sequence_editor_path = path.join(
|
|
150
|
-
os.tmpdir(),
|
|
151
|
-
"git-sequence-editor.sh"
|
|
152
|
-
);
|
|
153
|
-
|
|
154
|
-
actions.debug(
|
|
155
|
-
`tmp_git_sequence_editor_path=${tmp_git_sequence_editor_path}`
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
159
|
-
const GIT_SEQUENCE_EDITOR_SCRIPT = `process.env.GIT_SEQUENCE_EDITOR_SCRIPT`;
|
|
160
|
-
|
|
161
|
-
// write script to temporary path
|
|
162
|
-
fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
163
|
-
|
|
164
|
-
// ensure script is executable
|
|
165
|
-
fs.chmodSync(tmp_git_sequence_editor_path, "755");
|
|
166
|
-
|
|
167
146
|
// create temporary branch
|
|
168
147
|
await cli(`git checkout -b ${temp_branch_name}`);
|
|
169
148
|
|
|
@@ -310,6 +289,16 @@ async function run() {
|
|
|
310
289
|
/>
|
|
311
290
|
);
|
|
312
291
|
|
|
292
|
+
// before pushing reset base to master temporarily
|
|
293
|
+
// avoid accidentally pointing to orphaned parent commit
|
|
294
|
+
// should hopefully fix issues where a PR includes a bunch of commits after pushing
|
|
295
|
+
if (group.pr) {
|
|
296
|
+
await github.pr_edit({
|
|
297
|
+
branch: group.id,
|
|
298
|
+
base: master_branch,
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
313
302
|
// push to origin since github requires commit shas to line up perfectly
|
|
314
303
|
const git_push_command = [`git push -f origin HEAD:${group.id}`];
|
|
315
304
|
|
|
@@ -116,6 +116,12 @@ GitReviseTodo.execute = async function grt_execute(args: ExecuteArgs) {
|
|
|
116
116
|
"git-sequence-editor.sh"
|
|
117
117
|
);
|
|
118
118
|
|
|
119
|
+
// replaced at build time with literal contents of `scripts/git-sequence-editor.sh`
|
|
120
|
+
const GIT_SEQUENCE_EDITOR_SCRIPT = `process.env.GIT_SEQUENCE_EDITOR_SCRIPT`;
|
|
121
|
+
|
|
122
|
+
// write script to temporary path
|
|
123
|
+
fs.writeFileSync(tmp_git_sequence_editor_path, GIT_SEQUENCE_EDITOR_SCRIPT);
|
|
124
|
+
|
|
119
125
|
// ensure script is executable
|
|
120
126
|
fs.chmodSync(tmp_git_sequence_editor_path, "755");
|
|
121
127
|
|
package/src/core/github.tsx
CHANGED
|
@@ -141,14 +141,19 @@ export async function pr_create(args: CreatePullRequestArgs) {
|
|
|
141
141
|
type EditPullRequestArgs = {
|
|
142
142
|
branch: string;
|
|
143
143
|
base: string;
|
|
144
|
-
body
|
|
144
|
+
body?: string;
|
|
145
145
|
};
|
|
146
146
|
|
|
147
147
|
export async function pr_edit(args: EditPullRequestArgs) {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
const command_parts = [`gh pr edit ${args.branch} --base ${args.base}`];
|
|
149
|
+
|
|
150
|
+
if (args.body) {
|
|
151
|
+
command_parts.push(`--body-file="${body_file(args.body)}"`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const command = command_parts.join(" ");
|
|
155
|
+
|
|
156
|
+
const cli_result = await cli(command);
|
|
152
157
|
|
|
153
158
|
if (cli_result.code !== 0) {
|
|
154
159
|
handle_error(cli_result.output);
|