<div align="center">
<h1>stax</h1>
<p>
Fast stacked Git branches and PRs. A Rust rewrite of <a href="https://github.com/bradymadden97/freephite">freephite</a>.
</p>
<p>
<img alt="Startup" src="https://img.shields.io/badge/startup-~18ms-brightgreen">
<img alt="Git" src="https://img.shields.io/badge/git-git2-f34f29">
<img alt="Async" src="https://img.shields.io/badge/async-tokio-2f74c0">
<img alt="License" src="https://img.shields.io/badge/license-MIT-green">
</p>
</div>
## Install
```bash
cargo install --git https://github.com/cesarferreira/stax
```
Or build from source:
```bash
git clone https://github.com/cesarferreira/stax
cd stax
cargo install --path .
```
## Quick Start
```bash
# Authenticate with GitHub (for PR creation)
stax auth
# Create your first stacked branch
stax bc feat/my-feature
# Make changes, commit, then create another branch on top
stax bc feat/another-feature
# View your stack
stax s
# Submit all branches as PRs
stax ss
# When parent branch changes, sync and restack
stax rs --restack
```
## Commands
### Shortcuts (freephite compatible)
| `stax ss` | **S**ubmit **s**tack - push branches and create/update PRs |
| `stax rs` | **R**epo **s**ync - pull trunk, delete merged branches |
| `stax rs --restack` | Repo sync + restack branches |
| `stax bco` | **B**ranch **c**heck**o**ut - interactive branch picker |
| `stax bc <name>` | **B**ranch **c**reate - create a new stacked branch |
| `stax bc -m "msg"` | Create branch from message (spaces replaced) |
| `stax bu` | **B**ranch **u**p - move to child branch |
| `stax bd` | **B**ranch **d**own - move to parent branch |
### Full Commands
| `stax status` | `s`, `ls` | Show the current stack (simple view) |
| `stax log` | `l` | Show stack with commits and PR info |
| `stax sync` | `rs` | Pull trunk, delete merged branches |
| `stax sync --restack` | | Also restack after syncing |
| `stax restack` | | Rebase current branch onto parent |
| `stax restack --all` | | Restack all branches that need it |
| `stax submit` | `ss` | Push and create/update PRs |
| `stax submit --draft` | | Create PRs as drafts |
| `stax submit --no-pr` | | Just push, skip PR creation |
| `stax checkout [branch]` | `co`, `bco` | Checkout a branch (interactive if no arg) |
| `stax up` | `bu` | Move up the stack (to child branch) |
| `stax down` | `bd` | Move down the stack (to parent branch) |
| `stax continue` | `cont` | Continue after resolving conflicts |
| `stax auth` | | Set GitHub personal access token |
| `stax config` | | Show config file path and contents |
### Branch Commands
| `stax branch create <name>` | `b c` | Create a new stacked branch |
| `stax branch checkout` | `b co` | Interactive branch checkout |
| `stax branch track` | | Track an existing branch |
| `stax branch delete` | `b d` | Delete a branch |
### Upstack/Downstack
| `stax upstack restack` | `us restack` | Restack all branches above current |
| `stax downstack get` | `ds get` | Show branches below current |
## Example Workflow
```bash
# Start on main
git checkout main
# Create a stacked branch for your feature
stax bc feat/auth-api
# Make changes and commit
git add . && git commit -m "Add auth API"
# Create another branch on top
stax bc feat/auth-ui
# Make more changes
git add . && git commit -m "Add auth UI"
# View your stack
stax s
# │ ◉ feat/auth-ui ← you are here
# │ ○ feat/auth-api
# ○─┘ main
# Navigate the stack
stax bd # move down to feat/auth-api
stax bu # move back up to feat/auth-ui
# Submit all PRs
stax ss
# Submitting 2 branch(es) to owner/repo...
# Pushing feat/auth-api... ✓
# Pushing feat/auth-ui... ✓
# Creating/updating PRs...
# Creating PR for feat/auth-api... ✓ #123
# Creating PR for feat/auth-ui... ✓ #124
# If main gets updated, sync and restack
stax rs --restack
```
## How It Works
stax stores stack metadata in Git refs (`refs/branch-metadata/<branch>`), the same format as freephite. This means:
- No external files or databases
- Metadata travels with your repo
- You can use both `stax` and `fp` on the same repo
Each branch tracks:
- Parent branch name
- Parent branch revision (to detect when restack is needed)
- PR info (number, state)
## Configuration
Config is stored at `~/.config/stax/config.toml`:
```toml
[branch]
prefix = "cesar/" # Auto-prefix new branches (e.g., "my-feature" → "cesar/my-feature")
date = false # Add date to branch names (e.g., "2024-01-15-my-feature")
replacement = "-" # Character to replace spaces and special chars
[ui]
tips = true # Show helpful tips
```
View your config with `stax config`.
### GitHub Authentication
GitHub token is stored **separately** from config (not in dotfiles).
**Priority order:**
1. `STAX_GITHUB_TOKEN` env var (highest)
2. `GITHUB_TOKEN` env var
3. `~/.config/stax/.credentials` file (lowest)
```bash
# Option 1: stax-specific env var (recommended)
export STAX_GITHUB_TOKEN="ghp_xxxx"
# Option 2: Generic GitHub token
export GITHUB_TOKEN="ghp_xxxx"
# Option 3: Use stax auth command (saves to credentials file)
stax auth
```
## Migrating from freephite
stax uses the same metadata format as freephite. Just install stax and your existing stacks will work:
```bash
# Your existing fp stacks just work
stax s # shows your stack
stax rs # syncs repo
stax ss # submits PRs
```
## Why Rust?
| Startup time | ~18ms | ~300ms |
| Binary size | 6.2MB | ~50MB (with node_modules) |
| Dependencies | Compiled in | npm install required |
## License
MIT