Skip to content

Commit 907ca20

Browse files
committed
feat: Add a git TUI for managing lots of feature branches.
1 parent 50d7724 commit 907ca20

File tree

78 files changed

+17892
-9
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+17892
-9
lines changed

.restyled.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
restylers:
33
- pyment:
44
enabled: false
5+
- rustfmt:
6+
image: "toxchat/restylers:rustfmt"
7+
arguments: ["--edition=2024"]
58
- "*"

BUILD.bazel

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ haskell_library(
1010
"src/GitHub/Types/Base/*.hs",
1111
"src/GitHub/Types/Base*.hs",
1212
]),
13-
ghcopts = ["-j4"],
1413
src_strip_prefix = "src",
1514
tags = [
1615
"haskell",
@@ -34,7 +33,6 @@ haskell_library(
3433
"src/GitHub/Types/Events/*.hs",
3534
"src/GitHub/Types/Event*.hs",
3635
]),
37-
ghcopts = ["-j4"],
3836
src_strip_prefix = "src",
3937
tags = [
4038
"haskell",
@@ -101,9 +99,7 @@ haskell_library(
10199

102100
hspec_test(
103101
name = "testsuite",
104-
size = "small",
105102
args = [
106-
"-j4",
107103
"+RTS",
108104
"-N4",
109105
],

stack.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
packages: [.]
3-
resolver: lts-21.9
3+
resolver: lts-21.25
44
extra-deps:
5+
- Diff-1.0.2
56
- suspend-0.2.0.0
67
- timers-0.2.0.4

tools/check-workflows.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@ showDiff a b = Text.pack . PP.render . toDoc $ diff
7878
where
7979
toDoc = Diff.prettyContextDiff (PP.text "payload")
8080
(PP.text "value")
81-
(PP.text . Text.unpack)
81+
(\(Diff.Numbered _ t) -> PP.text . Text.unpack $ t)
8282
diff = Diff.getContextDiff linesOfContext (Text.lines a) (Text.lines b)
83-
linesOfContext = 3
83+
linesOfContext = Just 3

tools/gitui/BUILD.bazel

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
load("@rules_rust//rust:defs.bzl", "rust_binary", "rust_clippy", "rust_library", "rust_test")
2+
3+
rust_library(
4+
name = "gitui_lib",
5+
srcs = [
6+
"src/diff_utils.rs",
7+
"src/engine/executor.rs",
8+
"src/engine/git.rs",
9+
"src/engine/mod.rs",
10+
"src/engine/planner.rs",
11+
"src/engine/topology.rs",
12+
"src/engine/transaction.rs",
13+
"src/engine/types.rs",
14+
"src/lib.rs",
15+
"src/patch_utils.rs",
16+
"src/runtime.rs",
17+
"src/split_state.rs",
18+
"src/state/actions.rs",
19+
"src/state/input.rs",
20+
"src/state/mod.rs",
21+
"src/state/reducer.rs",
22+
"src/state/types.rs",
23+
"src/testing.rs",
24+
"src/topology/mod.rs",
25+
"src/topology/virtual_layer.rs",
26+
"src/ui/common.rs",
27+
"src/ui/main_view.rs",
28+
"src/ui/mod.rs",
29+
"src/ui/preview_view.rs",
30+
"src/ui/prompt_view.rs",
31+
"src/ui/split_view.rs",
32+
],
33+
crate_name = "gitui",
34+
edition = "2024",
35+
visibility = ["//visibility:public"],
36+
deps = [
37+
"@crates//:anyhow",
38+
"@crates//:crossterm",
39+
"@crates//:git2",
40+
"@crates//:indexmap",
41+
"@crates//:itertools",
42+
"@crates//:petgraph",
43+
"@crates//:ratatui",
44+
"@crates//:tempfile",
45+
"@crates//:tokio",
46+
"@crates//:unicode-segmentation",
47+
],
48+
)
49+
50+
rust_binary(
51+
name = "gitui",
52+
srcs = ["src/main.rs"],
53+
edition = "2024",
54+
rustc_flags = ["-Clink-arg=-fuse-ld=bfd"],
55+
deps = [
56+
":gitui_lib",
57+
"@crates//:anyhow",
58+
"@crates//:clap",
59+
"@crates//:tokio",
60+
],
61+
)
62+
63+
TEST_SRCS = glob(["test/*.rs"])
64+
65+
[
66+
rust_test(
67+
name = test_file.replace("test/", "").replace(".rs", ""),
68+
size = "small",
69+
srcs = [test_file],
70+
data = glob(["test/snapshots/**"]),
71+
edition = "2024",
72+
rustc_flags = ["-Clink-arg=-fuse-ld=bfd"],
73+
deps = [
74+
":gitui_lib",
75+
"@crates//:anyhow",
76+
"@crates//:crossterm",
77+
"@crates//:git2",
78+
"@crates//:insta",
79+
"@crates//:petgraph",
80+
"@crates//:proptest",
81+
"@crates//:ratatui",
82+
"@crates//:regex",
83+
"@crates//:tempfile",
84+
"@crates//:tokio",
85+
],
86+
)
87+
for test_file in TEST_SRCS
88+
]
89+
90+
rust_clippy(
91+
name = "clippy",
92+
testonly = True,
93+
deps = [
94+
":gitui",
95+
":gitui_lib",
96+
] + [
97+
":" + src.replace("test/", "").replace(".rs", "")
98+
for src in TEST_SRCS
99+
],
100+
)

tools/gitui/README.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Git Stack Manager (gitui)
2+
3+
A simple Git TUI for managing branch stacks and complex branch trees.
4+
5+
## Overview
6+
7+
This tool is designed to simplify the management of "stacked" branches, where
8+
multiple feature branches are built on top of each other. It provides a visual
9+
representation of the branch hierarchy and allows for easy restructuring of
10+
entire subtrees.
11+
12+
## Key Features
13+
14+
- **Visual Branch Tree:** Automatically detects and displays the relationship
15+
between local and remote branches.
16+
- **Interactive Move:** "Grab" a branch and move it to a new parent. The tool
17+
handles the rebase of the entire subtree.
18+
- **Predictive Conflict Detection:** Highlights potential merge conflicts
19+
_while_ you are moving a branch, before any action is taken.
20+
- **Heuristic Repair (`u`):** Automatically detects when a branch has drifted
21+
from its true parent (e.g. after a remote rebase) and allows you to
22+
"converge" it back with a single keypress.
23+
- **Split Branch (`x`):** Interactively decompose a single commit into
24+
multiple sequential branches by selecting specific hunks.
25+
- **Remote Visibility:** Toggle between local-only and tracking views for
26+
`origin` and `upstream` remotes.
27+
- **Submit Workflow:** Plan and execute branch submissions to `upstream` with
28+
automatic sync to `origin`.
29+
- **Localize Remotes:** Easily create local tracking branches from remote
30+
branches by simply moving them in the tree.
31+
- **Branch Management:** Directly push (`p`), delete (`d`), reset (`r`),
32+
rename (`R`), or amend (`m`/`M`) branches from the TUI.
33+
34+
## Shortcuts
35+
36+
### Navigation
37+
38+
- `j` / `Down`: Move selection down.
39+
- `k` / `Up`: Move selection up.
40+
- `a`: Toggle showing remote branches from `origin` and `upstream`.
41+
42+
### Manipulation
43+
44+
- `Space`: Grab or drop a branch. While grabbed, use `j`/`k` to select a new
45+
parent, or `h` to move to root.
46+
- `p`: Toggle pending push (for local branches with ahead commits).
47+
- `s`: Toggle pending submit (push to `upstream`, delete from `origin`, merge
48+
to `master`).
49+
- `x`: Enter Split Branch mode (only available if 1 commit ahead of parent).
50+
- `u`: Converge diverged branch (move to heuristic parent).
51+
- `d`: Toggle pending delete.
52+
- `r`: Toggle pending reset to upstream (or rebase onto upstream if
53+
ahead/behind).
54+
- `m`: Toggle pending amend (amends current staged changes into the selected
55+
branch).
56+
- `M`: Toggle pending amend with message update.
57+
- `R`: Rename the selected branch.
58+
- `f`: Toggle pending localize (for remote branches) or fetch (for root).
59+
60+
### Execution
61+
62+
- `v`: Enter Preview mode to see planned operations and predicted conflicts.
63+
- `c`: Execute all pending operations.
64+
- `Esc`: Cancel current grab or quit the current mode.
65+
- `q`: Quit.
66+
67+
## CLI Usage
68+
69+
```bash
70+
# Start the TUI in the current directory
71+
gitui
72+
73+
# Start in a specific directory
74+
gitui --path /path/to/repo
75+
76+
# Print the current tree and exit
77+
gitui --tree
78+
79+
# Print the tree including remote branches
80+
gitui --tree --all
81+
82+
# Show the submission plan for a branch and exit
83+
gitui --submit branch-name
84+
85+
# Show the plan to fix a diverged branch (converge)
86+
gitui --converge branch-name
87+
88+
# Show the plan to sync a branch with its upstream
89+
gitui --sync branch-name
90+
```
91+
92+
## Development
93+
94+
This tool is built with:
95+
96+
- **Language:** Rust
97+
- **UI:** [Ratatui](https://ratatui.rs/)
98+
- **Git Engine:** [git2-rs](https://github.com/rust-lang/git2-rs)
99+
- **Build System:** Bazel
100+
101+
### Building
102+
103+
```bash
104+
bazel build //hs-github-tools/tools/gitui:gitui
105+
```
106+
107+
### Testing
108+
109+
```bash
110+
bazel test //hs-github-tools/tools/gitui/...
111+
```

0 commit comments

Comments
 (0)