git-gx 0.2.0__tar.gz

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.
git_gx-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nate Landau
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.
git_gx-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.3
2
+ Name: git-gx
3
+ Version: 0.2.0
4
+ Summary: A CLI that wraps common git commands with sensible defaults, safety guards, and helpful summaries.
5
+ Author: Nate Landau
6
+ Author-email: Nate Landau <github@natenate.org>
7
+ License: MIT License
8
+
9
+ Copyright (c) 2026 Nate Landau
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
28
+ Classifier: Programming Language :: Python :: 3.13
29
+ Classifier: Programming Language :: Python :: 3.14
30
+ Requires-Dist: rich>=14.3.3
31
+ Requires-Dist: typer>=0.24.1
32
+ Requires-Python: >=3.13, <3.15
33
+ Description-Content-Type: text/markdown
34
+
35
+ # gx
36
+
37
+ A CLI that wraps common git commands with sensible defaults, safety guards, and helpful summaries.
38
+
39
+ ## Features
40
+
41
+ - Auto-numbered feature branches with optional worktree isolation
42
+ - Push with dirty-tree warnings and default-branch confirmation
43
+ - Pull with automatic stash/unstash and rebase
44
+ - Batch cleanup of merged, gone, and empty branches
45
+ - Rich status dashboard showing all branches at a glance
46
+ - Dry-run mode (`-n`) on every command
47
+
48
+ ## Installation
49
+
50
+ gx requires Python 3.13 or higher.
51
+
52
+ ```sh
53
+ # install via uv
54
+ uv tool install git-gx
55
+
56
+ # or install via pip
57
+ pip install git-gx
58
+ ```
59
+
60
+ ## Quick Start
61
+
62
+ ```sh
63
+ gx feat # create feat/1 from main
64
+ # ... make changes, commit ...
65
+ gx push # push to origin with tracking
66
+ # ... PR merged ...
67
+ gx done # checkout main, pull, delete feat/1
68
+ ```
69
+
70
+ ## Commands
71
+
72
+ Every command supports `-h` for help. All commands except `status` also support `-v`/`-vv` for verbosity and `-n` for dry-run.
73
+
74
+ ### `gx status`
75
+
76
+ Display a two-panel dashboard: a color-coded file tree of uncommitted changes and a table of all active branches with ahead/behind counts, file metrics, and stash counts. Running `gx` with no arguments inside a repo shows this dashboard automatically.
77
+
78
+ ```sh
79
+ gx status # full dashboard
80
+ gx status -F # file tree only
81
+ gx status -b # branch table only
82
+ gx status -a # include inactive branches
83
+ ```
84
+
85
+ ### `gx feat`
86
+
87
+ Create a new feature branch from the latest default branch. Without a name, branches are auto-numbered (`feat/1`, `feat/2`, ...), filling gaps in the sequence.
88
+
89
+ ```sh
90
+ gx feat # create feat/1 (or next available)
91
+ gx feat login # create feat/login
92
+ gx feat -w # create in a git worktree at .worktrees/feat/1
93
+ gx feat -w ui # create worktree at .worktrees/feat/ui
94
+ ```
95
+
96
+ Worktree mode (`-w`) lets you work on multiple branches simultaneously without stashing. Requires `.worktrees/` to be in `.gitignore`.
97
+
98
+ ### `gx push`
99
+
100
+ Push the current branch to its remote tracking branch (or `origin/<branch>` on first push). Automatically sets up tracking.
101
+
102
+ ```sh
103
+ gx push # push current branch
104
+ gx push -f # force push with --force-with-lease
105
+ gx push -t # push commits and all tags
106
+ ```
107
+
108
+ Safety guards:
109
+
110
+ - Warns about uncommitted or untracked files that won't be included
111
+ - Asks for confirmation before pushing to the default branch
112
+ - Uses `--force-with-lease` instead of `--force` to prevent overwriting others' work
113
+
114
+ ### `gx pull`
115
+
116
+ Fetch and rebase the current branch onto its upstream. Handles uncommitted changes automatically.
117
+
118
+ ```sh
119
+ gx pull # pull and rebase
120
+ gx pull -v # pull with debug output
121
+ ```
122
+
123
+ The full sequence:
124
+
125
+ 1. stash uncommitted changes
126
+ 2. fetch
127
+ 3. rebase
128
+ 4. update submodules (if `.gitmodules` exists)
129
+ 5. restore stash
130
+ 6. print a summary
131
+
132
+ If a rebase conflict occurs, gx restores your stash and prints resolution steps.
133
+
134
+ ### `gx clean`
135
+
136
+ Remove branches and worktrees that are no longer needed. Fetches with `--prune` first, then finds branches that are:
137
+
138
+ - **merged** into the default branch
139
+ - **gone** (upstream deleted on the remote)
140
+ - **empty** (zero commits ahead of the default branch)
141
+
142
+ ```sh
143
+ gx clean # interactive cleanup
144
+ gx clean -y # skip confirmation prompt
145
+ gx clean -f # include dirty worktrees
146
+ gx clean -n # preview what would be removed
147
+ ```
148
+
149
+ The current branch, `main`, `master`, and `develop` are always protected. Dirty worktrees are skipped unless you pass `--force`.
150
+
151
+ ### `gx done`
152
+
153
+ Post-merge cleanup. Checks out the default branch, pulls latest changes, and deletes the feature branch you were on.
154
+
155
+ ```sh
156
+ gx done # clean up after a merged PR
157
+ gx done -n # preview what would happen
158
+ ```
159
+
160
+ If run from a worktree, gx removes the worktree first, then switches to the main working directory.
161
+
162
+ ## Global Options
163
+
164
+ | Flag | Description |
165
+ | ------------------ | ------------------------------------------- |
166
+ | `-v` | Debug output (shows git commands) |
167
+ | `-vv` | Trace output (shows git stdout/stderr) |
168
+ | `-n` / `--dry-run` | Preview changes without executing mutations |
169
+ | `-h` / `--help` | Show help for any command |
170
+
171
+ ## Configuration
172
+
173
+ gx works out of the box with no configuration. Optionally, create `~/.config/gx/config.toml` to customize defaults:
174
+
175
+ ```toml
176
+ [branches]
177
+ prefix = "feat" # branch prefix for `gx feat`
178
+ protected = ["main", "master", "develop"] # branches protected from cleanup
179
+
180
+ [worktree]
181
+ directory = ".worktrees" # worktree base directory
182
+
183
+ [remote]
184
+ name = "origin" # default remote name
185
+ ```
186
+
187
+ All keys are optional - only specify the ones you want to change.
188
+
189
+ ### Worktree directory
190
+
191
+ The worktree directory can be relative or absolute:
192
+
193
+ - **Relative** (e.g. `.worktrees`) - resolved from the repo root. Must be in `.gitignore`.
194
+ - **Absolute** (e.g. `~/tmp/worktrees`) - used as-is. No `.gitignore` requirement.
195
+
196
+ ### Environment variables
197
+
198
+ Override any setting per-invocation with environment variables:
199
+
200
+ | Variable | Example |
201
+ | ----------------------- | ------------------------------------------------ |
202
+ | `GX_BRANCH_PREFIX` | `GX_BRANCH_PREFIX=fix gx feat` |
203
+ | `GX_WORKTREE_DIRECTORY` | `GX_WORKTREE_DIRECTORY=~/wt gx feat -w` |
204
+ | `GX_PROTECTED_BRANCHES` | `GX_PROTECTED_BRANCHES=main,production gx clean` |
205
+ | `GX_REMOTE_NAME` | `GX_REMOTE_NAME=upstream gx push` |
206
+
207
+ Environment variables take priority over the config file.
208
+
209
+ ## License
210
+
211
+ MIT
git_gx-0.2.0/README.md ADDED
@@ -0,0 +1,177 @@
1
+ # gx
2
+
3
+ A CLI that wraps common git commands with sensible defaults, safety guards, and helpful summaries.
4
+
5
+ ## Features
6
+
7
+ - Auto-numbered feature branches with optional worktree isolation
8
+ - Push with dirty-tree warnings and default-branch confirmation
9
+ - Pull with automatic stash/unstash and rebase
10
+ - Batch cleanup of merged, gone, and empty branches
11
+ - Rich status dashboard showing all branches at a glance
12
+ - Dry-run mode (`-n`) on every command
13
+
14
+ ## Installation
15
+
16
+ gx requires Python 3.13 or higher.
17
+
18
+ ```sh
19
+ # install via uv
20
+ uv tool install git-gx
21
+
22
+ # or install via pip
23
+ pip install git-gx
24
+ ```
25
+
26
+ ## Quick Start
27
+
28
+ ```sh
29
+ gx feat # create feat/1 from main
30
+ # ... make changes, commit ...
31
+ gx push # push to origin with tracking
32
+ # ... PR merged ...
33
+ gx done # checkout main, pull, delete feat/1
34
+ ```
35
+
36
+ ## Commands
37
+
38
+ Every command supports `-h` for help. All commands except `status` also support `-v`/`-vv` for verbosity and `-n` for dry-run.
39
+
40
+ ### `gx status`
41
+
42
+ Display a two-panel dashboard: a color-coded file tree of uncommitted changes and a table of all active branches with ahead/behind counts, file metrics, and stash counts. Running `gx` with no arguments inside a repo shows this dashboard automatically.
43
+
44
+ ```sh
45
+ gx status # full dashboard
46
+ gx status -F # file tree only
47
+ gx status -b # branch table only
48
+ gx status -a # include inactive branches
49
+ ```
50
+
51
+ ### `gx feat`
52
+
53
+ Create a new feature branch from the latest default branch. Without a name, branches are auto-numbered (`feat/1`, `feat/2`, ...), filling gaps in the sequence.
54
+
55
+ ```sh
56
+ gx feat # create feat/1 (or next available)
57
+ gx feat login # create feat/login
58
+ gx feat -w # create in a git worktree at .worktrees/feat/1
59
+ gx feat -w ui # create worktree at .worktrees/feat/ui
60
+ ```
61
+
62
+ Worktree mode (`-w`) lets you work on multiple branches simultaneously without stashing. Requires `.worktrees/` to be in `.gitignore`.
63
+
64
+ ### `gx push`
65
+
66
+ Push the current branch to its remote tracking branch (or `origin/<branch>` on first push). Automatically sets up tracking.
67
+
68
+ ```sh
69
+ gx push # push current branch
70
+ gx push -f # force push with --force-with-lease
71
+ gx push -t # push commits and all tags
72
+ ```
73
+
74
+ Safety guards:
75
+
76
+ - Warns about uncommitted or untracked files that won't be included
77
+ - Asks for confirmation before pushing to the default branch
78
+ - Uses `--force-with-lease` instead of `--force` to prevent overwriting others' work
79
+
80
+ ### `gx pull`
81
+
82
+ Fetch and rebase the current branch onto its upstream. Handles uncommitted changes automatically.
83
+
84
+ ```sh
85
+ gx pull # pull and rebase
86
+ gx pull -v # pull with debug output
87
+ ```
88
+
89
+ The full sequence:
90
+
91
+ 1. stash uncommitted changes
92
+ 2. fetch
93
+ 3. rebase
94
+ 4. update submodules (if `.gitmodules` exists)
95
+ 5. restore stash
96
+ 6. print a summary
97
+
98
+ If a rebase conflict occurs, gx restores your stash and prints resolution steps.
99
+
100
+ ### `gx clean`
101
+
102
+ Remove branches and worktrees that are no longer needed. Fetches with `--prune` first, then finds branches that are:
103
+
104
+ - **merged** into the default branch
105
+ - **gone** (upstream deleted on the remote)
106
+ - **empty** (zero commits ahead of the default branch)
107
+
108
+ ```sh
109
+ gx clean # interactive cleanup
110
+ gx clean -y # skip confirmation prompt
111
+ gx clean -f # include dirty worktrees
112
+ gx clean -n # preview what would be removed
113
+ ```
114
+
115
+ The current branch, `main`, `master`, and `develop` are always protected. Dirty worktrees are skipped unless you pass `--force`.
116
+
117
+ ### `gx done`
118
+
119
+ Post-merge cleanup. Checks out the default branch, pulls latest changes, and deletes the feature branch you were on.
120
+
121
+ ```sh
122
+ gx done # clean up after a merged PR
123
+ gx done -n # preview what would happen
124
+ ```
125
+
126
+ If run from a worktree, gx removes the worktree first, then switches to the main working directory.
127
+
128
+ ## Global Options
129
+
130
+ | Flag | Description |
131
+ | ------------------ | ------------------------------------------- |
132
+ | `-v` | Debug output (shows git commands) |
133
+ | `-vv` | Trace output (shows git stdout/stderr) |
134
+ | `-n` / `--dry-run` | Preview changes without executing mutations |
135
+ | `-h` / `--help` | Show help for any command |
136
+
137
+ ## Configuration
138
+
139
+ gx works out of the box with no configuration. Optionally, create `~/.config/gx/config.toml` to customize defaults:
140
+
141
+ ```toml
142
+ [branches]
143
+ prefix = "feat" # branch prefix for `gx feat`
144
+ protected = ["main", "master", "develop"] # branches protected from cleanup
145
+
146
+ [worktree]
147
+ directory = ".worktrees" # worktree base directory
148
+
149
+ [remote]
150
+ name = "origin" # default remote name
151
+ ```
152
+
153
+ All keys are optional - only specify the ones you want to change.
154
+
155
+ ### Worktree directory
156
+
157
+ The worktree directory can be relative or absolute:
158
+
159
+ - **Relative** (e.g. `.worktrees`) - resolved from the repo root. Must be in `.gitignore`.
160
+ - **Absolute** (e.g. `~/tmp/worktrees`) - used as-is. No `.gitignore` requirement.
161
+
162
+ ### Environment variables
163
+
164
+ Override any setting per-invocation with environment variables:
165
+
166
+ | Variable | Example |
167
+ | ----------------------- | ------------------------------------------------ |
168
+ | `GX_BRANCH_PREFIX` | `GX_BRANCH_PREFIX=fix gx feat` |
169
+ | `GX_WORKTREE_DIRECTORY` | `GX_WORKTREE_DIRECTORY=~/wt gx feat -w` |
170
+ | `GX_PROTECTED_BRANCHES` | `GX_PROTECTED_BRANCHES=main,production gx clean` |
171
+ | `GX_REMOTE_NAME` | `GX_REMOTE_NAME=upstream gx push` |
172
+
173
+ Environment variables take priority over the config file.
174
+
175
+ ## License
176
+
177
+ MIT
@@ -0,0 +1,163 @@
1
+ [project]
2
+ authors = [{ name = "Nate Landau", email = "github@natenate.org" }]
3
+ classifiers = [
4
+ "Programming Language :: Python :: 3.13",
5
+ "Programming Language :: Python :: 3.14",
6
+ ]
7
+ dependencies = ["rich>=14.3.3", "typer>=0.24.1"]
8
+ description = "A CLI that wraps common git commands with sensible defaults, safety guards, and helpful summaries."
9
+ license = { file = "LICENSE" }
10
+ name = "git-gx"
11
+ readme = "README.md"
12
+ requires-python = ">=3.13,<3.15"
13
+ version = "0.2.0"
14
+
15
+ [project.scripts]
16
+ gx = "gx.cli:main"
17
+
18
+ [build-system]
19
+ build-backend = "uv_build"
20
+ requires = ["uv_build>=0.10.12,<0.11.0"]
21
+
22
+ [tool.uv.build-backend]
23
+ module-name = "gx"
24
+
25
+ [dependency-groups]
26
+ dev = [
27
+ "commitizen>=4.13.9",
28
+ "coverage>=7.13.5",
29
+ "duty>=1.9.0",
30
+ "prek>=0.3.6",
31
+ "pytest-clarity>=1.0.1",
32
+ "pytest-cov>=7.1.0",
33
+ "pytest-devtools>=1.0.0",
34
+ "pytest-mock>=3.15.1",
35
+ "pytest-repeat>=0.9.4",
36
+ "pytest-sugar>=1.1.1",
37
+ "pytest-xdist>=3.8.0",
38
+ "pytest>=9.0.2",
39
+ "ruff>=0.15.7",
40
+ "shellcheck-py>=0.11.0.1",
41
+ "ty>=0.0.24",
42
+ "typos>=1.44.0",
43
+ "yamllint>=1.38.0",
44
+ ]
45
+
46
+ [tool.commitizen]
47
+ bump_message = "bump(release): v$current_version → v$new_version"
48
+ changelog_merge_prerelease = true
49
+ tag_format = "v$version"
50
+ update_changelog_on_bump = true
51
+ version_files = ["src/gx/__init__.py:__version__"]
52
+ version_provider = "uv"
53
+
54
+ [tool.coverage.report] # https://coverage.readthedocs.io/en/latest/config.html#report
55
+ exclude_lines = [
56
+ 'def __repr__',
57
+ 'except [\w\s\._]+ as .*:',
58
+ 'if TYPE_CHECKING',
59
+ 'pragma: no cover',
60
+ ]
61
+ fail_under = 10
62
+ show_missing = true
63
+ skip_covered = true
64
+ skip_empty = true
65
+
66
+ [tool.coverage.run]
67
+ branch = true
68
+ command_line = "--module pytest"
69
+ data_file = ".cache/coverage"
70
+ omit = ["tests/*"]
71
+ source = ["src"]
72
+
73
+ [tool.coverage.xml]
74
+ output = ".cache/coverage.xml"
75
+
76
+ [tool.pytest.ini_options]
77
+
78
+ addopts = "--color=yes --doctest-modules --strict-config --strict-markers -n auto --dist loadfile"
79
+ cache_dir = ".cache/pytest"
80
+ columns = 120
81
+ filterwarnings = ['error', 'ignore:.*Pydantic.*:UserWarning', 'ignore::DeprecationWarning:']
82
+ markers = ["serial"]
83
+ set_columns = true
84
+ testpaths = ["tests"]
85
+ xfail_strict = true
86
+
87
+ [tool.ruff] # https://github.com/charliermarsh/ruff
88
+
89
+ exclude = [".cache", ".git", ".venv", "build", "dist", "reference"]
90
+ fix = true
91
+ line-length = 100
92
+ output-format = "grouped"
93
+ src = ["src", "tests"]
94
+ target-version = "py313"
95
+ [tool.ruff.lint]
96
+ ignore = [
97
+ "ANN002", # Missing type annotation for `*args`
98
+ "ANN003", # Missing type annotation for `**kwargs`
99
+ "ANN204", # missing return type annotation for special method `__init__`
100
+ # "B006", # mutable-argument-default
101
+ # "B008", # function-call-in-default-argument
102
+ "COM812", # Trailing comma missing"
103
+ "CPY001", # Missing copyright notice at top of file
104
+ "D107", # undocumented-public-init
105
+ "E501", # line-too-long
106
+ "PLC0415", # Imports should be at top of file
107
+ # "FBT001", # Boolean-typed positional argument in function definition
108
+ # "FBT002", # Boolean-typed positional argument in function definition
109
+ "FIX002", # Line contains TODO, consider resolving the issue
110
+ "S311", # suspicious-non-cryptographic-random-usage
111
+ "TD001", # invalid-todo-tag
112
+ "TD002", # Missing author in TODO
113
+ "TD003", # Missing issue link on the line following this TODO
114
+ ]
115
+ per-file-ignores = { "tests/**/*.py" = [
116
+ "A002",
117
+ "A003",
118
+ "ANN001", # Missing type annotation for function argument `cls`
119
+ "ANN002", # Missing type annotation for `*args`
120
+ "ANN003", # Missing type annotation for `**kwargs`
121
+ "ANN201", # Missing return type annotation
122
+ "ARG001", # Unused function argument
123
+ "ARG002", # Unused method argument
124
+ "ARG005", # Unused lambda argument
125
+ "D102",
126
+ "ERA001", # Commented out code
127
+ "F403",
128
+ "F405", # May be undefined from type imports
129
+ "FBT001", # Boolean-typed positional argument in function definition
130
+ "PGH003", # Use specific rule codes when ignoring type issues
131
+ "PLC0415", # Imports should be at top of file
132
+ "PLR0913",
133
+ "PLR2004",
134
+ "PLW0108", # Lambda may be unnecessary; consider inlining inner function
135
+ "S101",
136
+ "SLF001", # Calling private method
137
+ "W292", # No blank line at end of file - included b/c cursor struggles to add a trailing newline and burns through requests trying to fix this linting error.
138
+ ] }
139
+ select = ["ALL"]
140
+ unfixable = [
141
+ "ERA001", # Commented out code
142
+ "F401", # unused-import
143
+ "F841", # unused-variable
144
+ ]
145
+
146
+ [tool.ruff.lint.mccabe]
147
+ # Unlike Flake8, default to a complexity level of 10.
148
+ max-complexity = 10
149
+
150
+ [tool.ruff.lint.pydocstyle]
151
+ convention = "google"
152
+
153
+ [tool.ruff.lint.pylint]
154
+ max-args = 7
155
+
156
+ [tool.ruff.lint.flake8-annotations]
157
+ allow-star-arg-any = true
158
+
159
+ [tool.ruff.format]
160
+ indent-style = "space"
161
+ line-ending = "auto"
162
+ quote-style = "double"
163
+ skip-magic-trailing-comma = false
@@ -0,0 +1,3 @@
1
+ """GX - A CLI tool for managing Git repositories."""
2
+
3
+ __version__ = "0.2.0"
@@ -0,0 +1,85 @@
1
+ """GX CLI - A wrapper around common git commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import typer
6
+ from typer import rich_utils
7
+
8
+ from gx import __version__
9
+ from gx.commands import clean, done, feat, pull, push, status
10
+ from gx.lib.console import set_verbosity
11
+ from gx.lib.git import check_git_installed, git
12
+ from gx.lib.options import VERBOSE_OPTION
13
+
14
+ rich_utils.STYLE_HELPTEXT = "" # ty:ignore[invalid-assignment]
15
+ CONTEXT_SETTINGS = {"help_option_names": ["-h", "--help"]}
16
+
17
+
18
+ app = typer.Typer(rich_markup_mode="rich", context_settings=CONTEXT_SETTINGS)
19
+ app.add_typer(push.app, name="push")
20
+ app.add_typer(pull.app, name="pull")
21
+ app.add_typer(feat.app, name="feat")
22
+ app.add_typer(clean.app, name="clean")
23
+ app.add_typer(done.app, name="done")
24
+ app.add_typer(status.app, name="status")
25
+
26
+
27
+ def _version_callback(value: bool) -> None: # noqa: FBT001
28
+ """Print version and exit."""
29
+ if value:
30
+ typer.echo(f"gx {__version__}")
31
+ raise typer.Exit
32
+
33
+
34
+ def _is_git_repo() -> bool:
35
+ """Return True if the current directory is inside a git repository."""
36
+ result = git("rev-parse", "--is-inside-work-tree")
37
+ return result.success
38
+
39
+
40
+ @app.callback(invoke_without_command=True)
41
+ def callback(
42
+ ctx: typer.Context,
43
+ verbose: int = VERBOSE_OPTION,
44
+ _version: bool | None = typer.Option( # noqa: FBT001
45
+ None,
46
+ "--version",
47
+ "-V",
48
+ callback=_version_callback,
49
+ is_flag=True,
50
+ expose_value=False,
51
+ is_eager=True,
52
+ help="Show version and exit.",
53
+ ),
54
+ ) -> None:
55
+ """Streamline your git workflow.
56
+
57
+ GX wraps common git operations with sensible defaults, safety guards, and helpful summaries. Every command supports --dry-run and --verbose flags.
58
+
59
+ Run [bold]gx COMMAND -h[/bold] for details on a specific command.
60
+
61
+ [bold]Common workflows:[/bold]
62
+
63
+ Start a feature branch: gx feat
64
+ Push your work: gx push
65
+ Pull latest changes: gx pull
66
+ Clean stale branches: gx clean
67
+ Finish a merged PR: gx done
68
+ View status dashboard: gx status
69
+
70
+ Configure defaults in ~/.config/gx/config.toml
71
+ """
72
+ set_verbosity(verbose)
73
+ check_git_installed()
74
+ if ctx.invoked_subcommand is None:
75
+ if _is_git_repo():
76
+ status_cmd = getattr(ctx.command, "commands", {}).get("status")
77
+ if status_cmd:
78
+ ctx.invoke(status_cmd)
79
+ else:
80
+ typer.echo(ctx.get_help())
81
+
82
+
83
+ def main() -> None:
84
+ """Entry point for the gx CLI."""
85
+ app()
@@ -0,0 +1 @@
1
+ """Subcommand modules for gx."""