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 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**.
@@ -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 cli_result = await cli(
29778
- // prettier-ignore
29779
- `gh pr edit ${args.branch} --base ${args.base} --body-file="${body_file(args.body)}"`);
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.1" )
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-stack-cli",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "",
5
5
  "author": "magus",
6
6
  "license": "MIT",
@@ -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
  );
@@ -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
 
@@ -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: string;
144
+ body?: string;
145
145
  };
146
146
 
147
147
  export async function pr_edit(args: EditPullRequestArgs) {
148
- const cli_result = await cli(
149
- // prettier-ignore
150
- `gh pr edit ${args.branch} --base ${args.base} --body-file="${body_file(args.body)}"`
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);