sluuz (slu)
Canonical: gitlab.com/safteinzz/sluuz · Mirror: github.com/safteinzz/sluuz
git, but it sleuths - a git superset with cross-repo search, secret scanning, and multi-repo management
Install
No cargo yet? Rust installs the same way on every distro: rustup.rs.
It is still git
Anything git understands is forwarded verbatim, with your editor, pager, prompts, colors and exit codes intact:
Then come the parts it does not. Each one below is an interactive tool and the plain command that prints the same answer, for scripts and pipes.
Every repo at once, and a way into them

Legend: ✚ uncommitted · ↑ unpushed commits · ↓ unpulled commits

One app, five doors: slu ibranch opens it at the branches level, slu itag
at the tags level, slu ilog at the commits level and slu istash at the
stashes of the repo you are standing in.
Find a leaked string in every repo's history


notifications-worker is the case a file listing cannot find: .env was
untracked afterwards, so the secret survives only in history. The origin/ refs
say it survives on the server too.
Terms are case-insensitive and default to
password,secret,token,api_key,passwd,credentials; -t replaces that list.
Being pickaxe-based, all three also read binary and encrypted blobs.
Read history in a real diff view



Highlighted in pure Rust, so no external diff tool is required - though Enter
hands the file to yours if you want it.
Stage and review in one place

Legend: left column staged (green) · right column unstaged (red) · MM both ·
?? untracked

git status you can act on, in git's own two-column code. s stages the file
under the cursor, u unstages it and space flips it; S and U do the same
to every file the list shows, filter included. d throws away every change to
the file, or the file itself when git has no copy of it, once you type its
name. The diff pane shows the side the tab you are on is about. Works from any
subdirectory.
See what a stash holds


No more git stash show -p stash@{2} to find out what you parked. The diff is
the stash against the commit it was made on, which is what git stash show -p
prints. a applies the stash under the cursor, p pops it (applies it, then
drops it) and d drops it, which asks for its name first, since its changes
are kept nowhere else. A pop that conflicts keeps the stash, as git always does.
Untracked files stashed with -u are not listed.
Know what you have not pushed, and delete what is finished

Legend: ↑N ahead of upstream · no remote never pushed · ⚑ gone upstream
was deleted · synced in step
# -r opens on the remote's, -g on the finished ones (upstream gone)

"Finished" means upstream gone, not "merged", so a branch still alive on the remote is never suggested for deletion. A gone branch is only offered once its changes are on the remote's main line, however they got there; one holding work the remote does not have is listed apart and left for you to look at.
Git only marks a branch gone once the remote-tracking ref is really absent, and
a plain git fetch never removes one - so on a repo that does not prune, tidy
can be missing branches and says so. tidy -p, or s in ibranch, prunes
first; git config --global fetch.prune true fixes it for good.
Know which tags the remote has

Legend: ↑ not pushed · ⚑ the remote's tag is not the same as yours · ↓ only
the remote has it

git keeps no record of which tags a remote has, so slu itag asks it with git ls-remote once the list is up, and never stops to prompt for a password: a
remote that wants one reads as unreachable. Below each tag are the commits since
the tag before it on the same line of history, which is what went into that
release.
Branches do not have that wait because every clone has git keep a copy of the
remote's branches (origin/main). t offers the same for tags: one fetch rule
in this repo's .git/config, after which git keeps a copy of the remote's tags
on every fetch and push, and slu itag shows the marks at once while it checks
for anything newer. The copy lives in refs/remote-tags/, outside
refs/remotes/, so tags never show up as remote branches.
Commands
Multi-repo commands take a path (default .) and -d, --depth <N> (default
3), and slu <command> --help lists any command's full flags.
Keys
| key | does |
|---|---|
j k / ↑ ↓ |
move, faster the longer you hold it; with ctrl, move the pane below or scroll a diff |
h l / ← → |
switch tab; with ctrl, pan a diff sideways |
/ |
filter the top pane, every space-separated term has to match; ↵ keeps it, esc drops it |
ctrl-f |
the same for the pane below |
↵ |
open what is under the cursor |
esc |
step back out; cancel a question, close help or an alert |
r |
read it again from git, keeping the cursor on what it was on |
? |
every key, on every screen |
q / ctrl-c |
quit; in a box or a filter, ctrl-c is esc |
Each screen's own keys are on its bottom row, and ? lists them all.
Tab completion
Completion reuses git's own, so slu branch v<Tab> completes a real branch name
and every git subcommand, alias and flag behaves exactly like git.
Restart your shell afterwards; without --add it just prints the script. Works
in Git Bash and WSL too.
Compatibility
Linux, macOS and Windows. Everything is passed through to your own git, so
anywhere git runs, slu runs.
License
AGPL-3.0-only