gflows 0.1.1
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/LICENSE +21 -0
- package/README.md +549 -0
- package/package.json +38 -0
- package/src/cli.ts +358 -0
- package/src/commands/bump.ts +213 -0
- package/src/commands/completion.ts +353 -0
- package/src/commands/delete.ts +133 -0
- package/src/commands/finish.ts +275 -0
- package/src/commands/help.ts +53 -0
- package/src/commands/init.ts +70 -0
- package/src/commands/list.ts +89 -0
- package/src/commands/start.ts +141 -0
- package/src/commands/status.ts +137 -0
- package/src/commands/switch.ts +102 -0
- package/src/commands/version.ts +27 -0
- package/src/config.ts +229 -0
- package/src/constants.ts +38 -0
- package/src/errors.ts +96 -0
- package/src/git.ts +481 -0
- package/src/index.ts +84 -0
- package/src/types.ts +124 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Ali AlNaghmoush (https://github.com/alialnaghmoush)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,549 @@
|
|
|
1
|
+
# gflows
|
|
2
|
+
|
|
3
|
+
A lightweight CLI for consistent Git branching workflows: long-lived **main** (production) and **dev** (integration), plus short-lived workflow branches with clear merge targets. Built for [Bun](https://bun.sh) and TypeScript; **scriptable** and **safe by default**—no history rewriting, predictable exit codes, and optional interactive pickers only when running in a TTY.
|
|
4
|
+
|
|
5
|
+
**Author:** [Ali AlNaghmoush](https://github.com/alialnaghmoush) · **Repository:** [github.com/alialnaghmoush/gflows](https://github.com/alialnaghmoush/gflows)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Table of contents
|
|
10
|
+
|
|
11
|
+
- [Prerequisites](#prerequisites)
|
|
12
|
+
- [Installation](#installation)
|
|
13
|
+
- [Concepts](#concepts)
|
|
14
|
+
- [Quick start](#quick-start)
|
|
15
|
+
- [Command reference](#command-reference)
|
|
16
|
+
- [Branch types in detail](#branch-types-in-detail)
|
|
17
|
+
- [Configuration](#configuration)
|
|
18
|
+
- [Scripting and CI](#scripting-and-ci)
|
|
19
|
+
- [Exit codes](#exit-codes)
|
|
20
|
+
- [Troubleshooting](#troubleshooting)
|
|
21
|
+
- [Shell completion](#shell-completion)
|
|
22
|
+
- [Publishing (maintainers)](#publishing-maintainers)
|
|
23
|
+
- [License](#license)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Prerequisites
|
|
28
|
+
|
|
29
|
+
- **Bun** ≥ 1.0 (recommended). The CLI runs TypeScript directly; no separate build step.
|
|
30
|
+
- **Git** for all repository operations.
|
|
31
|
+
|
|
32
|
+
Check versions:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
bun --version
|
|
36
|
+
git --version
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
**From the repository (development or link):**
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
git clone https://github.com/alialnaghmoush/gflows.git
|
|
47
|
+
cd gflows
|
|
48
|
+
bun install
|
|
49
|
+
bun link # global `gflows` (or: npm link)
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
**Run without installing** (from repo root):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bun run gflows -- <command> ...
|
|
56
|
+
# or
|
|
57
|
+
bun run src/cli.ts -- <command> ...
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**After linking**, use `gflows` from any Git repository:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
cd /path/to/your/repo
|
|
64
|
+
gflows init
|
|
65
|
+
gflows start feature my-feature
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Concepts
|
|
71
|
+
|
|
72
|
+
- **main** — Long-lived production branch. Default name: `main`. Only release and hotfix branches merge here.
|
|
73
|
+
- **dev** — Long-lived integration branch. Default name: `dev`. Feature, bugfix, chore, and spike branches merge here. Created by `gflows init` from `main`.
|
|
74
|
+
- **Workflow branches** — Short-lived branches with a type prefix (e.g. `feature/`, `bugfix/`, `release/`). Each type has a **base** branch and **merge target(s)**. gflows never rewrites history (no rebase by default).
|
|
75
|
+
- **Merge targets** — Where `gflows finish` merges:
|
|
76
|
+
- **feature / chore / spike** → `dev` only.
|
|
77
|
+
- **bugfix** → `dev` (or `main` if the bugfix was started from main with `-o main`).
|
|
78
|
+
- **release** → `main` first, then `main` is merged into `dev`; a tag is created.
|
|
79
|
+
- **hotfix** → `main` first, then `main` is merged into `dev`; a tag is created.
|
|
80
|
+
|
|
81
|
+
You can override branch names and prefixes via [configuration](#configuration).
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Quick start
|
|
86
|
+
|
|
87
|
+
**1. One-time setup** in your repo (ensure `main` exists and create `dev`):
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
gflows init
|
|
91
|
+
gflows init --push # also push dev to origin
|
|
92
|
+
gflows init --dry-run # show what would be done, no writes
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**2. Daily development** (feature → dev):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
gflows start feature add-login
|
|
99
|
+
# ... code, commit ...
|
|
100
|
+
gflows finish feature # merge into dev
|
|
101
|
+
gflows finish feature --push # merge and push dev
|
|
102
|
+
gflows finish feature --push -D # merge, push, and delete local branch
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
**3. Release** (dev → main, then tag):
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
gflows bump up minor # e.g. 1.2.3 → 1.3.0
|
|
109
|
+
gflows start release v1.3.0
|
|
110
|
+
# ... update CHANGELOG, commit ...
|
|
111
|
+
gflows finish release --push # merge to main, then dev; tag v1.3.0; push
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**4. Hotfix** (main → fix → main + dev):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
gflows start hotfix v1.3.1
|
|
118
|
+
# ... fix, commit ...
|
|
119
|
+
gflows finish hotfix --push # merge to main, then dev; tag v1.3.1; push
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## Command reference
|
|
125
|
+
|
|
126
|
+
### Summary table
|
|
127
|
+
|
|
128
|
+
| Command | Short | Description |
|
|
129
|
+
|-------------|-------|--------------|
|
|
130
|
+
| `init` | `-I` | Ensure main exists; create dev from main. |
|
|
131
|
+
| `start` | `-S` | Create a workflow branch (requires type + name). |
|
|
132
|
+
| `finish` | `-F` | Merge branch into target(s), optional tag (release/hotfix), delete, push. |
|
|
133
|
+
| `switch` | `-W` | Switch to a workflow branch (picker or name). |
|
|
134
|
+
| `delete` | `-L` | Delete local workflow branch(es). Never main/dev. |
|
|
135
|
+
| `list` | `-l` | List workflow branches; optional type filter and remote. |
|
|
136
|
+
| `bump` | — | Bump or rollback package version (patch/minor/major). |
|
|
137
|
+
| `completion` | — | Print shell completion script (bash \| zsh \| fish). |
|
|
138
|
+
| `status` | `-t` | Show current branch, type, base, merge target(s), ahead/behind. |
|
|
139
|
+
| `help` | `-h` | Show usage and quick reference. |
|
|
140
|
+
| `version` | `-V` | Show version. |
|
|
141
|
+
|
|
142
|
+
**Branch types (for start/finish/list):** `feature` (`-f`), `bugfix` (`-b`), `chore` (`-c`), `release` (`-r`), `hotfix` (`-x`), `spike` (`-e`).
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### init
|
|
147
|
+
|
|
148
|
+
Ensures the **main** branch exists (exits with error if not). Creates **dev** from main if it does not exist; does nothing if dev already exists. Does not rewrite or force-push.
|
|
149
|
+
|
|
150
|
+
**Examples:**
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
gflows init
|
|
154
|
+
gflows init --push # push dev to remote after creating
|
|
155
|
+
gflows init -C ../other-repo # run in another directory
|
|
156
|
+
gflows init --dry-run # log intended actions only
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Flags:** `--push`, `-C`/`--path <dir>`, `--dry-run`, `-v`/`--verbose`, `-q`/`--quiet`.
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### start
|
|
164
|
+
|
|
165
|
+
Creates a new workflow branch from the correct base. **Requires** type and name (e.g. `start feature my-feat`). For **release** and **hotfix**, the name must be a version: `vX.Y.Z` or `X.Y.Z` (e.g. `v1.2.0`).
|
|
166
|
+
|
|
167
|
+
**Pre-checks:** Repository is Git; not detached HEAD; no rebase/merge in progress; working tree clean (unless `--force`); base branch exists (local or after fetch).
|
|
168
|
+
|
|
169
|
+
**Examples:**
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
gflows start feature auth-refactor
|
|
173
|
+
gflows start -f auth-refactor # same (short type)
|
|
174
|
+
gflows start bugfix fix-login --from main # bugfix from main instead of dev
|
|
175
|
+
gflows start release v2.0.0
|
|
176
|
+
gflows start hotfix 1.2.1 # "v" is optional for version
|
|
177
|
+
gflows start feature wip --force # allow uncommitted changes
|
|
178
|
+
gflows start feature api-v2 --push # create branch and push to remote
|
|
179
|
+
gflows start chore deps-update -C ./backend # run in subdirectory
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**Flags:** `--force` (allow dirty working tree), `--push`, `-o`/`--from <branch>` (base override, e.g. `-o main` for bugfix), `-R`/`--remote`, `-C`/`--path`, `--dry-run`, `-v`, `-q`.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
### finish
|
|
187
|
+
|
|
188
|
+
Merges the current workflow branch (or the one given with `-B`) into its merge target(s). For **release** and **hotfix**, merges into main first, then merges main into dev and creates a tag. Uses normal merge; use `--no-ff` to always create a merge commit. On **merge conflict**, gflows exits with a clear message and does not complete the merge—you resolve conflicts manually, then run `git merge --continue` or re-run `gflows finish` as needed.
|
|
189
|
+
|
|
190
|
+
**Pre-checks:** Not detached HEAD; no rebase/merge in progress; current branch (or `-B` target) is not main or dev; for release/hotfix, tag does not already exist.
|
|
191
|
+
|
|
192
|
+
**Examples:**
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
gflows finish feature # merge current branch (feature/xyz) into dev
|
|
196
|
+
gflows finish feature -B feature/auth # finish branch feature/auth
|
|
197
|
+
gflows finish feature --no-ff # always create a merge commit
|
|
198
|
+
gflows finish feature --push -D # merge, push, delete local branch
|
|
199
|
+
gflows finish release --push # merge to main, then dev; tag; push
|
|
200
|
+
gflows finish hotfix -s # sign the tag (GPG)
|
|
201
|
+
gflows finish hotfix -T # no tag (e.g. abandon hotfix as release)
|
|
202
|
+
gflows finish -y # skip "Delete branch after finish?" prompt (use default)
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Branch resolution:** If you omit the branch name, gflows uses the current branch. With `-B` and no value in a TTY, it shows a picker of workflow branches. Without a TTY, you must pass the branch name explicitly.
|
|
206
|
+
|
|
207
|
+
**Flags:** `-B`/`--branch <name>`, `--no-ff`, `-D`/`--delete` (delete branch after finish), `-N`/`--no-delete`, `--push`, `-s`/`--sign`, `-T`/`--no-tag`, `-M`/`--tag-message`, `-m`/`--message`, `-y`/`--yes`, `-C`, `--dry-run`, `-v`, `-q`.
|
|
208
|
+
|
|
209
|
+
---
|
|
210
|
+
|
|
211
|
+
### switch
|
|
212
|
+
|
|
213
|
+
Switches to a workflow branch. With a **TTY** and no branch name, shows an interactive **picker** of local workflow branches. Otherwise you must pass the branch name as a positional.
|
|
214
|
+
|
|
215
|
+
**Examples:**
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
gflows switch # picker (if TTY)
|
|
219
|
+
gflows switch feature/auth-refactor
|
|
220
|
+
gflows -W feature/auth-refactor # same with short command
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
**Flags:** `-C`/`--path`, `-v`, `-q`.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
### delete
|
|
228
|
+
|
|
229
|
+
Deletes **local** workflow branch(es). Never deletes the configured main or dev. With a **TTY** and no names, shows a picker (or multi-select if supported). Otherwise pass one or more branch names as positionals.
|
|
230
|
+
|
|
231
|
+
**Examples:**
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
gflows delete # picker (if TTY)
|
|
235
|
+
gflows delete feature/old-spike
|
|
236
|
+
gflows delete feature/one feature/two # delete multiple
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
**Flags:** `-C`/`--path`, `-v`, `-q`.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### list
|
|
244
|
+
|
|
245
|
+
Lists workflow branches (those matching configured prefixes). Output is **one branch per line** to stdout for scripting. Optionally filter by type; optionally include remote-tracking branches (with `-r`/`--include-remote`, which may run `git fetch` first).
|
|
246
|
+
|
|
247
|
+
**Examples:**
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
gflows list # all local workflow branches
|
|
251
|
+
gflows list feature # only feature/* branches
|
|
252
|
+
gflows list -r # include remote-tracking branches
|
|
253
|
+
gflows list -r feature # remote + local feature branches
|
|
254
|
+
gflows list --include-remote
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
**Flags:** `-r`/`--include-remote`, `-C`/`--path`, `--dry-run`, `-v`, `-q`.
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### bump
|
|
262
|
+
|
|
263
|
+
Bumps or rolls back the **root** package version (reads `package.json` from cwd or `-C`). Keeps `package.json` and `jsr.json` in sync; **no git operations** (no commit or tag). Useful before `gflows start release vX.Y.Z`.
|
|
264
|
+
|
|
265
|
+
**Positionals:** direction `up` | `down`, type `patch` | `minor` | `major`. When both are omitted and stdin is a TTY, shows interactive selects. When not a TTY, both are required.
|
|
266
|
+
|
|
267
|
+
**Examples:**
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
gflows bump up patch # 1.2.3 → 1.2.4
|
|
271
|
+
gflows bump up minor # 1.2.3 → 1.3.0
|
|
272
|
+
gflows bump up major # 1.2.3 → 2.0.0
|
|
273
|
+
gflows bump down patch # 1.2.4 → 1.2.3 (floor at 0)
|
|
274
|
+
gflows bump down minor # 1.3.0 → 1.2.0
|
|
275
|
+
gflows bump # interactive (direction + type) when TTY
|
|
276
|
+
gflows bump --dry-run # print old → new, no file writes
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
**Flags:** `--dry-run`, `-C`/`--path`, `-v`, `-q`.
|
|
280
|
+
|
|
281
|
+
---
|
|
282
|
+
|
|
283
|
+
### status
|
|
284
|
+
|
|
285
|
+
Shows current branch, its **classification** (feature, bugfix, chore, release, hotfix, spike, main, dev, or unknown), **base** branch, **merge target(s)**, and **ahead/behind** vs base. No write operations; safe to run anytime.
|
|
286
|
+
|
|
287
|
+
**Examples:**
|
|
288
|
+
|
|
289
|
+
```bash
|
|
290
|
+
gflows status
|
|
291
|
+
gflows -t
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
**Flags:** `-C`/`--path`, `-v`, `-q`.
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
### completion
|
|
299
|
+
|
|
300
|
+
Prints the shell completion script. Use with `source` (bash/zsh) or pipe into your shell (fish) to enable tab-completion for commands, types, and branch names.
|
|
301
|
+
|
|
302
|
+
**Examples:** See [Shell completion](#shell-completion).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
### help & version
|
|
307
|
+
|
|
308
|
+
```bash
|
|
309
|
+
gflows help
|
|
310
|
+
gflows -h
|
|
311
|
+
gflows version
|
|
312
|
+
gflows -V
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Branch types in detail
|
|
318
|
+
|
|
319
|
+
| Type | Short | Base (default) | With `-o main` | Merge target(s) | Tag |
|
|
320
|
+
|----------|-------|------------------|-----------------|------------------------|-------|
|
|
321
|
+
| feature | `-f` | dev | — | dev | no |
|
|
322
|
+
| bugfix | `-b` | dev | main | dev (or main if from main) | no |
|
|
323
|
+
| chore | `-c` | dev | — | dev | no |
|
|
324
|
+
| release | `-r` | dev | — | main, then dev | yes |
|
|
325
|
+
| hotfix | `-x` | main | — | main, then dev | yes |
|
|
326
|
+
| spike | `-e` | dev | — | dev | no |
|
|
327
|
+
|
|
328
|
+
- **feature** — New functionality; branches from dev, merges to dev.
|
|
329
|
+
- **bugfix** — Bug fixes. Usually from dev → dev. Use `-o main` when fixing a bug on production (branch from main, merge to main then dev).
|
|
330
|
+
- **chore** — Tasks that don’t change behavior (deps, tooling, docs). dev → dev.
|
|
331
|
+
- **release** — Prepare a release from dev: merge to main, then merge main into dev, create tag (e.g. `v1.2.0`). Name must be a version: `vX.Y.Z` or `X.Y.Z`.
|
|
332
|
+
- **hotfix** — Urgent fix from production (main). Merge to main, then main into dev; tag. Name must be a version.
|
|
333
|
+
- **spike** — Short-lived experiment; dev → dev, no tag. Discard or merge as needed.
|
|
334
|
+
|
|
335
|
+
**Naming:** Branch names use prefixes by default: `feature/add-login`, `bugfix/fix-login`, `release/v1.0.0`, `hotfix/v1.0.1`, `chore/update-deps`, `spike/try-cache`. Prefixes can be overridden in [configuration](#configuration). Invalid branch names (e.g. containing `..`, `*`, spaces) are rejected with exit code 1.
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
## Configuration
|
|
340
|
+
|
|
341
|
+
Configuration is **optional**. Override branch names, remote, and branch **prefixes** when needed.
|
|
342
|
+
|
|
343
|
+
**Resolution order** (later overrides earlier):
|
|
344
|
+
|
|
345
|
+
1. Built-in defaults (`main`, `dev`, `origin`, and default prefixes).
|
|
346
|
+
2. Repo config file: **`.gflows.json`** in repo root, or **`gflows`** key in **`package.json`**.
|
|
347
|
+
3. Environment: **`GFLOWS_MAIN`**, **`GFLOWS_DEV`**, **`GFLOWS_REMOTE`**.
|
|
348
|
+
4. CLI (e.g. `-R`/`--remote` for push).
|
|
349
|
+
|
|
350
|
+
Only include keys you want to override; the rest stay default. Invalid or malformed config is ignored (with an optional warning when using `-v`).
|
|
351
|
+
|
|
352
|
+
### Example: `.gflows.json` (full)
|
|
353
|
+
|
|
354
|
+
```json
|
|
355
|
+
{
|
|
356
|
+
"main": "main",
|
|
357
|
+
"dev": "dev",
|
|
358
|
+
"remote": "origin",
|
|
359
|
+
"prefixes": {
|
|
360
|
+
"feature": "feature/",
|
|
361
|
+
"bugfix": "bugfix/",
|
|
362
|
+
"chore": "chore/",
|
|
363
|
+
"release": "release/",
|
|
364
|
+
"hotfix": "hotfix/",
|
|
365
|
+
"spike": "spike/"
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Example: minimal override (different branch names)
|
|
371
|
+
|
|
372
|
+
```json
|
|
373
|
+
{
|
|
374
|
+
"main": "master",
|
|
375
|
+
"dev": "develop"
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
### Example: custom prefixes only
|
|
380
|
+
|
|
381
|
+
```json
|
|
382
|
+
{
|
|
383
|
+
"prefixes": {
|
|
384
|
+
"feature": "feat/",
|
|
385
|
+
"bugfix": "fix/"
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Example: `package.json` key
|
|
391
|
+
|
|
392
|
+
```json
|
|
393
|
+
{
|
|
394
|
+
"name": "my-app",
|
|
395
|
+
"version": "1.0.0",
|
|
396
|
+
"gflows": {
|
|
397
|
+
"main": "main",
|
|
398
|
+
"dev": "development",
|
|
399
|
+
"remote": "upstream"
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Environment variables
|
|
405
|
+
|
|
406
|
+
```bash
|
|
407
|
+
export GFLOWS_MAIN=main
|
|
408
|
+
export GFLOWS_DEV=develop
|
|
409
|
+
export GFLOWS_REMOTE=origin
|
|
410
|
+
gflows init
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## Scripting and CI
|
|
416
|
+
|
|
417
|
+
- **Non-interactive:** When stdin is **not** a TTY, gflows does **not** show pickers (e.g. for switch, delete, or finish `-B`). You must pass branch names explicitly or the command exits with a clear message (exit code 1).
|
|
418
|
+
- **Skip confirmations:** Use **`-y`/`--yes`** to accept defaults (e.g. "Delete branch after finish?" → no delete unless you also passed `-D`).
|
|
419
|
+
- **Exit codes:** Use them in scripts: `0` success, `1` usage/validation, `2` Git/system error.
|
|
420
|
+
|
|
421
|
+
**Examples:**
|
|
422
|
+
|
|
423
|
+
```bash
|
|
424
|
+
# Require explicit branch when not TTY
|
|
425
|
+
gflows finish feature -B feature/add-login --push -y
|
|
426
|
+
|
|
427
|
+
# List branches for parsing (one per line)
|
|
428
|
+
gflows list feature | while read -r b; do echo "Branch: $b"; done
|
|
429
|
+
|
|
430
|
+
# CI: fail fast on error
|
|
431
|
+
set -e
|
|
432
|
+
gflows start feature ci-job --force
|
|
433
|
+
# ... run tests ...
|
|
434
|
+
gflows finish feature -B feature/ci-job -y
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
**Path:** Use `-C`/`--path` so all git and config resolution use that directory:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
gflows -C /var/lib/repos/my-app status
|
|
441
|
+
gflows -C ./packages/api list
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Exit codes
|
|
447
|
+
|
|
448
|
+
| Code | Meaning | Typical causes |
|
|
449
|
+
|------|---------|-----------------|
|
|
450
|
+
| **0** | Success | Command completed without error. |
|
|
451
|
+
| **1** | Usage / validation | Missing type or name for `start`; invalid branch name or version format; wrong/missing positionals for non-TTY. |
|
|
452
|
+
| **2** | Git / system | Not a Git repo; branch not found; dirty working tree (start without `--force`); merge conflict on finish; rebase/merge in progress; detached HEAD; finish on main/dev; tag already exists; push failed after merge. |
|
|
453
|
+
|
|
454
|
+
**Validation (exit 1):** Invalid version (e.g. `start release foo`), invalid branch name (e.g. `feature/bad..name`), or missing required args in non-interactive mode.
|
|
455
|
+
|
|
456
|
+
**Git/state (exit 2):** Repository issues, branch missing, merge conflicts (user must resolve manually), or guards (e.g. cannot finish main/dev, cannot delete main/dev).
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## Troubleshooting
|
|
461
|
+
|
|
462
|
+
| Situation | What to do |
|
|
463
|
+
|-----------|------------|
|
|
464
|
+
| **"Not a Git repository"** | Run from a directory that contains `.git`, or use `-C <path>` to point to the repo root. |
|
|
465
|
+
| **"Working tree has uncommitted changes"** | Commit or stash changes before `start`, or use `--force` (only when you intend to carry uncommitted work). |
|
|
466
|
+
| **"Merge conflict while merging into …"** | Resolve conflicts in your working tree, then run `git add` and `git merge --continue` (or `git merge --abort` to cancel). Re-run `gflows finish` after resolving if needed. |
|
|
467
|
+
| **"Tag v1.2.3 already exists"** | Use a new version for the release/hotfix, or delete/move the tag if you know what you’re doing. gflows does not overwrite tags. |
|
|
468
|
+
| **"Cannot finish the long-lived branch main/dev"** | You’re on main or dev. Checkout a workflow branch first, or use `-B <branch>` to finish another branch. |
|
|
469
|
+
| **"HEAD is detached"** | Checkout a branch (e.g. `git checkout dev`) before running `start` or `finish`. |
|
|
470
|
+
| **"A rebase or merge is in progress"** | Run `git rebase --abort` or `git merge --abort`, or complete the operation, then retry gflows. |
|
|
471
|
+
| **Picker not showing / "requires branch name"** | Without a TTY, gflows does not show interactive pickers. Pass the branch name explicitly (e.g. `-B feature/xyz` or `gflows switch feature/xyz`). |
|
|
472
|
+
| **Wrong remote or branch names** | Set `GFLOWS_MAIN`, `GFLOWS_DEV`, `GFLOWS_REMOTE` or use `.gflows.json` / `package.json` "gflows" key. Use `-R` for one-off remote override. |
|
|
473
|
+
|
|
474
|
+
Use **`-v`/`--verbose`** to see git commands and extra diagnostics; combine with the error message to pinpoint the cause.
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
## Shell completion
|
|
479
|
+
|
|
480
|
+
Generate and install completion so you can tab-complete commands, types, and (where applicable) branch names.
|
|
481
|
+
|
|
482
|
+
**Bash:**
|
|
483
|
+
|
|
484
|
+
```bash
|
|
485
|
+
source <(gflows completion bash)
|
|
486
|
+
# Or persist:
|
|
487
|
+
echo 'source <(gflows completion bash)' >> ~/.bashrc
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
**Zsh:**
|
|
491
|
+
|
|
492
|
+
```bash
|
|
493
|
+
source <(gflows completion zsh)
|
|
494
|
+
# Or persist:
|
|
495
|
+
echo 'source <(gflows completion zsh)' >> ~/.zshrc
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
**Fish:**
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
gflows completion fish | source
|
|
502
|
+
# Or persist:
|
|
503
|
+
gflows completion fish > ~/.config/fish/completions/gflows.fish
|
|
504
|
+
```
|
|
505
|
+
|
|
506
|
+
Completion covers: **commands** (init, start, finish, switch, delete, list, bump, completion, status, help, version), **types** (feature, bugfix, chore, release, hotfix, spike), and **branch names** from local workflow branches when the context expects a branch (e.g. after `switch` or `finish -B`).
|
|
507
|
+
|
|
508
|
+
---
|
|
509
|
+
|
|
510
|
+
## Publishing (maintainers)
|
|
511
|
+
|
|
512
|
+
Publishing is done with the **internal script** `scripts/publish.ts`. It syncs the version from **package.json** to **jsr.json**, then publishes to **npm** and/or **JSR**. The script is not part of the published package (`files` excludes `scripts/`).
|
|
513
|
+
|
|
514
|
+
### Commands
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
bun run publish # publish to npm and JSR (same version)
|
|
518
|
+
bun run publish -- --dry-run # sync version only; print intended commands; no publish
|
|
519
|
+
bun run publish -- --npm-only # publish only to npm
|
|
520
|
+
bun run publish -- --jsr-only # publish only to JSR
|
|
521
|
+
bun run publish -- --force # skip pre-publish checks (clean tree, branch main)
|
|
522
|
+
```
|
|
523
|
+
|
|
524
|
+
### Typical release workflow
|
|
525
|
+
|
|
526
|
+
1. Ensure you’re on **main** with a clean working tree (or use `--force` when intentional).
|
|
527
|
+
2. Bump version and tag in Git yourself, or use gflows bump + your own commit:
|
|
528
|
+
```bash
|
|
529
|
+
gflows bump up minor --dry-run # confirm
|
|
530
|
+
gflows bump up minor
|
|
531
|
+
git add package.json jsr.json && git commit -m "chore: bump to 1.4.0"
|
|
532
|
+
```
|
|
533
|
+
3. Run the publish script:
|
|
534
|
+
```bash
|
|
535
|
+
bun run publish -- --dry-run # verify
|
|
536
|
+
bun run publish
|
|
537
|
+
```
|
|
538
|
+
4. Optionally push main and tags:
|
|
539
|
+
```bash
|
|
540
|
+
git push origin main --tags
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
**Version sync:** The script reads `version` from **package.json** and writes it to **jsr.json** before publishing so the two registries never drift. Use **`gflows bump`** to change the version; the script does not bump for you.
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
## License
|
|
548
|
+
|
|
549
|
+
See [LICENSE](LICENSE) in this repository.
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "gflows",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "A lightweight CLI for consistent Git branching workflows (main + dev, feature/bugfix/chore/release/hotfix).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "src/index.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"gflows": "src/cli.ts"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "bun test",
|
|
12
|
+
"lint": "tsc --noEmit",
|
|
13
|
+
"gflows": "bun run src/cli.ts",
|
|
14
|
+
"publish": "bun run scripts/publish.ts",
|
|
15
|
+
"publish:npm": "bun run scripts/publish.ts -- --npm-only",
|
|
16
|
+
"publish:jsr": "bun run scripts/publish.ts -- --jsr-only"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"src",
|
|
20
|
+
"README.md",
|
|
21
|
+
"LICENSE"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"bun": ">=1.0.0"
|
|
25
|
+
},
|
|
26
|
+
"author": "Ali AlNaghmoush (https://github.com/alialnaghmoush)",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "git+https://github.com/alialnaghmoush/gflows.git"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@inquirer/prompts": "^8"
|
|
33
|
+
},
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@types/bun": "latest",
|
|
36
|
+
"typescript": "^5"
|
|
37
|
+
}
|
|
38
|
+
}
|