gitstow 0.2.8__tar.gz → 0.3.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.
- {gitstow-0.2.8 → gitstow-0.3.0}/.github/workflows/ci.yml +5 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/BACKLOG.md +2 -2
- {gitstow-0.2.8 → gitstow-0.3.0}/CHANGELOG.md +31 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/CLAUDE.md +19 -18
- {gitstow-0.2.8 → gitstow-0.3.0}/PKG-INFO +20 -18
- {gitstow-0.2.8 → gitstow-0.3.0}/README.md +8 -10
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/building/audit-2026-07-06.md +22 -22
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/user/commands.md +38 -31
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/user/getting-started.md +5 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/pyproject.toml +13 -9
- {gitstow-0.2.8 → gitstow-0.3.0}/scripts/release.sh +6 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/__init__.py +1 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/add.py +100 -34
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/config_cmd.py +6 -4
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/doctor.py +17 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/exec_cmd.py +4 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/export_cmd.py +75 -21
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/fetch.py +31 -68
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/helpers.py +22 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/list_cmd.py +4 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/main.py +0 -2
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/manage.py +4 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/onboard.py +2 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/open_cmd.py +25 -11
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/pull.py +46 -74
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/search.py +43 -30
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/serve.py +3 -2
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/status.py +43 -30
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/workspace_cmd.py +9 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/config.py +3 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/discovery.py +11 -7
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/git.py +22 -5
- gitstow-0.3.0/src/gitstow/core/operations.py +98 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/repo.py +32 -1
- gitstow-0.3.0/src/gitstow/core/status_model.py +119 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/mcp/server.py +85 -43
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/skill/SKILL.md +5 -3
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/collection.py +5 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/dashboard.py +57 -28
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/pages.py +10 -1
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/repos.py +53 -26
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/_repo_drawer.html +1 -9
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/dashboard.html +7 -7
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/partials/pull_summary.html +11 -0
- gitstow-0.3.0/tests/test_cli.py +885 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_config.py +9 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_git.py +22 -0
- gitstow-0.3.0/tests/test_mcp.py +138 -0
- gitstow-0.3.0/tests/test_operations.py +67 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_repo.py +51 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_serve.py +162 -0
- gitstow-0.3.0/tests/test_status_model.py +83 -0
- gitstow-0.2.8/src/gitstow/cli/tui.py +0 -27
- gitstow-0.2.8/src/gitstow/tui/__init__.py +0 -1
- gitstow-0.2.8/src/gitstow/tui/app.py +0 -384
- gitstow-0.2.8/tests/test_cli.py +0 -266
- {gitstow-0.2.8 → gitstow-0.3.0}/.claude/settings.json +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/.github/workflows/publish.yml +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/.gitignore +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/AGENTS.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/CODE_OF_CONDUCT.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/CONTRIBUTING.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/LICENSE +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/SECURITY.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/demo.gif +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/demo.tape +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/building/implementation-plan.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/building/plans/2026-07-06-wave-1-correctness-safety.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/building/plans/2026-07-06-wave-2-status-model.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/building/plans/2026-07-06-wave-3-structure-polish.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/user/concepts.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/docs/user/configuration.md +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/__main__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/migrate.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/remove.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/setup_ai.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/shell.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/skill_cmd.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/stats.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/cli/update.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/locking.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/parallel.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/paths.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/core/url_parser.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/mcp/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/system.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/routes/workspaces.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/server.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/static/app.css +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/add_repo.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/base.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/partials/dashboard_rows.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/partials/fetch_summary.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/partials/repo_row.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/settings.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/src/gitstow/web/templates/workspaces.html +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/__init__.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/conftest.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_locking.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_onboard.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_setup_ai.py +0 -0
- {gitstow-0.2.8 → gitstow-0.3.0}/tests/test_url_parser.py +0 -0
|
@@ -8,10 +8,14 @@ on:
|
|
|
8
8
|
|
|
9
9
|
jobs:
|
|
10
10
|
test:
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
11
|
strategy:
|
|
13
12
|
matrix:
|
|
13
|
+
os: [ubuntu-latest]
|
|
14
14
|
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
15
|
+
include:
|
|
16
|
+
- os: macos-latest
|
|
17
|
+
python-version: "3.12"
|
|
18
|
+
runs-on: ${{ matrix.os }}
|
|
15
19
|
|
|
16
20
|
steps:
|
|
17
21
|
- uses: actions/checkout@v4
|
|
@@ -9,9 +9,9 @@ Post-v0.1.0 improvements tracked here. See [GitHub Issues](https://github.com/ri
|
|
|
9
9
|
- [x] **Network retry/resume for batch operations** (#3) — `--retry N` flag on add and pull; cleans up partial clones before retry
|
|
10
10
|
- [x] **Export format versioning and checksums** (#4) — Added `version: 1` to YAML/JSON exports; validates on import; backward-compatible with unversioned files
|
|
11
11
|
- [x] **Progress indication during long clones** (#5) — `git clone --progress`; pull shows live counter `[5/47]`
|
|
12
|
-
- [x] **Publish to PyPI** (#6) — Release workflow created (`.github/workflows/
|
|
12
|
+
- [x] **Publish to PyPI** (#6) — Release workflow created (`.github/workflows/publish.yml`); publish on GitHub release
|
|
13
13
|
- [x] **Web dashboard (`gitstow ui`)** — Dark local browser UI wrapping core/ for daily repo management. FastAPI + Jinja2 + HTMX, dark + ember accent aesthetic. See [CHANGELOG.md](CHANGELOG.md) v0.2.0.
|
|
14
|
-
- [
|
|
14
|
+
- [x] **Fix TUI breakage** — Resolved by retirement: the Textual TUI was removed in v0.3.0; `gitstow ui` (web dashboard) is the visual surface going forward.
|
|
15
15
|
|
|
16
16
|
## Documentation
|
|
17
17
|
|
|
@@ -4,6 +4,37 @@ All notable changes to gitstow will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [0.3.0] - 2026-07-12
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Composition-aware status everywhere.** `gitstow status` now shows a Local Changes column (modified/staged/untracked counts) and a separate Remote column (in-sync/ahead/behind/diverged). The web dashboard rows, repo drawer, and help legend all use the same shared classifier — a repo with only staged or untracked files can no longer display as "clean". JSON output gains additive `local` and `remote` keys (all existing keys preserved).
|
|
12
|
+
- **`gitstow fetch_repos` MCP tool** and a `last_fetched` timestamp in all JSON outputs — MCP clients can now see fetch state, matching the CLI and web dashboard.
|
|
13
|
+
- **Untracked-repo hints on `list` and `status`.** Repos found on disk but not in the registry are now surfaced with a hint pointing at `workspace scan`, instead of being silently invisible.
|
|
14
|
+
- **`doctor` detects orphaned workspaces**, and `workspace remove` now warns when repos would be left pointing at a removed workspace.
|
|
15
|
+
- **`clone_timeout` setting** (`gitstow config set clone_timeout <seconds>`) — clone operations on very large repos no longer fail on a hardcoded 300s limit.
|
|
16
|
+
- **macOS added to the CI test matrix**, matching the packaging classifiers.
|
|
17
|
+
- **CHANGELOG gate in the release script** — `scripts/release.sh` now refuses to cut a release without a corresponding changelog entry.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **`add` clones multiple repos in parallel** and now detects remote mismatches and duplicate URLs before cloning, instead of silently registering whatever is already on disk.
|
|
22
|
+
- **`search` now runs across repos in parallel**, matching `exec`.
|
|
23
|
+
- **Pull, fetch, and the MCP server share one operations layer.** The MCP server now follows the same bulk-pull rule as the CLI and web dashboard (modified/staged skip, diverged skip, untracked-only pulls).
|
|
24
|
+
- **`open` prefers `$VISUAL`/`$EDITOR`** over guessing an editor, and runs terminal editors in the foreground so they actually get a usable TTY.
|
|
25
|
+
- **Disk sizing (`stats`, `repo info`) now shells out to `du`** instead of walking every file in Python — much faster on large repos.
|
|
26
|
+
- **`collection import` honors each entry's recorded workspace** instead of dumping everything into one workspace, and now fails loudly (with a printed error) on newer file versions instead of exiting silently.
|
|
27
|
+
- **The web dashboard's dependencies (FastAPI, uvicorn, Jinja2) moved to the optional `[ui]` extra.** Existing installs keep working; fresh CLI-only installs are ~15 packages lighter. Install with `pip install "gitstow[ui]"` to keep the dashboard.
|
|
28
|
+
- **Bulk pull rule unified and refined (behavior change).** CLI `pull` and the dashboard's Pull-all now follow one rule: repos with modified or staged files are skipped (with the composition shown), diverged repos are skipped (fast-forward pull cannot succeed), and repos with only untracked files ARE pulled — previously the CLI skipped them forever while the web pulled everything.
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- **`search`, `exec`, and `status` `--json` now emit pure JSON on an empty filter match** — previously they printed a "no repos match" banner and no payload at all, even with `--json` set.
|
|
33
|
+
|
|
34
|
+
### Removed
|
|
35
|
+
|
|
36
|
+
- **The Textual TUI (`gitstow tui`).** The web dashboard (`gitstow ui`) replaced it as the visual surface in v0.2.0; the TUI had been broken and parked since. Git history preserves it.
|
|
37
|
+
|
|
7
38
|
## [0.2.8] - 2026-07-12
|
|
8
39
|
|
|
9
40
|
### Fixed
|
|
@@ -25,21 +25,20 @@ src/gitstow/
|
|
|
25
25
|
│ ├── exec_cmd.py, search.py, open_cmd.py, stats.py # Power commands
|
|
26
26
|
│ ├── export_cmd.py # export/import collection
|
|
27
27
|
│ ├── shell.py # Shell integration (fzf, aliases)
|
|
28
|
-
│ ├── tui.py # TUI launcher
|
|
29
28
|
│ ├── serve.py # Web dashboard launcher
|
|
30
29
|
│ ├── migrate.py, config_cmd.py, onboard.py, doctor.py, skill_cmd.py
|
|
31
30
|
│ └── __init__.py
|
|
32
31
|
├── core/ # Business logic (git ops, URL parsing, state)
|
|
33
|
-
│ ├── paths.py
|
|
34
|
-
│ ├── config.py
|
|
35
|
-
│ ├── repo.py
|
|
36
|
-
│ ├── url_parser.py
|
|
37
|
-
│ ├── git.py
|
|
38
|
-
│ ├── discovery.py
|
|
39
|
-
│ ├── parallel.py
|
|
40
|
-
│
|
|
41
|
-
├──
|
|
42
|
-
│ ├──
|
|
32
|
+
│ ├── paths.py # Path constants, central repos.yaml resolution
|
|
33
|
+
│ ├── config.py # Workspace + Settings dataclasses, load/save
|
|
34
|
+
│ ├── repo.py # Repo dataclass + RepoStore (nested YAML CRUD)
|
|
35
|
+
│ ├── url_parser.py # URL → (host, owner, repo) extraction
|
|
36
|
+
│ ├── git.py # All git subprocess calls
|
|
37
|
+
│ ├── discovery.py # Walk directory tree (structured + flat), reconcile
|
|
38
|
+
│ ├── parallel.py # Async execution with semaphore
|
|
39
|
+
│ ├── status_model.py # Shared repo-state classifier — local composition vs remote relationship
|
|
40
|
+
│ ├── operations.py # Shared filter + bulk-runner layer (pull/fetch/MCP)
|
|
41
|
+
│ ├── locking.py # Cross-process file lock guarding repos.yaml writes
|
|
43
42
|
│ └── __init__.py
|
|
44
43
|
├── web/ # FastAPI browser dashboard (gitstow ui)
|
|
45
44
|
│ ├── server.py # FastAPI app, uvicorn runner, app.state.server stash
|
|
@@ -64,15 +63,18 @@ src/gitstow/
|
|
|
64
63
|
- `core/url_parser.py` — URL parsing (the hardest part). Test changes here thoroughly.
|
|
65
64
|
- `core/git.py` — All git subprocess calls. Uses `git status --porcelain=v2 --branch` for single-call efficiency.
|
|
66
65
|
- `core/parallel.py` — Async execution with semaphore (max 6 concurrent).
|
|
66
|
+
- `core/status_model.py` — `RepoState` — the single source of truth for local (modified/staged/untracked) vs remote (in-sync/ahead/behind/diverged) classification, consumed by CLI, web, and JSON.
|
|
67
|
+
- `core/operations.py` — Shared `filter_repo_pairs()` + bulk-runner used by `pull`, `fetch`, and the MCP server so surfaces can't drift.
|
|
68
|
+
- `core/locking.py` — `file_lock()` cross-process advisory lock guarding `repos.yaml` against concurrent CLI/web writes.
|
|
67
69
|
- `cli/helpers.py` — Shared workspace resolution used by all CLI commands.
|
|
68
70
|
- `cli/workspace_cmd.py` — workspace list/add/remove/scan subcommands.
|
|
69
71
|
- `cli/main.py` — Typer app, global `-w/--workspace` option, command registration.
|
|
70
|
-
- `tui/app.py` — Textual dashboard with DataTable, filter, pull, freeze toggle.
|
|
71
72
|
|
|
72
73
|
## Data Files
|
|
73
74
|
|
|
74
75
|
- `~/.gitstow/config.yaml` — Settings (workspaces list, default host, SSH pref).
|
|
75
76
|
- `~/.gitstow/repos.yaml` — Repo metadata nested by workspace label. Central location.
|
|
77
|
+
- `~/.gitstow/repos.lock` — Cross-process advisory lock file (`core/locking.py`) held during `repos.yaml` writes. Not user-facing data; safe to ignore/delete if orphaned.
|
|
76
78
|
|
|
77
79
|
### repos.yaml format
|
|
78
80
|
```yaml
|
|
@@ -86,14 +88,14 @@ active:
|
|
|
86
88
|
tags: [active]
|
|
87
89
|
```
|
|
88
90
|
|
|
89
|
-
## All Commands (
|
|
91
|
+
## All Commands (37)
|
|
90
92
|
|
|
91
93
|
**Core:** `add`, `pull`, `fetch`, `list`, `status`, `remove`, `migrate`
|
|
92
94
|
**Workspace:** `workspace list`, `workspace add`, `workspace remove`, `workspace scan`
|
|
93
95
|
**Repo management:** `repo freeze`, `repo unfreeze`, `repo tag`, `repo untag`, `repo tags`, `repo info`
|
|
94
96
|
**Power:** `exec`, `search`, `open`, `stats`
|
|
95
97
|
**Sharing:** `collection export`, `collection import`
|
|
96
|
-
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `
|
|
98
|
+
**Shell:** `shell pick`, `shell init`, `shell completions`, `shell setup`, `ui`
|
|
97
99
|
**Setup:** `onboard`, `config show/set/path/migrate-root`, `doctor`, `install-skill`, `setup-ai`, `update`
|
|
98
100
|
|
|
99
101
|
## Development
|
|
@@ -101,9 +103,8 @@ active:
|
|
|
101
103
|
```bash
|
|
102
104
|
cd ~/labs/projects/gitstow
|
|
103
105
|
pip install -e ".[dev]"
|
|
104
|
-
pytest #
|
|
106
|
+
pytest # full suite — keep green
|
|
105
107
|
ruff check src/
|
|
106
|
-
pip install -e ".[tui]" # For TUI development
|
|
107
108
|
```
|
|
108
109
|
|
|
109
110
|
## Patterns
|
|
@@ -123,7 +124,7 @@ pip install -e ".[tui]" # For TUI development
|
|
|
123
124
|
|
|
124
125
|
- Prefer proper long-term solutions over shortcut patches. If a feature is incomplete in one surface, build the feature into that surface instead of papering over it with wording, partial conditionals, or one-off display logic.
|
|
125
126
|
- Do not recommend quick fixes, temporary patches, or narrow workarounds unless the user explicitly asks for a shortcut.
|
|
126
|
-
- Keep CLI,
|
|
127
|
+
- Keep CLI, web dashboard, JSON output, docs, and tests semantically aligned when changing user-facing status behavior.
|
|
127
128
|
- For repo state presentation, avoid using "dirty" as a broad user-facing bucket for every local change. Present it as local/uncommitted changes with the composition visible: modified, staged, and untracked counts.
|
|
128
129
|
- Keep local working-tree state separate from remote relationship state. For example: local changes, clean, ahead, behind, diverged, frozen, missing.
|
|
129
130
|
- When improving the web dashboard, implement the actual missing dashboard feature and shared classification/model behavior instead of copying a CLI-only assumption into the template.
|
|
@@ -139,6 +140,6 @@ pip install -e ".[tui]" # For TUI development
|
|
|
139
140
|
**Optional: MCP server** (`src/gitstow/mcp/server.py`)
|
|
140
141
|
- For non-Claude-Code AI tools (Claude Desktop, Cursor, Windsurf)
|
|
141
142
|
- Install: `pip install gitstow[mcp]`, entry point: `gitstow-mcp`
|
|
142
|
-
-
|
|
143
|
+
- 14 tools + 3 resources, wraps same `core/` modules as CLI
|
|
143
144
|
- **Tradeoff:** MCP tools are always loaded into context (costs tokens even when idle).
|
|
144
145
|
The skill has no such cost. Only use MCP for dedicated repo-management setups.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gitstow
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: A git repository library manager — clone, organize, and maintain collections of repos you learn from
|
|
5
5
|
Project-URL: Homepage, https://github.com/rishmadaan/gitstow
|
|
6
6
|
Project-URL: Repository, https://github.com/rishmadaan/gitstow
|
|
@@ -26,21 +26,25 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
26
26
|
Classifier: Topic :: Software Development :: Version Control :: Git
|
|
27
27
|
Requires-Python: >=3.10
|
|
28
28
|
Requires-Dist: beaupy>=3.0
|
|
29
|
-
Requires-Dist: fastapi>=0.110
|
|
30
|
-
Requires-Dist: jinja2>=3.1
|
|
31
|
-
Requires-Dist: python-multipart>=0.0.9
|
|
32
29
|
Requires-Dist: pyyaml>=6.0
|
|
33
30
|
Requires-Dist: rich>=13.0
|
|
34
|
-
Requires-Dist: typer
|
|
35
|
-
Requires-Dist: uvicorn>=0.27
|
|
31
|
+
Requires-Dist: typer>=0.9
|
|
36
32
|
Provides-Extra: dev
|
|
33
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
37
34
|
Requires-Dist: httpx>=0.27; extra == 'dev'
|
|
35
|
+
Requires-Dist: jinja2>=3.1; extra == 'dev'
|
|
36
|
+
Requires-Dist: mcp>=1.0; extra == 'dev'
|
|
38
37
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
38
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'dev'
|
|
39
39
|
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
40
|
+
Requires-Dist: uvicorn>=0.27; extra == 'dev'
|
|
40
41
|
Provides-Extra: mcp
|
|
41
42
|
Requires-Dist: mcp>=1.0; extra == 'mcp'
|
|
42
|
-
Provides-Extra:
|
|
43
|
-
Requires-Dist:
|
|
43
|
+
Provides-Extra: ui
|
|
44
|
+
Requires-Dist: fastapi>=0.110; extra == 'ui'
|
|
45
|
+
Requires-Dist: jinja2>=3.1; extra == 'ui'
|
|
46
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
|
|
47
|
+
Requires-Dist: uvicorn>=0.27; extra == 'ui'
|
|
44
48
|
Description-Content-Type: text/markdown
|
|
45
49
|
|
|
46
50
|
# gitstow
|
|
@@ -62,8 +66,8 @@ Existing tools solve parts of this:
|
|
|
62
66
|
## Quick Start
|
|
63
67
|
|
|
64
68
|
```bash
|
|
65
|
-
pipx install gitstow # recommended
|
|
66
|
-
# or: pip install gitstow
|
|
69
|
+
pipx install "gitstow[ui]" # recommended — CLI + browser dashboard
|
|
70
|
+
# or: pip install gitstow # CLI only; add [ui] for the dashboard
|
|
67
71
|
|
|
68
72
|
# First-run setup (optional — works without it)
|
|
69
73
|
gitstow onboard
|
|
@@ -99,6 +103,8 @@ gitstow workspace scan active
|
|
|
99
103
|
```bash
|
|
100
104
|
gitstow add anthropic/claude-code facebook/react torvalds/linux
|
|
101
105
|
```
|
|
106
|
+
Multiple URLs clone concurrently (bounded by `parallel_limit`, default 6) — a mismatched remote on an existing path errors instead of silently registering, and duplicate URLs in the same invocation are deduped.
|
|
107
|
+
|
|
102
108
|
Creates (in a structured workspace):
|
|
103
109
|
```
|
|
104
110
|
~/oss/
|
|
@@ -117,8 +123,9 @@ gitstow -w oss pull # Only update oss workspace
|
|
|
117
123
|
gitstow pull --tag ai # Only repos tagged 'ai'
|
|
118
124
|
gitstow pull --exclude-tag stale # Everything except stale repos
|
|
119
125
|
gitstow status # Git status dashboard
|
|
120
|
-
gitstow -w active status --dirty #
|
|
126
|
+
gitstow -w active status --dirty # Repos with local changes in active workspace
|
|
121
127
|
```
|
|
128
|
+
`status` shows local changes as a composition (e.g. "2 modified · 1 staged · 3 untracked") rather than a single "dirty" bucket, and keeps the remote relationship (ahead/behind/diverged) in its own column.
|
|
122
129
|
|
|
123
130
|
### Freeze & Tags
|
|
124
131
|
```bash
|
|
@@ -182,17 +189,13 @@ gsp # gitstow pull shorthand
|
|
|
182
189
|
|
|
183
190
|
### Browser Dashboard
|
|
184
191
|
```bash
|
|
185
|
-
gitstow
|
|
192
|
+
pip install "gitstow[ui]" # if you installed CLI-only
|
|
193
|
+
gitstow ui # opens http://127.0.0.1:7853 in your browser
|
|
186
194
|
gitstow ui --port 8080
|
|
187
195
|
gitstow ui --no-browser
|
|
188
196
|
```
|
|
189
197
|
Persistent local web dashboard for daily repo management — a tab you leave open. Shows dirty state across your library, pulls single repos or all-of-them with a parallel summary panel, adds/removes repos, edits tags, freezes stale ones. Auto-refreshes row status every 30 seconds. Binds `127.0.0.1` only (arbitrary git execution must not be LAN-reachable). Click **Shutdown** in the footer — or Ctrl+C — to stop.
|
|
190
198
|
|
|
191
|
-
### Interactive Dashboard (TUI)
|
|
192
|
-
```bash
|
|
193
|
-
gitstow tui # Keyboard-driven terminal dashboard (SSH-friendly)
|
|
194
|
-
```
|
|
195
|
-
|
|
196
199
|
### JSON Output
|
|
197
200
|
Every command supports `--json` for scripting and AI consumption:
|
|
198
201
|
```bash
|
|
@@ -237,7 +240,6 @@ gitstow status --json
|
|
|
237
240
|
| `gitstow shell init` | Print shell functions to source in rc file |
|
|
238
241
|
| `gitstow shell pick` | fzf-powered repo picker |
|
|
239
242
|
| `gitstow shell completions` | Tab completion for repo names, workspaces, tags |
|
|
240
|
-
| `gitstow tui` | Interactive terminal dashboard |
|
|
241
243
|
| `gitstow fetch` | Fetch all remotes — update ahead/behind counts without merging |
|
|
242
244
|
| `gitstow ui` | Launch local browser dashboard (http://127.0.0.1:7853) |
|
|
243
245
|
| `gitstow update` | Upgrade gitstow itself from PyPI (detects pipx / pip / editable) |
|
|
@@ -17,8 +17,8 @@ Existing tools solve parts of this:
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
pipx install gitstow # recommended
|
|
21
|
-
# or: pip install gitstow
|
|
20
|
+
pipx install "gitstow[ui]" # recommended — CLI + browser dashboard
|
|
21
|
+
# or: pip install gitstow # CLI only; add [ui] for the dashboard
|
|
22
22
|
|
|
23
23
|
# First-run setup (optional — works without it)
|
|
24
24
|
gitstow onboard
|
|
@@ -54,6 +54,8 @@ gitstow workspace scan active
|
|
|
54
54
|
```bash
|
|
55
55
|
gitstow add anthropic/claude-code facebook/react torvalds/linux
|
|
56
56
|
```
|
|
57
|
+
Multiple URLs clone concurrently (bounded by `parallel_limit`, default 6) — a mismatched remote on an existing path errors instead of silently registering, and duplicate URLs in the same invocation are deduped.
|
|
58
|
+
|
|
57
59
|
Creates (in a structured workspace):
|
|
58
60
|
```
|
|
59
61
|
~/oss/
|
|
@@ -72,8 +74,9 @@ gitstow -w oss pull # Only update oss workspace
|
|
|
72
74
|
gitstow pull --tag ai # Only repos tagged 'ai'
|
|
73
75
|
gitstow pull --exclude-tag stale # Everything except stale repos
|
|
74
76
|
gitstow status # Git status dashboard
|
|
75
|
-
gitstow -w active status --dirty #
|
|
77
|
+
gitstow -w active status --dirty # Repos with local changes in active workspace
|
|
76
78
|
```
|
|
79
|
+
`status` shows local changes as a composition (e.g. "2 modified · 1 staged · 3 untracked") rather than a single "dirty" bucket, and keeps the remote relationship (ahead/behind/diverged) in its own column.
|
|
77
80
|
|
|
78
81
|
### Freeze & Tags
|
|
79
82
|
```bash
|
|
@@ -137,17 +140,13 @@ gsp # gitstow pull shorthand
|
|
|
137
140
|
|
|
138
141
|
### Browser Dashboard
|
|
139
142
|
```bash
|
|
140
|
-
gitstow
|
|
143
|
+
pip install "gitstow[ui]" # if you installed CLI-only
|
|
144
|
+
gitstow ui # opens http://127.0.0.1:7853 in your browser
|
|
141
145
|
gitstow ui --port 8080
|
|
142
146
|
gitstow ui --no-browser
|
|
143
147
|
```
|
|
144
148
|
Persistent local web dashboard for daily repo management — a tab you leave open. Shows dirty state across your library, pulls single repos or all-of-them with a parallel summary panel, adds/removes repos, edits tags, freezes stale ones. Auto-refreshes row status every 30 seconds. Binds `127.0.0.1` only (arbitrary git execution must not be LAN-reachable). Click **Shutdown** in the footer — or Ctrl+C — to stop.
|
|
145
149
|
|
|
146
|
-
### Interactive Dashboard (TUI)
|
|
147
|
-
```bash
|
|
148
|
-
gitstow tui # Keyboard-driven terminal dashboard (SSH-friendly)
|
|
149
|
-
```
|
|
150
|
-
|
|
151
150
|
### JSON Output
|
|
152
151
|
Every command supports `--json` for scripting and AI consumption:
|
|
153
152
|
```bash
|
|
@@ -192,7 +191,6 @@ gitstow status --json
|
|
|
192
191
|
| `gitstow shell init` | Print shell functions to source in rc file |
|
|
193
192
|
| `gitstow shell pick` | fzf-powered repo picker |
|
|
194
193
|
| `gitstow shell completions` | Tab completion for repo names, workspaces, tags |
|
|
195
|
-
| `gitstow tui` | Interactive terminal dashboard |
|
|
196
194
|
| `gitstow fetch` | Fetch all remotes — update ahead/behind counts without merging |
|
|
197
195
|
| `gitstow ui` | Launch local browser dashboard (http://127.0.0.1:7853) |
|
|
198
196
|
| `gitstow update` | Upgrade gitstow itself from PyPI (detects pipx / pip / editable) |
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
**Date:** 2026-07-06
|
|
4
4
|
**Auditor:** Claude (Fable 5), full read of all source (~9.5k lines Python), planning docs, tests, CI, packaging
|
|
5
5
|
**Baseline:** commit `1aefe9a`, 139 tests passing
|
|
6
|
-
**Status:**
|
|
6
|
+
**Status:** COMPLETE — all three waves shipped (Wave 1 → 0.2.8; Waves 2+3 → 0.3.0)
|
|
7
7
|
|
|
8
8
|
This document is the working tracker for the post-audit improvement effort. Each finding
|
|
9
9
|
has an ID for reference. Check items off as waves land.
|
|
@@ -119,27 +119,27 @@ Opus (substantial) / Sonnet (mechanical) subagents.
|
|
|
119
119
|
- [x] B12 path-containment check in CLI `remove --delete`
|
|
120
120
|
- [x] B11 workspace label validation
|
|
121
121
|
|
|
122
|
-
### Wave 2 — Shared status model (Opus) —
|
|
123
|
-
- [
|
|
124
|
-
- [
|
|
125
|
-
- [
|
|
126
|
-
- [
|
|
127
|
-
- [
|
|
128
|
-
- [
|
|
129
|
-
- [
|
|
130
|
-
|
|
131
|
-
### Wave 3 — Structure & polish (Sonnet-heavy, Opus for A3/A4) —
|
|
132
|
-
- [
|
|
133
|
-
- [
|
|
134
|
-
- [
|
|
135
|
-
- [
|
|
136
|
-
- [
|
|
137
|
-
- [
|
|
138
|
-
- [
|
|
139
|
-
- [
|
|
140
|
-
- [
|
|
141
|
-
- [
|
|
142
|
-
- [
|
|
122
|
+
### Wave 2 — Shared status model (Opus) — COMPLETE (2026-07-12)
|
|
123
|
+
- [x] P5 retire the Textual TUI (decision: retire; clears the third surface before the refactor)
|
|
124
|
+
- [x] A1/P4 `core/status_model.py`: one classifier separating local composition (modified/staged/untracked counts) from remote relationship (in-sync/ahead/behind/diverged) + frozen/missing overlays
|
|
125
|
+
- [x] Consume from CLI `status`, web dashboard, and `--json` payloads (per CLAUDE.md standards)
|
|
126
|
+
- [x] B6 one pull rule on both surfaces: modified/staged skip, untracked-only pulls (decision locked)
|
|
127
|
+
- [x] E1 parallelize web status gathering via `run_parallel` (off the event loop)
|
|
128
|
+
- [x] E2 batch RepoStore updates — `bulk()` (single save per bulk op)
|
|
129
|
+
- [x] Tests covering the classifier matrix
|
|
130
|
+
|
|
131
|
+
### Wave 3 — Structure & polish (Sonnet-heavy, Opus for A3/A4) — COMPLETE (2026-07-12)
|
|
132
|
+
- [x] P1/E3 parallel `add` clones; P2 remote-mismatch conflict error
|
|
133
|
+
- [x] E4 parallel `search`
|
|
134
|
+
- [x] A4 `core/operations.py` extraction (filters + bulk runner); collapse pull/fetch duplication
|
|
135
|
+
- [x] A3 MCP server consumes operations layer; add `last_fetched` everywhere (DOC3); new `fetch_repos` tool
|
|
136
|
+
- [x] P3 reconciliation hints surfacing untracked repos in `list`/`status` (human output only; JSON shapes unchanged)
|
|
137
|
+
- [x] B7 import preserves workspace; loud version error. B8 orphaned-workspace detection in doctor + workspace remove warning
|
|
138
|
+
- [x] B9 `$VISUAL`/`$EDITOR`-first open logic; terminal editors run foreground
|
|
139
|
+
- [x] A2 web stack → `[ui]` extra (decision locked; ships 0.3.0)
|
|
140
|
+
- [x] E5 `du`-backed disk sizing; E6 configurable `clone_timeout` setting
|
|
141
|
+
- [x] D2 macOS CI; D3 changelog gate in release.sh; D4 typer extra; D5 fetch/MCP tests
|
|
142
|
+
- [x] DOC1/DOC2 docs sync
|
|
143
143
|
|
|
144
144
|
## Verification notes
|
|
145
145
|
|
|
@@ -83,8 +83,10 @@ gitstow add anthropic/claude-code --update
|
|
|
83
83
|
- Repos are added to the default workspace (first configured), or the workspace specified with `-w`
|
|
84
84
|
- If the repo is already tracked: skips (or pulls with `--update`)
|
|
85
85
|
- If the path exists on disk but isn't tracked: registers it automatically
|
|
86
|
+
- If the path exists on disk with a **different** remote than the one requested: errors with a remote-mismatch message instead of silently registering — move the directory or pick another workspace
|
|
86
87
|
- If the path exists but isn't a git repo: errors
|
|
87
|
-
-
|
|
88
|
+
- Equivalent URLs passed twice in the same invocation (e.g. HTTPS and SSH forms of the same repo) are deduplicated — only the first is cloned, the rest are reported as duplicates
|
|
89
|
+
- Multiple URLs are cloned concurrently (bounded by `parallel_limit`, default 6), with per-clone retry via `--retry`
|
|
88
90
|
|
|
89
91
|
---
|
|
90
92
|
|
|
@@ -132,7 +134,9 @@ gitstow pull --include-frozen
|
|
|
132
134
|
|
|
133
135
|
**Behavior:**
|
|
134
136
|
- Frozen repos are skipped (shown as "Frozen" in summary)
|
|
135
|
-
-
|
|
137
|
+
- Repos with modified or staged files are skipped — the composition is shown in the summary (e.g. "2 modified · 1 staged")
|
|
138
|
+
- Diverged repos (local and remote both have commits the other lacks) are skipped — resolve manually (rebase or merge)
|
|
139
|
+
- Repos with only untracked files ARE pulled — an ff-only pull can't lose them
|
|
136
140
|
- Uses `--ff-only` — won't create merge commits
|
|
137
141
|
- Runs in parallel (configurable, default 6 concurrent)
|
|
138
142
|
- Updates `last_pulled` timestamp on success
|
|
@@ -217,6 +221,8 @@ gitstow list --paths # Show full paths
|
|
|
217
221
|
gitstow list --json # Machine-readable output
|
|
218
222
|
```
|
|
219
223
|
|
|
224
|
+
If a workspace has repos on disk that aren't tracked yet, `list` prints a hint (e.g. `⚠ 2 untracked repos in oss — run gitstow workspace scan oss`) — suppressed by `--json`/`--quiet`.
|
|
225
|
+
|
|
220
226
|
---
|
|
221
227
|
|
|
222
228
|
### `gitstow status`
|
|
@@ -233,19 +239,25 @@ gitstow status [flags]
|
|
|
233
239
|
|------|-------|-------------|
|
|
234
240
|
| `--tag` | `-t` | Filter by tag. |
|
|
235
241
|
| `--owner` | | Filter by owner. |
|
|
236
|
-
| `--dirty` | | Show only
|
|
242
|
+
| `--dirty` | | Show only repos with local changes. |
|
|
237
243
|
| `--json` | `-j` | JSON output. |
|
|
238
244
|
| `--quiet` | `-q` | Minimal output. |
|
|
239
245
|
|
|
240
|
-
Shows: repo name, branch,
|
|
246
|
+
Shows: repo name, branch, a **Local Changes** column (composition — e.g. "2 modified · 1 staged · 3 untracked", or "clean"), a separate **Remote** column (in-sync / ahead / behind / diverged / no-upstream), and last commit message and date. Local working-tree state and remote relationship are always shown as two separate dimensions — never a bare "dirty" bucket.
|
|
247
|
+
|
|
248
|
+
**JSON output** (`--json`) keeps all existing flat fields (`dirty`, `staged`, `untracked`, `ahead`, `behind`, `clean`, `status_symbol`, ...) and adds two keys from the shared status model:
|
|
249
|
+
- `local` — `{modified, staged, untracked, summary}`
|
|
250
|
+
- `remote` — `{state, ahead, behind}`, where `state` is one of `in-sync` / `ahead` / `behind` / `diverged` / `no-upstream` / `unknown`
|
|
241
251
|
|
|
242
|
-
**Status symbols
|
|
252
|
+
**Status symbols** (legacy `status_symbol` JSON field):
|
|
243
253
|
- `✓` clean
|
|
244
254
|
- `*` unstaged changes
|
|
245
255
|
- `+` staged changes
|
|
246
256
|
- `?` untracked files
|
|
247
257
|
- `❄` frozen
|
|
248
258
|
|
|
259
|
+
Like `list`, `status` prints an untracked-repos hint per workspace when repos exist on disk but aren't tracked — suppressed by `--json`/`--quiet`.
|
|
260
|
+
|
|
249
261
|
---
|
|
250
262
|
|
|
251
263
|
### `gitstow remove`
|
|
@@ -406,12 +418,12 @@ gitstow open <owner/repo> [flags]
|
|
|
406
418
|
|
|
407
419
|
| Flag | Short | Description |
|
|
408
420
|
|------|-------|-------------|
|
|
409
|
-
| `--editor` | `-e` | Open in
|
|
421
|
+
| `--editor` | `-e` | Open in your editor (`$VISUAL`/`$EDITOR`, then VS Code/Cursor). This is the default. |
|
|
410
422
|
| `--browser` | `-b` | Open the repo on GitHub/GitLab in your browser. |
|
|
411
423
|
| `--finder` | `-f` | Open in Finder/file manager. |
|
|
412
424
|
| `--path` | `-p` | Just print the path to stdout. |
|
|
413
425
|
|
|
414
|
-
With no flags, opens in the
|
|
426
|
+
With no flags, opens in an editor: `$VISUAL`, then `$EDITOR`, then a fallback of VS Code (`code`) or Cursor (`cursor`) if installed. Terminal editors (`vi`, `vim`, `nvim`, `nano`, `emacs`, `hx`, `kak`, `micro`) run in the foreground since they need the TTY; GUI editors are launched detached. The `--path` flag is useful for shell integration:
|
|
415
427
|
|
|
416
428
|
```bash
|
|
417
429
|
cd "$(gitstow open anthropic/claude-code -p)"
|
|
@@ -517,25 +529,12 @@ Completes:
|
|
|
517
529
|
- Workspace labels for `-w/--workspace`
|
|
518
530
|
- Tag names for `-t/--tag`
|
|
519
531
|
|
|
520
|
-
### `gitstow tui`
|
|
521
|
-
|
|
522
|
-
Interactive terminal dashboard built with [Textual](https://github.com/Textualize/textual). Requires `pip install gitstow[tui]`.
|
|
523
|
-
|
|
524
|
-
Keyboard shortcuts:
|
|
525
|
-
- `r` — Refresh
|
|
526
|
-
- `p` — Pull all unfrozen repos
|
|
527
|
-
- `P` — Pull selected repo only
|
|
528
|
-
- `f` — Toggle freeze on selected repo
|
|
529
|
-
- `w` — Cycle workspace filter
|
|
530
|
-
- `t` — Cycle tag filter
|
|
531
|
-
- `Enter` — Show repo details
|
|
532
|
-
- `/` — Focus filter input
|
|
533
|
-
- `q` — Quit
|
|
534
|
-
|
|
535
532
|
### `gitstow ui`
|
|
536
533
|
|
|
537
534
|
Launch a local browser dashboard — a dark-themed web UI for daily repo management. Binds to `127.0.0.1` only; auto-opens your default browser.
|
|
538
535
|
|
|
536
|
+
> Requires the `ui` extra: `pip install "gitstow[ui]"` (or `pipx install "gitstow[ui]"`). Running `gitstow ui` without it prints an install hint and exits.
|
|
537
|
+
|
|
539
538
|
```bash
|
|
540
539
|
gitstow ui # http://127.0.0.1:7853
|
|
541
540
|
gitstow ui --port 8080 # custom port
|
|
@@ -561,8 +560,8 @@ Every interactive element has a hover tooltip. There's also a `?` button in the
|
|
|
561
560
|
| | Meaning | What to do |
|
|
562
561
|
|---|---|---|
|
|
563
562
|
| clean | Working tree matches HEAD; in sync with the last fetch | Nothing |
|
|
564
|
-
| dirty |
|
|
565
|
-
| conflict |
|
|
563
|
+
| dirty | Local changes — the label shows the composition (e.g. "2 modified · 1 staged · 3 untracked") | Commit/stash modified or staged files before pulling; untracked-only repos can still pull |
|
|
564
|
+
| conflict | Local changes (modified/staged) AND behind remote, or local and remote have diverged | Resolve locally before pulling |
|
|
566
565
|
| behind | Remote has commits you don't | Click the orange Pull button |
|
|
567
566
|
| ahead | You have local commits not yet pushed | Consider `git push` |
|
|
568
567
|
| frozen | Intentionally skipped by "Pull all" | Unfreeze from the ⋯ menu |
|
|
@@ -570,8 +569,8 @@ Every interactive element has a hover tooltip. There's also a `?` button in the
|
|
|
570
569
|
**The Pull button color encodes priority**:
|
|
571
570
|
|
|
572
571
|
- **Orange** `↓ Pull 5` — repo is behind; clicking fast-forwards by the shown count
|
|
573
|
-
- **Ghost** (gray) — already up to date,
|
|
574
|
-
- **Disabled** — frozen, in conflict, or missing on disk
|
|
572
|
+
- **Ghost** (gray) — already up to date, has local changes, or ahead. The button still works; it just won't change anything useful. (Untracked-only local changes still pull fine — a bulk pull only skips modified/staged files.)
|
|
573
|
+
- **Disabled** — frozen, in conflict, diverged from remote, or missing on disk
|
|
575
574
|
|
|
576
575
|
**Remote Δ** (`↑ N`, `↓ N`, or `—`) reflects your *last fetch*, not live remote state. If the counts look stale, pull (or run `git fetch --all` manually) to refresh them.
|
|
577
576
|
|
|
@@ -615,20 +614,26 @@ Change a setting.
|
|
|
615
614
|
gitstow config set default_host gitlab.com
|
|
616
615
|
gitstow config set prefer_ssh true
|
|
617
616
|
gitstow config set parallel_limit 8
|
|
617
|
+
gitstow config set clone_timeout 900
|
|
618
618
|
```
|
|
619
619
|
|
|
620
|
+
Valid keys: `default_host`, `prefer_ssh`, `parallel_limit`, `clone_timeout` (clone timeout in seconds).
|
|
621
|
+
|
|
620
622
|
> **Note:** The old `root_path` setting has been replaced by workspaces. Use `gitstow workspace add` to manage where repos are stored.
|
|
621
623
|
|
|
622
624
|
### `gitstow config migrate-root`
|
|
623
625
|
|
|
624
|
-
Move
|
|
626
|
+
Move one workspace's repos to a new directory and update that workspace's `path` in config.
|
|
625
627
|
|
|
626
628
|
```bash
|
|
627
|
-
gitstow config migrate-root ~/new-location
|
|
628
|
-
gitstow config migrate-root ~/new-location
|
|
629
|
-
gitstow config migrate-root ~/new-location --
|
|
629
|
+
gitstow config migrate-root ~/new-location # Moves the default workspace
|
|
630
|
+
gitstow -w active config migrate-root ~/new-location # Moves a specific workspace
|
|
631
|
+
gitstow config migrate-root ~/new-location --copy # Keep originals
|
|
632
|
+
gitstow config migrate-root ~/new-location --yes # Skip confirmation
|
|
630
633
|
```
|
|
631
634
|
|
|
635
|
+
> **Note:** `migrate-root` has no local `--workspace` flag — target a non-default workspace with the global `-w` flag *before* `config`, not after `migrate-root`.
|
|
636
|
+
|
|
632
637
|
### `gitstow config path`
|
|
633
638
|
|
|
634
639
|
Print the config file path.
|
|
@@ -774,13 +779,14 @@ Then add to your AI tool's config:
|
|
|
774
779
|
|
|
775
780
|
Or use `gitstow setup-ai` to auto-detect and configure.
|
|
776
781
|
|
|
777
|
-
### MCP Tools (
|
|
782
|
+
### MCP Tools (14)
|
|
778
783
|
|
|
779
784
|
| Tool | Description |
|
|
780
785
|
|------|-------------|
|
|
781
786
|
| `list_repos` | List repos with tag/owner/query filters |
|
|
782
787
|
| `add_repo` | Clone a repo (shorthand or full URL) |
|
|
783
788
|
| `pull_repos` | Bulk pull with tag/exclude/frozen filters |
|
|
789
|
+
| `fetch_repos` | Bulk fetch (updates ahead/behind, no merge; includes frozen) |
|
|
784
790
|
| `repo_status` | Git status dashboard across repos |
|
|
785
791
|
| `repo_info` | Detailed single repo info |
|
|
786
792
|
| `freeze_repo` | Freeze a repo (skip during pull) |
|
|
@@ -790,6 +796,7 @@ Or use `gitstow setup-ai` to auto-detect and configure.
|
|
|
790
796
|
| `remove_repo` | Remove from tracking (optionally delete) |
|
|
791
797
|
| `search_repos` | Grep across repos with pattern and glob |
|
|
792
798
|
| `collection_stats` | Disk usage, owner breakdown, tag counts |
|
|
799
|
+
| `list_workspaces` | List configured workspaces with repo counts |
|
|
793
800
|
|
|
794
801
|
### MCP Resources (3)
|
|
795
802
|
|
|
@@ -22,10 +22,13 @@ Get gitstow installed and managing repos in about 5 minutes.
|
|
|
22
22
|
pip install gitstow
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
+
Want the browser dashboard (`gitstow ui`) too? Add the `[ui]` extra: `pip install "gitstow[ui]"`.
|
|
26
|
+
|
|
25
27
|
Or with [pipx](https://pipx.pypa.io/) (recommended — keeps it isolated):
|
|
26
28
|
|
|
27
29
|
```bash
|
|
28
|
-
pipx install gitstow
|
|
30
|
+
pipx install "gitstow[ui]" # CLI + browser dashboard
|
|
31
|
+
# or: pipx install gitstow # CLI only
|
|
29
32
|
```
|
|
30
33
|
|
|
31
34
|
Verify it worked:
|
|
@@ -163,6 +166,7 @@ This is also done automatically during `gitstow onboard` and auto-updates when y
|
|
|
163
166
|
## Prefer a Browser?
|
|
164
167
|
|
|
165
168
|
```bash
|
|
169
|
+
pip install "gitstow[ui]" # only needed if you installed CLI-only above
|
|
166
170
|
gitstow ui
|
|
167
171
|
```
|
|
168
172
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "gitstow"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.0"
|
|
8
8
|
description = "A git repository library manager — clone, organize, and maintain collections of repos you learn from"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -30,14 +30,10 @@ classifiers = [
|
|
|
30
30
|
]
|
|
31
31
|
|
|
32
32
|
dependencies = [
|
|
33
|
-
"typer
|
|
33
|
+
"typer>=0.9",
|
|
34
34
|
"pyyaml>=6.0",
|
|
35
35
|
"rich>=13.0",
|
|
36
36
|
"beaupy>=3.0",
|
|
37
|
-
"fastapi>=0.110",
|
|
38
|
-
"uvicorn>=0.27",
|
|
39
|
-
"jinja2>=3.1",
|
|
40
|
-
"python-multipart>=0.0.9",
|
|
41
37
|
]
|
|
42
38
|
|
|
43
39
|
[project.urls]
|
|
@@ -48,13 +44,21 @@ Issues = "https://github.com/rishmadaan/gitstow/issues"
|
|
|
48
44
|
Changelog = "https://github.com/rishmadaan/gitstow/blob/main/CHANGELOG.md"
|
|
49
45
|
|
|
50
46
|
[project.optional-dependencies]
|
|
47
|
+
ui = [
|
|
48
|
+
"fastapi>=0.110",
|
|
49
|
+
"uvicorn>=0.27",
|
|
50
|
+
"jinja2>=3.1",
|
|
51
|
+
"python-multipart>=0.0.9",
|
|
52
|
+
]
|
|
51
53
|
dev = [
|
|
52
54
|
"pytest>=8.0",
|
|
53
55
|
"ruff>=0.4",
|
|
54
56
|
"httpx>=0.27",
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
"
|
|
57
|
+
"fastapi>=0.110",
|
|
58
|
+
"uvicorn>=0.27",
|
|
59
|
+
"jinja2>=3.1",
|
|
60
|
+
"python-multipart>=0.0.9",
|
|
61
|
+
"mcp>=1.0",
|
|
58
62
|
]
|
|
59
63
|
mcp = [
|
|
60
64
|
"mcp>=1.0",
|