# Gitforest

A terminal UI for managing multiple Git repositories and GitHub integration.

Built with Bun, TypeScript, Ink (React for CLI), and Drizzle ORM.

## Features

- **Project Discovery**: Scan configured directories for git repos, non-git projects, and submodules
- **Git Status Dashboard**: See unstaged changes, unpushed/unpulled commits, sync status
- **Sort & Filter**: Sort by status, name, branch, sync, language, stars, forks, activity, or size; filter by text search and quick filters
- **Git Operations**: Init git, pull, push, fetch for single or all repos
- **GitHub Integration**: Create, archive, list, and clone GitHub repos using `gh` for auth and the GitHub API for data
- **Background Sync**: Auto-fetch remotes every 5 minutes
- **Caching**: SQLite cache for fast subsequent runs

## Installation

```bash
# From the gitforest directory
bun install

# Create config file
bun run start --init

# Edit config to add your project directories
vim ~/.config/gitforest/config.yaml

# Run gitforest
bun run start
```

## Configuration

Config file location: `~/.config/gitforest/config.yaml`. For project-local
workflows, `gitforest.config.yaml` in the current directory takes priority;
review that file before running Gitforest in an untrusted checkout.

```yaml
directories:
  - path: ~/projects
    maxDepth: 2
    label: Projects
  - path: ~/.dotfiles
    maxDepth: 3
    label: Dotfiles

scan:
  ignore:
    - node_modules
    - .git
    - vendor
  includeHidden: false
  concurrency: 5

github:
  defaultVisibility: private

display:
  showSubmodules: true
  sortBy: status # status | name | branch | sync | language | stars | forks | lastActivity | size
  sortDirection: desc

# Optional custom commands. These execute via `sh -c` in the selected project
# directory with your normal user privileges. Confirmation defaults to true;
# set `confirm: false` only for commands you fully trust.
commands:
  - name: "Run Tests"
    key: "t"
    command: "bun test"
    confirm: true
```

## Keyboard Shortcuts

### Navigation

| Key       | Action       |
| --------- | ------------ |
| `j` / `↓` | Move down    |
| `k` / `↑` | Move up      |
| `g`       | Go to top    |
| `G`       | Go to bottom |

### Selection

| Key     | Action                    |
| ------- | ------------------------- |
| `space` | Toggle selection          |
| `a`     | Select all / deselect all |

### Git Operations

| Key | Action                                |
| --- | ------------------------------------- |
| `p` | Push selected repos                   |
| `P` | Pull all repos                        |
| `f` | Fetch all remotes                     |
| `i` | Init git in selected non-git projects |

### GitHub Operations

| Key | Action                                      |
| --- | ------------------------------------------- |
| `c` | Create GitHub repo for selected local repos |
| `C` | Init git if needed, then create GitHub repos |
| `A` | Archive selected GitHub repos               |
| `D` | Clone selected GitHub-only repos            |

### View Controls

| Key       | Action                                |
| --------- | ------------------------------------- |
| `Tab`     | Cycle local/GitHub/all views          |
| `/`       | Enter filter mode                     |
| `F`       | Show filter options                   |
| `0`-`9`   | Apply quick filters                   |
| `s` / `S` | Cycle sort field / reverse direction  |
| `x`       | Open custom command palette           |
| `r`       | Refresh project list                  |
| `?`       | Show help                             |
| `q`       | Quit                                  |

## Status Icons

| Icon | Meaning                     |
| ---- | --------------------------- |
| ✓    | Clean (no changes)          |
| ●    | Dirty (uncommitted changes) |
| ○    | Submodule                   |
| -    | Not a git repo              |
| ↑N   | N unpushed commits          |
| ↓N   | N unpulled commits          |

## Project Detection

Gitforest detects projects by looking for:

- `.git` directory (git repository)
- `.gitmodules` file (for submodules)
- Project marker files:
  - `package.json` (Node.js)
  - `Cargo.toml` (Rust)
  - `pyproject.toml` / `setup.py` (Python)
  - `go.mod` (Go)
  - `Gemfile` (Ruby)
  - `pom.xml` / `build.gradle` (Java)
  - And more...

## Requirements

- [Bun](https://bun.sh/) runtime
- [gh CLI](https://cli.github.com/) for GitHub operations (optional but recommended)

Custom commands are intentionally not a security sandbox. They can read or
modify anything your user account can access, so only run trusted configuration
files and review commands before disabling confirmation.

## Development

```bash
# Run in development mode with hot reload
bun run dev

# Run tests (recommended - handles test isolation)
bun run test

# Or run specific test groups
bun run test:unit          # Unit tests only
bun run test:hooks         # Hooks tests (includes isolated useKeyBindings)
bun run test:db            # Database tests
bun run test:integration   # Integration tests
bun run test:fast          # Fast unit tests (skips scanner/git)
```

## Architecture

```
src/
├── app.tsx                 # Root Ink application
├── config/                 # Config loading & validation (Zod)
├── db/                     # Drizzle + SQLite cache
├── services/               # Git, GitHub, editor, and README adapters
├── github/                 # GitHub auth, cache, CLI URL parsing, unified view
├── scanner/                # Directory scanning
├── components/             # Ink UI components
├── hooks/                  # React hooks
├── state/                  # State management
└── types/                  # TypeScript types
```
