# Gitorii ⛩️
A human-first Git client. Simpler commands, built-in safety nets, and multi-platform support — designed for developers who want to focus on code, not version control syntax.
> Git was designed for Linus, by Linus. Gitorii is designed for everyone — including AI.
## Install
**Prebuilt binaries** (Linux / macOS):
```bash
**Windows** (PowerShell):
```powershell
> **If the installer URL above 404s** (the wrapper script isn't generated yet
> as of 0.6.7), grab the raw binary directly from the GitLab Generic Package
> Registry — they're produced by CI on every tag and live forever at:
>
> - <https://gitlab.com/paskidev/gitorii/-/releases> (release page with assets)
> - Direct: `https://gitlab.com/api/v4/projects/paskidev%2Fgitorii/packages/generic/gitorii/v0.6.7/torii-linux-x86_64`
>
> ```bash
> curl -L "https://gitlab.com/api/v4/projects/paskidev%2Fgitorii/packages/generic/gitorii/v0.6.7/torii-linux-x86_64" \
> -o ~/.local/bin/torii && chmod +x ~/.local/bin/torii
> ```
>
> Replace `v0.6.7` with the latest tag (see <https://gitlab.com/paskidev/gitorii/-/tags>).
> Aliases: `torii-linux-aarch64`, `torii-windows-x86_64.exe`.
**Via `cargo binstall`** (fetches prebuilt binary):
```bash
cargo binstall gitorii
```
**From source via cargo** (compiles locally):
```bash
cargo install gitorii --locked
```
> Note `--locked` — respects the committed `Cargo.lock` so you build the exact
> dep graph the maintainer tested with. See **Known issue** below if you hit a
> rustc ICE or SIGSEGV.
> **Building from source needs only a C compiler** (`gcc` or `clang`).
> No `perl`, no `openssl-dev`, no `libssh2-dev`, no `pkg-config`.
> Since 0.6.0, gitorii uses pure-Rust HTTPS (`rustls`) and SSH (`russh`)
> transports instead of libcurl/libssh2/openssl.
### Known issue: rustc ICE / SIGSEGV when compiling from source
`cargo install gitorii` can fail in two distinct ways depending on your
toolchain. Both are upstream bugs triggered by the transitive crypto chain
that `russh` pulls in (`rsa 0.10-rc` → `crypto-bigint 0.7-rc` →
`elliptic-curve 0.14-rc`). **Neither is a gitorii bug.**
**1. `rustc 1.95.0` ICE in mono-item partitioning.** Symptom:
```
thread 'rustc' panicked at compiler/rustc_span/src/symbol.rs:2760
called `Option::unwrap()` on a `None` value
```
The crate ships a `rust-toolchain.toml` pinning the build to `1.94.0`, which
`rustup` honours automatically when invoked from inside the unpacked crate
directory. If you have `rustup`, you may need nothing more than:
```bash
rustup install 1.94.0
cargo install gitorii --locked
```
If `rustup` isn't picking up the pin (some shells / cargo configurations
override it), force the toolchain explicitly:
```bash
cargo +1.94.0 install gitorii --locked
```
**2. `SIGSEGV` in LLVM codegen / stack overflow.** Symptom:
```
error: rustc interrupted by SIGSEGV, printing backtrace
... LlvmCodegenBackend ... compile_codegen_unit ...
help: you can increase rustc's stack size by setting RUST_MIN_STACK=16777216
```
This bites independent of rustc version when generics monomorphisation goes
deep enough to overflow rustc's 8 MB default thread stack, or when too many
rustcs in parallel exhaust system RAM (each codegen worker can spike to
3–5 GB). The fix is to raise the per-thread stack and cap parallelism:
```bash
RUST_MIN_STACK=16777216 \
cargo +1.94.0 install gitorii --locked -j 2
```
For maximum stability (no parallelism), use `-j 1` — slower but bulletproof.
**3. Fallback: prebuilt binary** — skip the compiler entirely. The installer
URL at the top of this section is wired to GitHub Releases but the wrapper
script isn't generated yet (as of 0.6.7). Until then, grab the binary
directly from the GitLab Generic Package Registry:
```bash
curl -L "https://gitlab.com/api/v4/projects/paskidev%2Fgitorii/packages/generic/gitorii/v0.6.7/torii-linux-x86_64" \
-o ~/.local/bin/torii && chmod +x ~/.local/bin/torii
```
Upstream tracking: `rust-lang/rust` (compiler ICE), `warp-tech/russh` (crypto
RC defaults), and our own backlog (cargo-dist for proper installer scripts).
The `rust-toolchain.toml` pin and this section will be removed once a fixed
stable rustc lands and we've validated it against the dep tree.
## Quick start
```bash
torii init # initialize repo
torii status # see what changed
torii save -am "feat: add user auth" # stage all + commit
torii sync # pull + push
```
## Command reference
### Core
| `torii init` | Initialize a repository |
| `torii save -m "msg"` | Commit staged changes |
| `torii save -am "msg"` | Stage all and commit |
| `torii save <files> -m "msg"` | Stage specific files and commit |
| `torii save --amend -m "msg"` | Amend last commit |
| `torii save --revert <hash> -m "msg"` | Revert a commit |
| `torii save --reset HEAD~1 --reset-mode soft` | Undo last commit, keep changes |
| `torii save --reset HEAD~1 --reset-mode hard` | Undo last commit, discard changes |
| `torii sync` | Pull and push |
| `torii sync --push` | Push only |
| `torii sync --pull` | Pull only |
| `torii sync --force` | Force push |
| `torii sync --fetch` | Fetch without merging |
| `torii sync <branch>` | Integrate branch (smart merge/rebase) |
| `torii sync <branch> --merge` | Force merge strategy |
| `torii sync <branch> --rebase` | Force rebase strategy |
| `torii sync <branch> --preview` | Preview without executing |
| `torii status` | Repository status |
| `torii diff` | Show unstaged changes |
| `torii diff --staged` | Show staged changes |
| `torii diff --last` | Show last commit diff |
### Workspaces
Run commands across multiple repos at once.
```bash
torii workspace add <name> ~/repos/api # add repo to workspace
torii workspace add <name> ~/repos/frontend
torii workspace list # list all workspaces
torii workspace status <name> # git status across all repos
torii workspace save <name> -m "wip" --all # commit all repos with changes
torii workspace sync <name> # pull + push all repos
torii workspace remove <name> ~/repos/api # remove a repo
torii workspace delete <name> # delete workspace
```
### Branches
```bash
torii branch # list local branches
torii branch --all # list local and remote branches
torii branch <name> -c # create and switch
torii branch <name> # switch to branch
torii branch -d <name> # delete branch
torii branch --rename <name> # rename current branch
```
### Worktrees
Multiple checkouts of the same repo, each on its own branch, sharing objects. Great for hot-fixes without disturbing in-progress work.
```bash
torii worktree # default: list
torii worktree add -b feature/auth # new branch + worktree at ../<repo>-feature-auth/
torii worktree add ../hotfix release/0.7 # check out existing branch in a worktree
torii worktree list # all worktrees with branch + clean/dirty + ahead/behind
torii worktree remove ../hotfix # delete worktree (snapshot taken automatically)
torii worktree remove ../hotfix --force # ...even if dirty
torii worktree prune # clean up metadata of deleted worktrees
torii worktree open ../hotfix # launch $SHELL inside the worktree
```
Default path comes from `worktree.base_dir` config (default `..`). `worktree.inherit_paths` automatically copies/symlinks `.env`, `target/`, `node_modules/` etc. into new worktrees so you don't rebuild from scratch:
```bash
torii config set worktree.inherit_paths ".env,target,node_modules"
```
### Submodules
Embed another git repo at a path and commit pinned at a specific commit.
```bash
torii submodule # default: status
torii submodule add git@github.com:owner/lib.git vendor/lib --branch main
torii submodule status # list with HEAD / working / state
torii submodule init # copy .gitmodules URLs to .git/config
torii submodule update --init # init missing + checkout pinned commit
torii submodule sync # re-copy URLs (after upstream URL change)
torii submodule foreach 'cargo build' # run command in each submodule
torii submodule remove vendor/lib # deregister + scrub all four state locations
```
### Subtrees
Merge another project's history into a subdirectory of this repo, flattening it into your tree. Thin wrapper over `git subtree` (must be installed).
```bash
torii subtree add --prefix=vendor/lib git@... main --squash # initial import
torii subtree pull --prefix=vendor/lib git@... main --squash # fetch upstream changes
torii subtree push --prefix=vendor/lib git@... main # push subtree back upstream
torii subtree split --prefix=vendor/lib -b lib-split # extract history to a new branch
```
Submodule vs subtree quick choice: submodule when the dep is a black box you bump occasionally; subtree when you patch it locally and want one cohesive history.
### Inspect
```bash
torii show # show HEAD commit with diff
torii show <hash> # show specific commit
torii show <tag> # show tag details
torii show <file> --blame # line-by-line change history
torii show <file> --blame -L 10,20 # specific line range
```
### History
```bash
torii log # last 10 commits
torii log -n 50 # last 50 commits
torii log --oneline # compact view
torii log --graph # branch graph
torii log --author "Alice" # filter by author
torii log --since 2026-01-01 # filter by date
torii log --grep "feat" # filter by message
torii log --stat # show file change stats
torii log --reflog # HEAD movement history
torii sync --verify # verify local vs remote HEAD
torii show <file> --blame # line-by-line change history (was: torii blame, deprecated)
torii show <file> --blame -L 10,20
torii scan # scan staged files for secrets
torii scan --history # scan entire git history
torii cherry-pick <hash> # apply commit to current branch
torii cherry-pick --continue
torii cherry-pick --abort
torii history rewrite "2026-01-01" "2026-03-01" # rewrite commit dates
torii history compact # pack objects + expire reflog (alias: gc)
torii history orphans # find unreachable objects (alias: fsck)
torii history remove-file <path> # purge file from entire history
torii history rebase main # rebase onto branch
torii history rebase HEAD~5 -i # interactive rebase (opens editor)
torii history rebase --root # rebase from root commit (squash initial)
torii history rebase HEAD~5 --todo-file plan.txt
torii history rebase --continue
torii history rebase --abort
torii history rebase --skip
torii history reauthor --old "Old <a@x>" --new "New <b@y>" # rename author in history
torii history reauthor --old oldname --new "New <b@y>" # match by name only
torii history reauthor --old a@x --new "New <b@y>" --committer # also committer
torii history reauthor ... --since v0.6.0 --dry-run # preview a range
torii history mailmap apply # batch via .mailmap
torii history mailmap apply --file other.mailmap --dry-run
```
`reauthor` and `mailmap apply` take a safety snapshot before rewriting
(revert with `torii snapshot restore <id>`), preserve timestamps,
rewrite annotated-tag taggers to match, and abort on pending operations
or dirty working trees. GPG signatures invalidate after rewrite —
re-sign manually if needed.
### Security scanner
```bash
torii history scan # scan staged files for secrets
torii history scan --history # scan entire git history
```
Runs automatically before every `torii save`. Detects:
- JWT tokens, AWS keys (AKIA/ASIA), GitHub/GitLab tokens
- Stripe live keys, Twilio/SendGrid/Brevo keys
- PEM private keys, database connection strings with credentials
- Generic API keys and passwords
Files named `*.example`, `*.sample`, or `*.template` are always skipped.
### Ignore rules (`.toriignore` + `.toriignore.local`)
`.toriignore` extends `.gitignore` syntax with optional sections for custom secret patterns, file size limits, and pre/post hooks. It is auto-synced into `.git/info/exclude` so `git` itself respects the rules.
```bash
torii ignore add 'build/' # add path to public .toriignore
torii ignore add --local '/internal/billing/' # add path to .toriignore.local
torii ignore secret 'AKIA[0-9A-Z]{16}' --name AWS # add secret regex (defaults to .local)
torii ignore secret 'ghp_[A-Za-z0-9]{36}' --public # add to public .toriignore (warns)
torii ignore list # show effective rules (merged)
```
**`.toriignore.local`** is machine-private — gitignored automatically and never committed. Use it for rules whose existence would aid recon if the public repo leaked: proprietary secret formats, internal paths, custom audit regex. Local rules merge on top of public ones; tighter local size limits override public ones.
```
# .toriignore # .toriignore.local (private)
[secrets] [secrets]
deny: AKIA[0-9A-Z]{16} deny: PROP_[a-z]{20} # internal
[size] [size]
max: 10MB max: 5MB # tighter wins
```
### Snapshots
Snapshots are local saves — not commits. Use them before risky operations.
```bash
torii snapshot create -n "before-refactor"
torii snapshot list
torii snapshot restore <id>
torii snapshot delete <id>
torii snapshot stash # quick stash
torii snapshot stash -u # include untracked files
torii snapshot unstash
torii snapshot unstash <id> --keep
torii snapshot undo # undo last operation
```
### Tags
```bash
torii tag create v1.0.0 -m "Release"
torii tag list
torii tag delete v1.0.0
torii tag push v1.0.0
torii tag push # push all tags
torii tag show v1.0.0
torii tag create --release # auto-bump from conventional commits
torii tag create --release --bump minor # force bump type
torii tag create --release --dry-run # preview without creating
```
`torii tag create --release` reads commits since the last tag and bumps following [Conventional Commits](https://www.conventionalcommits.org/):
- `feat:` → minor bump
- `fix:` / `perf:` → patch bump
- `feat!:` / breaking → major bump
### Mirrors
Mirror your repository across multiple platforms simultaneously.
```bash
torii mirror add gitlab user <username> <repo> --primary
torii mirror add github user <username> <repo>
torii mirror add codeberg user <username> <repo>
torii mirror sync
torii mirror sync --force
torii mirror list
torii mirror promote gitlab user
torii mirror remove github user
torii mirror autofetch --enable --interval 30m
torii mirror autofetch --disable
torii mirror autofetch --status
```
Supported platforms: GitHub, GitLab, Codeberg, Bitbucket, Gitea, Forgejo.
### Remote repository management
Create and manage repositories directly from the CLI (requires auth token in config):
```bash
torii remote create github <repo> --public
torii remote create github <repo> --private --description "My repo"
torii remote delete github <owner> <repo> --yes
torii remote visibility github <owner> <repo> --public
torii remote configure github <owner> <repo> --default-branch main
torii remote info github <owner> <repo>
torii remote list github
# Multiple platforms at once (comma-separated)
torii remote create github,gitlab,codeberg <name> --public --push
torii remote delete github,gitlab <owner> <name> --yes
```
### Config
```bash
torii config set user.name "Alice"
torii config set user.name "Alice" --local
torii config get user.name
torii config list
torii config list --local
torii config edit
torii config reset
```
Available keys: `user.name`, `user.email`, `user.editor`, `auth.github_token`, `auth.gitlab_token`, `auth.gitea_token`, `auth.forgejo_token`, `auth.codeberg_token`, `git.default_branch`, `git.sign_commits`, `git.pull_rebase`, `mirror.default_protocol`, `mirror.autofetch_enabled`, `snapshot.auto_enabled`, `snapshot.auto_interval_minutes`, `ui.colors`, `ui.emoji`, `ui.verbose`, `ui.date_format`, `worktree.base_dir`, `worktree.inherit_paths` (comma-separated).
### Auth (gitorii.com cloud)
Separate from the per-platform `auth.<platform>_token` keys above. `torii auth` manages the API key for gitorii.com cloud features (CI transpile, etc.), stored at `~/.config/torii/auth.toml` (chmod 600).
```bash
torii auth login # prompt for API key and save
torii auth login --key gitorii_sk_… # save non-interactively
torii auth status # show org / plan / seats
torii auth whoami # alias of status
torii auth logout # forget the local key
```
Override per-process with `TORII_API_KEY=gitorii_sk_…`. Generate keys at <https://gitorii.com/dashboard/api-keys>.
### Pull requests
Works against the platform of the current repo (GitHub, GitLab, Codeberg, etc.). Requires `auth.<platform>_token` to be set.
```bash
torii pr list # list open PRs
torii pr create -t "wip" --draft # create as draft
torii pr merge 42 # merge with merge commit
torii pr merge 42 --method squash|rebase
torii pr close 42 # close without merging
torii pr checkout 42 # checkout PR branch locally
torii pr open 42 # open in browser
```
### Issues
```bash
torii issue list # open issues
torii issue create -t "title" -d "description"
torii issue close 42
torii issue comment 42 -m "Fixed in v0.6.6"
```
### Other
```bash
torii clone github <user>/<repo> # clone with platform shorthand
torii clone https://... # clone with full URL
torii clone github <user>/<repo> -d dir # clone into specific directory
torii config check-ssh # verify SSH key setup
```
## TUI
Launch the interactive terminal UI:
```bash
torii tui
```
Full-screen interface with sidebar navigation. All views accessible from keyboard.
| `↑↓` / `j k` | Navigate sidebar (previews view in real time) |
| `Tab` / `Enter` | Enter selected view |
| `Esc` | Return to sidebar |
| `q` / `Ctrl+C` | Quit |
| `e` | Toggle event log |
| `?` | Help |
**Views** (navigate with sidebar or shortcut key):
| `f` | files | Staged / unstaged / untracked files. `Space` to stage/unstage, `d` for diff |
| `c` | save | Commit staged files. Optional conventional commit type selector |
| `s` | sync | Pull, push, fetch, force-push. Animated progress, non-blocking |
| `p` | snapshot | Create, restore, delete snapshots. Auto-snapshot with configurable interval |
| `l` | log | Commit history. `Enter` diff, `r` reset soft, `b` new branch |
| `b` | branch | List branches, checkout with `Enter` |
| `t` | tags | List tags, push/delete |
| `h` | history | Reflog and history rewrite operations |
| `r` | remote | Remote repository info |
| `m` | mirror | Mirror sync |
| `w` | workspace | Multi-repo workspace management |
| `g` | config | Edit repo/global config inline |
| `x` | settings | TUI appearance, keybinds, visible views |
**Diff view** — LCS-based inline char highlighting, paired +/- lines, hunk separators, line numbers.
**Snapshot auto-interval** — configurable per-repo in `.torii/auto-interval` (travels with the project).
**Settings** — customizable brand color, border style, keybinds. Saved in `~/.torii/tui-settings.toml`.
## Gitorii vs other Git clients
| Pure CLI (no TUI required) | ✓ | ✗ | ✗ | ✗ | ✗ | ✓ |
| Optional TUI with full feature parity | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ |
| Secret scanner (pre-commit) | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Scan full git history | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Snapshots (pre-op safety saves) | ✓ | ✗ | ✗ | ✗ | ~ | ✗ |
| Multi-remote mirrors | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Workspace (multi-repo commands) | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| PR / MR creation from CLI | ✓ | ~ | ✗ | ✗ | ~ | ✓ |
| GitHub + GitLab native support | ✓ | ✗ | ✗ | ✗ | ~ | ✗ |
| Conventional commits auto-tag | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Remove file from entire history | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ |
| Interactive rebase | ✓ | ✓ | ~ | ✗ | ✓ | ✗ |
| No runtime dependencies | ✓ | ✗ | ✓ | ✓ | ✗ | ✗ |
> ✓ supported · ~ partial · ✗ not supported
> Full comparison at [gitorii.com/vs](https://gitorii.com/vs)
## Why Gitorii?
| `git add . && git commit -m "msg"` | `torii save -am "msg"` |
| `git pull && git push` | `torii sync` |
| `git switch -c branch` | `torii branch <name> -c` |
| `git fetch` | `torii sync --fetch` |
| `git reset --soft HEAD~1` | `torii save --reset HEAD~1 --reset-mode soft` |
| `git rebase -i HEAD~3` | `torii history rebase HEAD~3 -i` |
| `git stash push -u` | `torii snapshot stash -u` |
| `git log --oneline --author X` | `torii log --oneline --author X` |
| `git show HEAD` | `torii show` |
| `git blame src/main.rs` | `torii show src/main.rs --blame` |
| Push to 3 platforms | `torii mirror sync` |
| Hunt for exposed secrets | `torii scan --history` |
| Run status across 5 repos | `torii workspace status <name>` |
| Commit all dirty repos at once | `torii workspace save <name> -am "wip"` |
## System dependencies
**None at runtime** for prebuilt binaries. **Only a C compiler** when building from source.
Since 0.6.0 gitorii ships its own pure-Rust HTTPS (`rustls`) and SSH (`russh`)
transports, so libgit2 is built without HTTPS/SSH support — no openssl-dev,
no libssh2-dev, no pkg-config, no perl.
| Ubuntu/Debian | `sudo apt install build-essential` |
| Fedora/RHEL | `sudo dnf install gcc make` |
| macOS | `xcode-select --install` |
| Arch | `sudo pacman -S base-devel` |
| Alpine | `apk add build-base` |
Want a fully static binary with zero runtime libs (runs on Alpine, scratch,
busybox)? Build with the `static` feature on the musl target:
```bash
cargo build --release --target x86_64-unknown-linux-musl --features static
```
## Links
- [Website](https://gitorii.com)
- [Releases](https://github.com/paskidev/gitorii/releases)
- [Docs](https://gitorii.com/docs)
- [Issues](https://github.com/paskidev/gitorii/issues)
- [crates.io](https://crates.io/crates/gitorii)
## License
TSAL-1.0 — Free for personal and non-production use. Commercial use requires a license. Converts to Apache 2.0 after 10 years. See [LICENSE](LICENSE) for details.
## Author
Built by **Pasqual Peñalver Collado** ([PaskiDev](https://paski.dev)) — Lead Full Stack Developer in Barcelona. More projects and devlog at [paski.dev](https://paski.dev).