git-branch-cleaner-tui 1.0.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.
@@ -0,0 +1,31 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.egg-info/
6
+ dist/
7
+ build/
8
+ *.egg
9
+
10
+ # Virtual environment
11
+ .venv/
12
+ venv/
13
+ .env/
14
+
15
+ # Test cache
16
+ .pytest_cache/
17
+ .mypy_cache/
18
+ .ruff_cache/
19
+
20
+ # IDE
21
+ .vscode/
22
+ .idea/
23
+ *.swp
24
+ *.swo
25
+
26
+ # OS
27
+ .DS_Store
28
+ Thumbs.db
29
+
30
+ # Project
31
+ docs/superpowers/
@@ -0,0 +1,306 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-branch-cleaner-tui
3
+ Version: 1.0.0
4
+ Summary: TUI tool for browsing and bulk-deleting git branches
5
+ Author: git-cleaner
6
+ Requires-Python: >=3.11
7
+ Requires-Dist: textual
8
+ Description-Content-Type: text/markdown
9
+
10
+ ```text
11
+ ████ ████ ████ █████ ██ █████ █████ ██▄ ██ █████ █████
12
+ ██ ▄▄ ██ ██ ██ ▀▀ ██ ██▄▄ ██ ██ ██████ ██▄▄ ██▄██
13
+ ██▄██ ▄██▄ ██ ██▄██ ██▄██ ██▄▄▄ █████ ██▀███ ██▄▄▄ ██▀█▄
14
+ ▀▀▀▀▀ ▀▀▀▀ ▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀▀ ▀▀ ▀▀
15
+ ```
16
+
17
+ A **TUI tool** for interactively browsing and bulk-deleting git branches, plus **repo maintenance** (GC, repack, prune). Pick a date range, review branches with their last-commit dates, and delete locally and/or on remote — protected and blacklisted branches are automatically safeguarded.
18
+
19
+ Built with [Textual](https://textual.textualize.io/) and Python 3.11+.
20
+
21
+ ![Python](https://img.shields.io/badge/python-3.11+-blue?logo=python)
22
+ ![Textual](https://img.shields.io/badge/textual-8.x-orange)
23
+ ![License](https://img.shields.io/badge/license-MIT-green)
24
+
25
+ ---
26
+
27
+ ## Installation
28
+
29
+ ### With uv (recommended)
30
+
31
+ ```bash
32
+ # Install as a global tool
33
+ uv tool install git-branch-cleaner-tui
34
+
35
+ # Run in any git repo
36
+ git-branch-cleaner-tui
37
+ ```
38
+
39
+ ### From source
40
+
41
+ ```bash
42
+ git clone https://github.com/Allentgt/Git-Cleaner
43
+ cd git-cleaner
44
+ uv sync
45
+ uv run git-branch-cleaner-tui --repo /path/to/repo
46
+ ```
47
+
48
+ ### Requirements
49
+
50
+ - Python ≥ 3.11
51
+ - [uv](https://docs.astral.sh/uv/) (recommended) or pip
52
+ - A git repository
53
+
54
+ ---
55
+
56
+ ## Features
57
+
58
+ - **🗓️ Interactive calendar** — Pick From / Until dates visually, with highlighted range and auto-switching mode
59
+ - **🔍 Branch browser** — DataTable with multi-select, sorted by last commit date
60
+ - **🛡️ Protection** — `main`, `master`, `develop`, plus custom patterns from config; marked with 🔒, cannot be deleted
61
+ - **⛔ Blacklist** — Wildcard patterns (`archive/*`, `wip-*`); marked with ⛔, hidden by default
62
+ - **☁️ Remote deletion** — Toggle `r` to also delete branches on remote (`git push origin --delete`)
63
+ - **🔧 Maintenance dashboard** — Repo health stats, `git gc`, `git repack`, `git remote prune`, `git reflog expire`
64
+ - **📁 Configurable** — Per-repo `.git-branch-cleaner.toml` + global `~/.git-branch-cleaner.toml`
65
+ - **⚡ Fast** — Single `git for-each-ref` call for branch listing; bulk delete with one confirm
66
+
67
+ ---
68
+
69
+ ## Usage
70
+
71
+ ### 0. Start the App
72
+
73
+ ```bash
74
+ git-branch-cleaner-tui
75
+ # or: git-branch-cleaner-tui --repo /path/to/repo
76
+ ```
77
+
78
+ Opens the calendar screen. Press **Maintenance** for repo optimization, or pick dates and **Load Branches** to clean.
79
+
80
+ ### 1. Pick a Date Range
81
+
82
+ The app opens with an interactive calendar:
83
+
84
+ - **Navigate months** with `<` / `>` arrows
85
+ - **Set From date** — click a day (mode auto-switches to Until)
86
+ - **Set Until date** — click another day
87
+ - **Toggle mode** manually with `Set From Date` / `Set Until Date` buttons
88
+ - Selected range is highlighted in the calendar grid
89
+
90
+ When both dates are set, click **Load Branches**.
91
+
92
+ ### 2. Browse and Select Branches
93
+
94
+ | Key | Action |
95
+ |-----|--------|
96
+ | `Space` | Toggle selection on focused row |
97
+ | `a` | Toggle select / deselect all selectable branches |
98
+ | `d` | Delete selected (with confirmation dialog) |
99
+ | `r` | Toggle remote deletion on/off |
100
+ | `p` | Toggle show/hide protected branches |
101
+ | `b` | Toggle show/hide blacklisted branches |
102
+ | `Escape` | Go back to calendar |
103
+ | `Ctrl+R` | Refresh branch list |
104
+
105
+ - **Protected** branches 🔒 are always safe — cannot be selected
106
+ - **Blacklisted** branches ⛔ are hidden by default; press `b` to review them
107
+ - Status bar shows: `Total | Selected | Protected | Blacklisted | Remote ON/OFF`
108
+
109
+ ### 3. Confirm Deletion
110
+
111
+ A modal dialog lists all branches marked for deletion and shows the scope:
112
+
113
+ - **Local only** — `git branch -D <name>`
114
+ - **Local + remote** — `git branch -D <name>` then `git push origin --delete <name>`
115
+
116
+ Remote deletion is attempted only for branches that succeeded locally.
117
+
118
+ ### 4. Maintenance Dashboard
119
+
120
+ Press **Maintenance** on the calendar screen opens a dashboard with:
121
+
122
+ **Repository Health:**
123
+ - `.git` directory size
124
+ - Loose object count (unpacked)
125
+ - Packed object count + total pack size
126
+ - Garbage objects
127
+ - Prune-packable objects
128
+
129
+ **Maintenance Tasks** (click any to run):
130
+
131
+ | Button | Command | Use Case |
132
+ |--------|---------|---------|
133
+ | **Git GC** | `git gc` | Standard housekeeping — compress revisions, remove loose objects |
134
+ | **GC Aggressive** | `git gc --aggressive` | Deep optimization (slower, best for repos that haven't been GC'd in months) |
135
+ | **Repack** | `git repack -Ad` | Reorganize pack files for better delta compression |
136
+ | **Prune Remote** | `git remote prune origin` | Remove stale remote-tracking refs (branches deleted on remote) |
137
+ | **Expire Reflog** | `git reflog expire --expire=90.days.ago` | Trim old reflog entries |
138
+ | **Run All** | Runs the 4 tasks above sequentially | One-shot full cleanup |
139
+
140
+ Tasks run asynchronously (UI stays responsive). Health stats refresh automatically after each task.
141
+
142
+ | Key | Action |
143
+ |-----|--------|
144
+ | `Escape` | Back to calendar |
145
+ | `r` | Refresh health stats |
146
+
147
+ ---
148
+
149
+ ## Configuration
150
+
151
+ ### Project-level config
152
+
153
+ Place `.git-branch-cleaner.toml` in your repository root:
154
+
155
+ ```toml
156
+ [protected]
157
+ patterns = ["release/*", "hotfix/*"]
158
+
159
+ [blacklist]
160
+ patterns = ["archive/*", "wip-*", "experiments/**"]
161
+ ```
162
+
163
+ ### Global config
164
+
165
+ Place `~/.git-branch-cleaner.toml` for user-wide rules:
166
+
167
+ ```toml
168
+ [protected]
169
+ patterns = ["personal/*"]
170
+
171
+ [blacklist]
172
+ patterns = ["deps/*"]
173
+ ```
174
+
175
+ ### Merging strategy
176
+
177
+ All sources merged (hardcoded defaults → global → project), with project config taking highest precedence.
178
+
179
+ **Hardcoded defaults** (always active): `main`, `master`, `develop` are protected. The current checked-out branch is also automatically protected.
180
+
181
+ ---
182
+
183
+ ## Keybindings Reference
184
+
185
+ ### Calendar Screen
186
+
187
+ | Key | Action |
188
+ |-----|--------|
189
+ | Click day | Select date (From or Until per mode) |
190
+ | Click `<` `>` | Navigate months |
191
+ | Click mode buttons | Toggle between From / Until selection |
192
+ | Click **Load Branches** | Proceed to branch list |
193
+ | Click **Maintenance** | Open maintenance dashboard |
194
+
195
+ ### Branch List Screen
196
+
197
+ | Key | Action |
198
+ |-----|--------|
199
+ | `Space` | Toggle row selection |
200
+ | `a` | Toggle select / deselect all eligible |
201
+ | `d` | Delete selected |
202
+ | `r` | Toggle remote deletion |
203
+ | `p` | Toggle protected visibility |
204
+ | `b` | Toggle blacklisted visibility |
205
+ | `Escape` | Back to calendar |
206
+ | `Ctrl+R` | Refresh |
207
+
208
+ ### Maintenance Screen
209
+
210
+ | Key | Action |
211
+ |-----|--------|
212
+ | `Escape` | Back to calendar |
213
+ | `r` | Refresh health stats |
214
+
215
+ ---
216
+
217
+ ## Project Structure
218
+
219
+ ```
220
+ git-cleaner/
221
+ ├── pyproject.toml # Project metadata, deps, entry point
222
+ ├── README.md
223
+ ├── src/
224
+ │ └── git_cleaner/
225
+ │ ├── __init__.py
226
+ │ ├── __main__.py # python -m git_cleaner entry
227
+ │ ├── cli.py # CLI arg parsing
228
+ │ ├── app.py # Textual TUI (Calendar, Maintenance, BranchList, Confirm)
229
+ │ ├── config.py # TOML config loading and merging
230
+ │ └── git_ops.py # Git subprocess wrapper (list, delete, gc, repack, etc.)
231
+ ├── tests/
232
+ │ ├── test_config.py # 7 tests
233
+ │ └── test_git_ops.py # 16 tests
234
+ └── uv.lock
235
+ ```
236
+
237
+ ### Module responsibilities
238
+
239
+ | Module | Role |
240
+ |--------|------|
241
+ | `cli.py` | Parse `--repo` flag, launch the TUI app |
242
+ | `app.py` | Textual screens: calendar, maintenance dashboard, branch list with DataTable, confirmation dialog |
243
+ | `config.py` | Load `.git-branch-cleaner.toml` (project + global), fnmatch pattern matching |
244
+ | `git_ops.py` | `list_branches()`, `delete_branches()`, `delete_remote_branches()`, `get_repo_root()`, `get_git_dir_size()`, `get_object_stats()`, `run_gc()`, `repack_objects()`, `prune_remote()`, `expire_reflog()` |
245
+
246
+ ---
247
+
248
+ ## Development
249
+
250
+ ```bash
251
+ # Set up
252
+ git clone https://github.com/Allentgt/Git-Cleaner
253
+ cd git-cleaner
254
+ uv sync --dev
255
+
256
+ # Run tests (23 total)
257
+ uv run pytest
258
+
259
+ # Run with verbose output
260
+ uv run pytest -v
261
+
262
+ # Run a specific test
263
+ uv run pytest tests/test_config.py -v
264
+
265
+ # Run the app
266
+ uv run git-branch-cleaner-tui --repo /path/to/repo
267
+ ```
268
+
269
+ ### Test coverage
270
+
271
+ 23 tests covering:
272
+
273
+ - Config loading and merging (defaults, project, global)
274
+ - Pattern matching (exact, wildcard, fnmatch)
275
+ - Git operations (listing, current branch detection, date filtering, deletion, remote deletion)
276
+ - Repository health (`get_git_dir_size`, `get_object_stats`)
277
+ - Maintenance tasks (`run_gc`, `repack_objects`, `prune_remote`, `expire_reflog`)
278
+ - Error handling (non-repo path, no remote configured, timeout)
279
+
280
+ ---
281
+
282
+ ## FAQ
283
+
284
+ **Q: Can I undo a deletion?**
285
+ No — `git branch -D` is irreversible. Use the confirmation dialog to review before confirming.
286
+
287
+ **Q: Does it work on Windows?**
288
+ Yes. Tested on Windows (PowerShell), macOS, and Linux. Requires Python 3.11+.
289
+
290
+ **Q: Can I delete remote branches?**
291
+ Yes. Press `r` to toggle remote deletion on, then delete normally. Branches are deleted locally first, then via `git push origin --delete`.
292
+
293
+ **Q: How are dates filtered?**
294
+ By the commit date of the branch tip (most recent commit). Both From and Until are inclusive.
295
+
296
+ **Q: Is `git gc --aggressive` safe?**
297
+ Yes. It's more CPU-intensive than standard `git gc` but performs deeper optimization. Good for repos that haven't been GC'd in months. The UI won't freeze — it runs in a background thread.
298
+
299
+ **Q: Does the maintenance dashboard modify my repo?**
300
+ Yes, the maintenance tasks run real git commands (`git gc`, `git repack`, etc.) that modify the `.git` directory. They are safe read-only operations that don't change working tree files.
301
+
302
+ ---
303
+
304
+ ## License
305
+
306
+ MIT
@@ -0,0 +1,297 @@
1
+ ```text
2
+ ████ ████ ████ █████ ██ █████ █████ ██▄ ██ █████ █████
3
+ ██ ▄▄ ██ ██ ██ ▀▀ ██ ██▄▄ ██ ██ ██████ ██▄▄ ██▄██
4
+ ██▄██ ▄██▄ ██ ██▄██ ██▄██ ██▄▄▄ █████ ██▀███ ██▄▄▄ ██▀█▄
5
+ ▀▀▀▀▀ ▀▀▀▀ ▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀▀ ▀▀ ▀▀
6
+ ```
7
+
8
+ A **TUI tool** for interactively browsing and bulk-deleting git branches, plus **repo maintenance** (GC, repack, prune). Pick a date range, review branches with their last-commit dates, and delete locally and/or on remote — protected and blacklisted branches are automatically safeguarded.
9
+
10
+ Built with [Textual](https://textual.textualize.io/) and Python 3.11+.
11
+
12
+ ![Python](https://img.shields.io/badge/python-3.11+-blue?logo=python)
13
+ ![Textual](https://img.shields.io/badge/textual-8.x-orange)
14
+ ![License](https://img.shields.io/badge/license-MIT-green)
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ### With uv (recommended)
21
+
22
+ ```bash
23
+ # Install as a global tool
24
+ uv tool install git-branch-cleaner-tui
25
+
26
+ # Run in any git repo
27
+ git-branch-cleaner-tui
28
+ ```
29
+
30
+ ### From source
31
+
32
+ ```bash
33
+ git clone https://github.com/Allentgt/Git-Cleaner
34
+ cd git-cleaner
35
+ uv sync
36
+ uv run git-branch-cleaner-tui --repo /path/to/repo
37
+ ```
38
+
39
+ ### Requirements
40
+
41
+ - Python ≥ 3.11
42
+ - [uv](https://docs.astral.sh/uv/) (recommended) or pip
43
+ - A git repository
44
+
45
+ ---
46
+
47
+ ## Features
48
+
49
+ - **🗓️ Interactive calendar** — Pick From / Until dates visually, with highlighted range and auto-switching mode
50
+ - **🔍 Branch browser** — DataTable with multi-select, sorted by last commit date
51
+ - **🛡️ Protection** — `main`, `master`, `develop`, plus custom patterns from config; marked with 🔒, cannot be deleted
52
+ - **⛔ Blacklist** — Wildcard patterns (`archive/*`, `wip-*`); marked with ⛔, hidden by default
53
+ - **☁️ Remote deletion** — Toggle `r` to also delete branches on remote (`git push origin --delete`)
54
+ - **🔧 Maintenance dashboard** — Repo health stats, `git gc`, `git repack`, `git remote prune`, `git reflog expire`
55
+ - **📁 Configurable** — Per-repo `.git-branch-cleaner.toml` + global `~/.git-branch-cleaner.toml`
56
+ - **⚡ Fast** — Single `git for-each-ref` call for branch listing; bulk delete with one confirm
57
+
58
+ ---
59
+
60
+ ## Usage
61
+
62
+ ### 0. Start the App
63
+
64
+ ```bash
65
+ git-branch-cleaner-tui
66
+ # or: git-branch-cleaner-tui --repo /path/to/repo
67
+ ```
68
+
69
+ Opens the calendar screen. Press **Maintenance** for repo optimization, or pick dates and **Load Branches** to clean.
70
+
71
+ ### 1. Pick a Date Range
72
+
73
+ The app opens with an interactive calendar:
74
+
75
+ - **Navigate months** with `<` / `>` arrows
76
+ - **Set From date** — click a day (mode auto-switches to Until)
77
+ - **Set Until date** — click another day
78
+ - **Toggle mode** manually with `Set From Date` / `Set Until Date` buttons
79
+ - Selected range is highlighted in the calendar grid
80
+
81
+ When both dates are set, click **Load Branches**.
82
+
83
+ ### 2. Browse and Select Branches
84
+
85
+ | Key | Action |
86
+ |-----|--------|
87
+ | `Space` | Toggle selection on focused row |
88
+ | `a` | Toggle select / deselect all selectable branches |
89
+ | `d` | Delete selected (with confirmation dialog) |
90
+ | `r` | Toggle remote deletion on/off |
91
+ | `p` | Toggle show/hide protected branches |
92
+ | `b` | Toggle show/hide blacklisted branches |
93
+ | `Escape` | Go back to calendar |
94
+ | `Ctrl+R` | Refresh branch list |
95
+
96
+ - **Protected** branches 🔒 are always safe — cannot be selected
97
+ - **Blacklisted** branches ⛔ are hidden by default; press `b` to review them
98
+ - Status bar shows: `Total | Selected | Protected | Blacklisted | Remote ON/OFF`
99
+
100
+ ### 3. Confirm Deletion
101
+
102
+ A modal dialog lists all branches marked for deletion and shows the scope:
103
+
104
+ - **Local only** — `git branch -D <name>`
105
+ - **Local + remote** — `git branch -D <name>` then `git push origin --delete <name>`
106
+
107
+ Remote deletion is attempted only for branches that succeeded locally.
108
+
109
+ ### 4. Maintenance Dashboard
110
+
111
+ Press **Maintenance** on the calendar screen opens a dashboard with:
112
+
113
+ **Repository Health:**
114
+ - `.git` directory size
115
+ - Loose object count (unpacked)
116
+ - Packed object count + total pack size
117
+ - Garbage objects
118
+ - Prune-packable objects
119
+
120
+ **Maintenance Tasks** (click any to run):
121
+
122
+ | Button | Command | Use Case |
123
+ |--------|---------|---------|
124
+ | **Git GC** | `git gc` | Standard housekeeping — compress revisions, remove loose objects |
125
+ | **GC Aggressive** | `git gc --aggressive` | Deep optimization (slower, best for repos that haven't been GC'd in months) |
126
+ | **Repack** | `git repack -Ad` | Reorganize pack files for better delta compression |
127
+ | **Prune Remote** | `git remote prune origin` | Remove stale remote-tracking refs (branches deleted on remote) |
128
+ | **Expire Reflog** | `git reflog expire --expire=90.days.ago` | Trim old reflog entries |
129
+ | **Run All** | Runs the 4 tasks above sequentially | One-shot full cleanup |
130
+
131
+ Tasks run asynchronously (UI stays responsive). Health stats refresh automatically after each task.
132
+
133
+ | Key | Action |
134
+ |-----|--------|
135
+ | `Escape` | Back to calendar |
136
+ | `r` | Refresh health stats |
137
+
138
+ ---
139
+
140
+ ## Configuration
141
+
142
+ ### Project-level config
143
+
144
+ Place `.git-branch-cleaner.toml` in your repository root:
145
+
146
+ ```toml
147
+ [protected]
148
+ patterns = ["release/*", "hotfix/*"]
149
+
150
+ [blacklist]
151
+ patterns = ["archive/*", "wip-*", "experiments/**"]
152
+ ```
153
+
154
+ ### Global config
155
+
156
+ Place `~/.git-branch-cleaner.toml` for user-wide rules:
157
+
158
+ ```toml
159
+ [protected]
160
+ patterns = ["personal/*"]
161
+
162
+ [blacklist]
163
+ patterns = ["deps/*"]
164
+ ```
165
+
166
+ ### Merging strategy
167
+
168
+ All sources merged (hardcoded defaults → global → project), with project config taking highest precedence.
169
+
170
+ **Hardcoded defaults** (always active): `main`, `master`, `develop` are protected. The current checked-out branch is also automatically protected.
171
+
172
+ ---
173
+
174
+ ## Keybindings Reference
175
+
176
+ ### Calendar Screen
177
+
178
+ | Key | Action |
179
+ |-----|--------|
180
+ | Click day | Select date (From or Until per mode) |
181
+ | Click `<` `>` | Navigate months |
182
+ | Click mode buttons | Toggle between From / Until selection |
183
+ | Click **Load Branches** | Proceed to branch list |
184
+ | Click **Maintenance** | Open maintenance dashboard |
185
+
186
+ ### Branch List Screen
187
+
188
+ | Key | Action |
189
+ |-----|--------|
190
+ | `Space` | Toggle row selection |
191
+ | `a` | Toggle select / deselect all eligible |
192
+ | `d` | Delete selected |
193
+ | `r` | Toggle remote deletion |
194
+ | `p` | Toggle protected visibility |
195
+ | `b` | Toggle blacklisted visibility |
196
+ | `Escape` | Back to calendar |
197
+ | `Ctrl+R` | Refresh |
198
+
199
+ ### Maintenance Screen
200
+
201
+ | Key | Action |
202
+ |-----|--------|
203
+ | `Escape` | Back to calendar |
204
+ | `r` | Refresh health stats |
205
+
206
+ ---
207
+
208
+ ## Project Structure
209
+
210
+ ```
211
+ git-cleaner/
212
+ ├── pyproject.toml # Project metadata, deps, entry point
213
+ ├── README.md
214
+ ├── src/
215
+ │ └── git_cleaner/
216
+ │ ├── __init__.py
217
+ │ ├── __main__.py # python -m git_cleaner entry
218
+ │ ├── cli.py # CLI arg parsing
219
+ │ ├── app.py # Textual TUI (Calendar, Maintenance, BranchList, Confirm)
220
+ │ ├── config.py # TOML config loading and merging
221
+ │ └── git_ops.py # Git subprocess wrapper (list, delete, gc, repack, etc.)
222
+ ├── tests/
223
+ │ ├── test_config.py # 7 tests
224
+ │ └── test_git_ops.py # 16 tests
225
+ └── uv.lock
226
+ ```
227
+
228
+ ### Module responsibilities
229
+
230
+ | Module | Role |
231
+ |--------|------|
232
+ | `cli.py` | Parse `--repo` flag, launch the TUI app |
233
+ | `app.py` | Textual screens: calendar, maintenance dashboard, branch list with DataTable, confirmation dialog |
234
+ | `config.py` | Load `.git-branch-cleaner.toml` (project + global), fnmatch pattern matching |
235
+ | `git_ops.py` | `list_branches()`, `delete_branches()`, `delete_remote_branches()`, `get_repo_root()`, `get_git_dir_size()`, `get_object_stats()`, `run_gc()`, `repack_objects()`, `prune_remote()`, `expire_reflog()` |
236
+
237
+ ---
238
+
239
+ ## Development
240
+
241
+ ```bash
242
+ # Set up
243
+ git clone https://github.com/Allentgt/Git-Cleaner
244
+ cd git-cleaner
245
+ uv sync --dev
246
+
247
+ # Run tests (23 total)
248
+ uv run pytest
249
+
250
+ # Run with verbose output
251
+ uv run pytest -v
252
+
253
+ # Run a specific test
254
+ uv run pytest tests/test_config.py -v
255
+
256
+ # Run the app
257
+ uv run git-branch-cleaner-tui --repo /path/to/repo
258
+ ```
259
+
260
+ ### Test coverage
261
+
262
+ 23 tests covering:
263
+
264
+ - Config loading and merging (defaults, project, global)
265
+ - Pattern matching (exact, wildcard, fnmatch)
266
+ - Git operations (listing, current branch detection, date filtering, deletion, remote deletion)
267
+ - Repository health (`get_git_dir_size`, `get_object_stats`)
268
+ - Maintenance tasks (`run_gc`, `repack_objects`, `prune_remote`, `expire_reflog`)
269
+ - Error handling (non-repo path, no remote configured, timeout)
270
+
271
+ ---
272
+
273
+ ## FAQ
274
+
275
+ **Q: Can I undo a deletion?**
276
+ No — `git branch -D` is irreversible. Use the confirmation dialog to review before confirming.
277
+
278
+ **Q: Does it work on Windows?**
279
+ Yes. Tested on Windows (PowerShell), macOS, and Linux. Requires Python 3.11+.
280
+
281
+ **Q: Can I delete remote branches?**
282
+ Yes. Press `r` to toggle remote deletion on, then delete normally. Branches are deleted locally first, then via `git push origin --delete`.
283
+
284
+ **Q: How are dates filtered?**
285
+ By the commit date of the branch tip (most recent commit). Both From and Until are inclusive.
286
+
287
+ **Q: Is `git gc --aggressive` safe?**
288
+ Yes. It's more CPU-intensive than standard `git gc` but performs deeper optimization. Good for repos that haven't been GC'd in months. The UI won't freeze — it runs in a background thread.
289
+
290
+ **Q: Does the maintenance dashboard modify my repo?**
291
+ Yes, the maintenance tasks run real git commands (`git gc`, `git repack`, etc.) that modify the `.git` directory. They are safe read-only operations that don't change working tree files.
292
+
293
+ ---
294
+
295
+ ## License
296
+
297
+ MIT
@@ -0,0 +1,15 @@
1
+ """
2
+ ASCII logo for git-cleaner TUI.
3
+
4
+ Rendered in the terminal using box-drawing characters.
5
+ Import and display as a Static widget with Rich markup.
6
+ """
7
+
8
+ BANNER = (
9
+ "[bold #6366F1]"
10
+ "╔═══╗ ╔═╗ ╔═══╗ ╔═══╗ ╔═══╗ ╔═══╗ ╔═══╗ ═╗ ╔╗ ╔═══╗\n"
11
+ "║ ══╝ ║ ║ ║ ║ ║ ║ ║ ║ ══╝ ║ ║║ ║║ ║ ══╝\n"
12
+ "║ ║ ║ ║ ║ ║ ║ ║ ║ ║ ║╚═╝║ ║ \n"
13
+ "╚═╝ ╚═╝ ╚═══╝ ╚═══╝ ╚═══╝ ╚═╝ ╚═══╝ ╚═╝ ╚╝ ╚═══╝"
14
+ "[/]"
15
+ )
@@ -0,0 +1,41 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 80" width="320" height="80" role="img" aria-labelledby="gc-logo-title">
2
+ <title id="gc-logo-title">git-cleaner</title>
3
+ <defs>
4
+ <linearGradient id="broom-grad" x1="0%" y1="0%" x2="100%" y2="100%">
5
+ <stop offset="0%" stop-color="#4F46E5"/>
6
+ <stop offset="100%" stop-color="#6366F1"/>
7
+ </linearGradient>
8
+ <linearGradient id="sweep-grad" x1="0%" y1="0%" x2="100%" y2="100%">
9
+ <stop offset="0%" stop-color="#10B981"/>
10
+ <stop offset="100%" stop-color="#34D399"/>
11
+ </linearGradient>
12
+ <linearGradient id="bg-grad" x1="0%" y1="0%" x2="100%" y2="100%">
13
+ <stop offset="0%" stop-color="#EEF2FF"/>
14
+ <stop offset="100%" stop-color="#E0E7FF"/>
15
+ </linearGradient>
16
+ </defs>
17
+
18
+ <!-- Circular badge background -->
19
+ <circle cx="36" cy="40" r="32" fill="url(#bg-grad)"/>
20
+ <circle cx="36" cy="40" r="32" fill="none" stroke="#4F46E5" stroke-width="2"/>
21
+
22
+ <!-- Broom handle -->
23
+ <line x1="14" y1="58" x2="44" y2="18" stroke="url(#broom-grad)" stroke-width="3.5" stroke-linecap="round"/>
24
+
25
+ <!-- Broom bristles (fan shape) -->
26
+ <line x1="42" y1="22" x2="52" y2="12" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
27
+ <line x1="44" y1="26" x2="56" y2="18" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
28
+ <line x1="44" y1="30" x2="58" y2="24" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
29
+ <line x1="44" y1="34" x2="58" y2="30" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
30
+ <line x1="42" y1="38" x2="56" y2="36" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
31
+ <line x1="40" y1="42" x2="52" y2="42" stroke="url(#sweep-grad)" stroke-width="3" stroke-linecap="round"/>
32
+
33
+ <!-- Git branch being swept (dot + branch line) -->
34
+ <circle cx="50" cy="44" r="2" fill="#10B981" opacity="0.5"/>
35
+ <path d="M48,48 Q52,44 52,36" stroke="#10B981" stroke-width="1.5" fill="none" opacity="0.4" stroke-linecap="round"/>
36
+ <circle cx="52" cy="36" r="1.5" fill="#10B981" opacity="0.3"/>
37
+
38
+ <!-- Text -->
39
+ <text x="80" y="38" font-family="system-ui, -apple-system, sans-serif" font-size="24" font-weight="700" fill="#1F2937" letter-spacing="-0.3">git-cleaner</text>
40
+ <text x="80" y="54" font-family="system-ui, -apple-system, sans-serif" font-size="11" fill="#6B7280" letter-spacing="2.5">MAINTENANCE &amp; CLEANUP</text>
41
+ </svg>