git-stack-cli 0.7.3 → 0.7.5
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 +23 -12
- package/dist/app/LocalMergeRebase.js +7 -1
- package/dist/app/ManualRebase.js +6 -2
- package/dist/command.js +2 -2
- package/dist/core/cli.js +8 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,40 +1,51 @@
|
|
|
1
1
|
# git-stack-cli
|
|
2
2
|
|
|
3
|
+
- ✨ **[Stacked diffs](https://graphite.dev/guides/stacked-diffs) for `git`**
|
|
3
4
|
- 🚀 **Simple one-branch workflow**
|
|
4
5
|
- 🎯 **Interactively select commits for each pull request**
|
|
5
|
-
- 📚 **Preserve your detailed commit history**
|
|
6
|
-
- ♻️ **Automatically synchronize each pull request in the stack**
|
|
7
6
|
- 💬 **Group commits for focused code review**
|
|
8
|
-
-
|
|
7
|
+
- 🌐 **Use the [official GitHub CLI](https://cli.github.com/)**
|
|
8
|
+
- ♻️ **Automatically synchronize each pull request in the stack**
|
|
9
9
|
- 💪 **Work seamlessly with GitHub's interface**
|
|
10
|
-
-
|
|
10
|
+
- 🚫 **Avoid juggling mutiple branches and complex rebasing**
|
|
11
|
+
- 📚 **Preserve your detailed commit history**
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
## Demo
|
|
13
15
|
|
|
14
|
-
> <img src="https://github.com/magus/git-multi-diff-playground/assets/290084/
|
|
16
|
+
> <img src="https://github.com/magus/git-multi-diff-playground/assets/290084/069c304b-80cb-49a9-9dc6-4ed3b061a5bc">
|
|
15
17
|
|
|
16
18
|
## Install
|
|
17
19
|
|
|
18
20
|
```bash
|
|
19
21
|
npm i -g git-stack-cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
20
26
|
|
|
27
|
+
```bash
|
|
21
28
|
git stack
|
|
22
|
-
```
|
|
23
29
|
|
|
30
|
+
git stack --verbose # print more detailed logs for debugging internals
|
|
31
|
+
git stack --no-verify # skip git hooks such as pre-commit and pre-push
|
|
32
|
+
|
|
33
|
+
git-stack --help # print a table of all command-line arguments
|
|
34
|
+
```
|
|
24
35
|
|
|
25
36
|
## Why?
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
Often pushing all your commits to a single pull request is the simplest and fastest approach to development.
|
|
29
|
-
However, there is a cost to this, your teammates have to review larger, less related pieces of code and you will lose some of your atomic commit history if you squahs and merge.
|
|
38
|
+
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**.
|
|
30
39
|
|
|
40
|
+
Often pushing all your commits to a single pull request is the simplest and fastest approach to development.
|
|
41
|
+
This comes at a price, your teammates have to review larger, less related pieces of code and you will lose some of your atomic commit history if you "Squash and merge".
|
|
31
42
|
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
When you decide to break changes up into multiple diffs that depend on one another this process is commonly referred to as **[stacked diffs](https://graphite.dev/guides/stacked-diffs)** (pull requests that depend on other pull requests).
|
|
44
|
+
This appraoch is popular at many major comparnies such as Twitter, Facebook, etc.
|
|
45
|
+
Managing stacked diffs manually involves managing multiple local branches, jumping between them, rebasing, etc.
|
|
34
46
|
This process gets even more complicated when you start getting feedback in code review and have to update individual branches.
|
|
35
47
|
Managing even a few stacked diffs requires a relatively strong knowledge of `git`, even with tricks like [`--update-refs`](https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt---update-refs).
|
|
36
48
|
|
|
37
|
-
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**.
|
|
38
49
|
|
|
39
50
|
## How is this different than **`x`**
|
|
40
51
|
|
|
@@ -17,9 +17,11 @@ export function LocalMergeRebase() {
|
|
|
17
17
|
async function run() {
|
|
18
18
|
const state = Store.getState();
|
|
19
19
|
const actions = state.actions;
|
|
20
|
+
const argv = state.argv;
|
|
20
21
|
const branch_name = state.branch_name;
|
|
21
22
|
const commit_range = state.commit_range;
|
|
22
23
|
const master_branch = state.master_branch;
|
|
24
|
+
invariant(argv, "argv must exist");
|
|
23
25
|
invariant(branch_name, "branch_name must exist");
|
|
24
26
|
invariant(commit_range, "commit_range must exist");
|
|
25
27
|
// always listen for SIGINT event and restore git state
|
|
@@ -51,7 +53,11 @@ async function run() {
|
|
|
51
53
|
commit_message: React.createElement(Brackets, null, commit.message),
|
|
52
54
|
} }));
|
|
53
55
|
}
|
|
54
|
-
|
|
56
|
+
const git_cherry_pick_command = [`git cherry-pick ${commit.sha}`];
|
|
57
|
+
if (argv.verify === false) {
|
|
58
|
+
git_cherry_pick_command.push("--no-verify");
|
|
59
|
+
}
|
|
60
|
+
await cli(git_cherry_pick_command);
|
|
55
61
|
if (commit.branch_id && !commit_pr) {
|
|
56
62
|
if (actions.isDebug()) {
|
|
57
63
|
actions.output(React.createElement(FormatText, { wrapper: React.createElement(Ink.Text, { color: colors.yellow, wrap: "truncate-end" }), message: "Cleaning up unused group {group}", values: {
|
package/dist/app/ManualRebase.js
CHANGED
|
@@ -57,7 +57,11 @@ async function run(props) {
|
|
|
57
57
|
const selected_url = get_group_url(group);
|
|
58
58
|
// cherry-pick and amend commits one by one
|
|
59
59
|
for (const commit of group.commits) {
|
|
60
|
-
|
|
60
|
+
const git_cherry_pick_command = [`git cherry-pick ${commit.sha}`];
|
|
61
|
+
if (argv.verify === false) {
|
|
62
|
+
git_cherry_pick_command.push("--no-verify");
|
|
63
|
+
}
|
|
64
|
+
await cli(git_cherry_pick_command);
|
|
61
65
|
if (commit.branch_id !== group.id) {
|
|
62
66
|
const new_message = await Metadata.write(commit.message, group.id);
|
|
63
67
|
await cli(`git commit --amend -m "${new_message}"`);
|
|
@@ -72,7 +76,7 @@ async function run(props) {
|
|
|
72
76
|
if (argv.verify === false) {
|
|
73
77
|
git_push_command.push("--no-verify");
|
|
74
78
|
}
|
|
75
|
-
await cli(git_push_command
|
|
79
|
+
await cli(git_push_command);
|
|
76
80
|
if (group.pr) {
|
|
77
81
|
// ensure base matches pr in github
|
|
78
82
|
await github.pr_edit({
|
package/dist/command.js
CHANGED
|
@@ -19,13 +19,13 @@ export async function command() {
|
|
|
19
19
|
.option("verify", {
|
|
20
20
|
type: "boolean",
|
|
21
21
|
default: true,
|
|
22
|
-
description: "
|
|
22
|
+
description: "Skip git hooks such as pre-commit and pre-push",
|
|
23
23
|
})
|
|
24
24
|
.option("verbose", {
|
|
25
25
|
type: "boolean",
|
|
26
26
|
alias: ["v"],
|
|
27
27
|
default: false,
|
|
28
|
-
description: "
|
|
28
|
+
description: "Print more detailed logs for debugging internals",
|
|
29
29
|
})
|
|
30
30
|
.option("branch", {
|
|
31
31
|
type: "string",
|
package/dist/core/cli.js
CHANGED
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import * as child from "node:child_process";
|
|
2
2
|
import { Store } from "../app/Store.js";
|
|
3
|
-
export async function cli(
|
|
3
|
+
export async function cli(unsafe_command, unsafe_options) {
|
|
4
4
|
const state = Store.getState();
|
|
5
5
|
const options = Object.assign({}, unsafe_options);
|
|
6
|
+
let command;
|
|
7
|
+
if (Array.isArray(unsafe_command)) {
|
|
8
|
+
command = unsafe_command.join(" ");
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
command = unsafe_command;
|
|
12
|
+
}
|
|
6
13
|
return new Promise((resolve, reject) => {
|
|
7
14
|
const childProcess = child.spawn("sh", ["-c", command], options);
|
|
8
15
|
let stdout = "";
|