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.
- git_branch_cleaner_tui-1.0.0/.gitignore +31 -0
- git_branch_cleaner_tui-1.0.0/PKG-INFO +306 -0
- git_branch_cleaner_tui-1.0.0/README.md +297 -0
- git_branch_cleaner_tui-1.0.0/logo/ascii_banner.py +15 -0
- git_branch_cleaner_tui-1.0.0/logo/concept1-horizontal.svg +41 -0
- git_branch_cleaner_tui-1.0.0/logo/concept1-icon.svg +36 -0
- git_branch_cleaner_tui-1.0.0/logo/concept2-horizontal.svg +29 -0
- git_branch_cleaner_tui-1.0.0/logo/concept2-icon.svg +25 -0
- git_branch_cleaner_tui-1.0.0/logo/favicon.svg +31 -0
- git_branch_cleaner_tui-1.0.0/logo/logo-readme.svg +40 -0
- git_branch_cleaner_tui-1.0.0/logo_output.txt +0 -0
- git_branch_cleaner_tui-1.0.0/pyproject.toml +23 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/__init__.py +0 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/__main__.py +4 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/app.py +1363 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/cli.py +22 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/config.py +110 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/git_ops.py +284 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/logo.py +24 -0
- git_branch_cleaner_tui-1.0.0/src/git_cleaner/logo_data.py +3 -0
- git_branch_cleaner_tui-1.0.0/tests/__init__.py +0 -0
- git_branch_cleaner_tui-1.0.0/tests/test_config.py +53 -0
- git_branch_cleaner_tui-1.0.0/tests/test_git_ops.py +231 -0
- git_branch_cleaner_tui-1.0.0/uv.lock +190 -0
|
@@ -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
|
+

|
|
22
|
+

|
|
23
|
+

|
|
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
|
+

|
|
13
|
+

|
|
14
|
+

|
|
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 & CLEANUP</text>
|
|
41
|
+
</svg>
|