Git repos, organized
cargo install pjior
brew install zhanba/tap/pji| Option | Description |
|---|---|
-n, --non-interactive |
Force non-interactive mode. This is also enabled automatically when stdin, stdout, or stderr is not attached to a terminal |
--root <DIR> |
Select a root directory without prompting |
| Command | Description |
|---|---|
pji [QUERY] |
Fuzzy find and cd into a repository (default) |
pji add <URL> |
Clone and register a repository |
pji remove <URL> [-y] |
Remove a repository |
pji list [-l] |
List repositories (-l for detailed view) |
pji scan |
Discover and add existing repositories |
pji config [ROOT] |
Configure root directories |
pji clean |
Remove pji metadata and config |
| Command | Description |
|---|---|
pji open [REPO] |
Open repository homepage |
pji open pr [NUMBER] |
Open pull request page |
pji open issue [NUMBER] |
Open issue page |
| Command | Description |
|---|---|
pji wt |
Switch between worktrees (default) |
pji wt add [BRANCH] |
Create a worktree |
pji wt list |
List all worktrees |
pji wt remove [WORKTREE] [-y] |
Remove a worktree |
pji wt prune |
Clean up stale worktree info |
pji automatically runs in non-interactive mode when stdin, stdout, or stderr is
not attached to a terminal, such as in scripts, CI, command substitution, pipes,
or redirected output. You can also force this behavior with -n or
--non-interactive.
In non-interactive mode, pji never opens prompts or fuzzy selectors. Commands that normally switch into a repository or worktree print the target path instead of opening a shell, so they can be used from scripts:
cd "$(pji find pji)"
cd "$(pji wt sw feature/login)"If an operation would require a choice, pji fails and asks for more specific
input. For example, use a narrower query when multiple repositories or
worktrees match. If multiple roots are configured, pass --root <DIR> to choose
one explicitly.
Destructive commands still require explicit confirmation. In non-interactive
mode, pass --yes for commands such as pji remove or pji wt remove.
pji -n find pji
pji -n --root ~/pji add git@github.com:zhanba/pji.git
pji -n wt add feature/login --path ../pji.worktrees/feature-login
pji -n wt remove feature/login --yespji also exposes a small, stable API for other Rust apps. Use Pji as the
entry point; internal CLI modules are not part of the public contract. The
CLI's interactive and non-interactive behavior is handled by the binary, so
library callers should make their own selection and confirmation decisions.
The API is split into a few groups:
- State:
Pji::load,Pji::save,Pji::roots,Pji::add_root,Pji::repositories, andPji::repositories_by_last_openedread and write pji's config and metadata. - Repository helpers:
GitUrl::parse,Pji::parse_git_url, andPji::repository_pathparse URLs and compute pji's on-disk layout without running git. - Repository operations:
clone_repository,unregister_repository,is_repository_registered,find_repositories,scan,resolve_repository, andmark_repository_openedmanage repository metadata and discovery. - Worktree operations:
list_worktrees,default_worktree_path,add_worktree,remove_worktree,prune_worktrees,local_branches, andremote_brancheswrap git worktree and branch commands.
Methods that mutate config or metadata do not automatically save every change.
Call pji.save()? after changes you want to persist. Methods that run git
commands return PjiError::GitCommand if git exits unsuccessfully.
use pji::{AddWorktreeRequest, GitUrl, Pji, PjiError};
fn main() -> Result<(), PjiError> {
let mut pji = Pji::load()?;
let root = Pji::default_root()?;
pji.add_root(&root);
pji.save()?;
let git = GitUrl::parse("git@github.com:zhanba/pji.git")?;
let repo_path = Pji::repository_path(&root, &git);
println!("{}", repo_path.display());
if !pji.is_repository_registered(&git.original, &root)? {
pji.clone_repository(&git.original, &root)?;
pji.save()?;
}
let matches = pji.find_repositories("pji");
for repo in &matches {
println!("{}", repo.dir.display());
}
if let Some(repo) = matches.first() {
let worktree_path = Pji::default_worktree_path(&repo.dir, "feature/login");
pji.add_worktree(AddWorktreeRequest {
repo_dir: repo.dir.clone(),
branch: "feature/login".to_string(),
path: Some(worktree_path),
create_branch: true,
base_branch: Some("main".to_string()),
})?;
}
pji.scan()?;
pji.save()?;
Ok(())
}$ROOT/
├── github.com/
│ └── user/
│ └── repo/
└── gitlab.com/
└── user/
└── repo/
MIT