sluuz 0.10.9

git, but it sleuths - a git superset with cross-repo search, secret scanning, and multi-repo management
sluuz-0.10.9 is not a library.

sluuz (slu)

git, but it sleuths - a git superset with cross-repo search, secret scanning, and multi-repo management

Install

cargo install sluuz
slu self check   # is a newer release out?
slu self update  # install the latest

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:

slu commit -m "fix"
slu push
slu rebase -i HEAD~3
slu --no-pager log -3

-C <path> works as git's does, for slu's own commands too (slu -C ~/src repos).

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

slu irepos drilling from a repository through its branches and commits into a diff, narrowing each list by typing a filter

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

slu irepos               # every repo under here, with a way in; `s` syncs them all, `S` also pulls
slu irepos ~/projects    # or under somewhere else
slu repos                # the same list, printed
slu repos --dirty        # only the ones needing attention

slu repos listing six repositories and their state, then only the dirty ones

The same app opens at the branches, tags, commits or stashes of the repo you are in with slu ibranch, slu itag, slu ilog and slu istash.

Find a leaked string in every repo's history

slu iscan searching every repository's history for a password and browsing the hits with the diff of each

slu iscan                             # type the terms, browse the hits
slu search -r "1337-let-me-in"        # one string, every repo, printed
slu scan                              # the usual terms, printed
slu scan -t "AKIA,BEGIN RSA PRIVATE KEY"

slu scan's report over six repositories, ending in a summary of seven hits

notifications-worker is the case a file listing cannot find: .env was untracked afterwards, so the secret survives only in history, and the origin/ refs say it survives on the server too.

Read history in a real diff view

slu ilog showing a history with a side-by-side diff below it, scrolled and panned

Legend: ↑ unpushed commits · ↓ unpulled commits, which only the upstream has

slu ilog                     # this branch, and what a pull would bring in
slu ilog --all -n 500        # every branch, more history
slu ilog src/main.rs         # only commits touching that path
slu trace [-a] [-g] [-n N]   # the aligned log, printed; every branch, with a graph

slu ilog with the selected commit's diff side by side below it

slu trace -a listing every branch's history in aligned columns

Highlighted in pure Rust, so no external diff tool is needed, though Enter hands the file to yours if you want it.

Stage and review in one place

slu istatus staging and unstaging a file with its diff below, and switching between its tabs

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

slu istatus              # the two columns, with the diffs
slu status -sb           # real git, passed straight through

slu status -sb and slu log as git prints them

git status you can act on, in git's own two-column code: s stages, u unstages, and S and U do it to every file the list shows. c commits what is staged, and d throws a file's changes away once you type its name.

See what a stash holds

slu istash listing two stashes with the files each one holds, opening their diffs, then asking for a stash's name before dropping it

slu istash               # every stash, its files and their diffs
slu stash list           # real git, passed straight through

slu stash list and slu stash show as git prints them

No more git stash show -p stash@{2} to find out what you parked. a applies, p pops and d drops, asking for the stash's name first, since its changes are kept nowhere else.

Know what you have not pushed, and delete what is finished

slu ibranch listing branches with their push state across its tabs, filtering them, asking for an unpushed branch's name before it would delete it, then deleting a finished one

Legend: ↑N ahead of upstream · no remote never pushed · ⚑ gone upstream was deleted · synced in step

slu ibranch [-r|-g]      # push state of your branches; `d` deletes, `s` syncs, `S` also pulls
                         # -r opens on the remote's, -g on the finished ones (upstream gone)
slu tidy [path] [-a]     # finished branches across every repo, with a delete command to paste
slu tidy -p              # the same, after dropping remote branches that are gone

slu tidy -a reporting the finished branches across six repositories

"Finished" means upstream gone, not "merged", so a branch still alive on the remote is never suggested, and one holding work the remote does not have is listed apart for you to look at.

Know which tags the remote has

slu itag marking three tags against the remote, asking for a pushed one's name before it would delete it everywhere, opening another's commits and a diff, and deleting that one

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

slu itag                 # every tag against the remote, and what went into each
slu tag -n               # real git, passed straight through

slu tag -n as git prints it

git keeps no record of a remote's tags, so slu itag asks the remote once the list is up and never stops for a password. t adds one fetch rule so git keeps a copy of them, and the marks then show at once.

See where every remote stands

slu iremote measuring a fork's main against origin and upstream, pushing it to origin, opening upstream's branches and their commits, then adding a remote through a form and removing it behind a gate

Legend: ↑N commits that remote lacks · ↓N commits only it has · · no local branch tracks it

slu iremote              # every remote against this branch; `p` pushes, `s` syncs, `S` also pulls
slu branch -vv           # real git, passed straight through

slu remote and slu branch -vv as git prints them

p never forces and sets an upstream only on a branch that has none, so pushing a fork's work to upstream never changes where it pulls from.

Commands

slu sync [path] [--pull]       # fetch and prune every repo, optionally fast-forward
slu each <git args>            # run any git command in every repo, in parallel

Multi-repo commands take a path (default .) and -d N (default 3), slu <command> --help has every flag, and ? in any screen lists every key.

Every interactive tool has a plain command that prints the same answer for scripts and pipes, and anything passed through keeps git's own output and exit code.

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.

slu completions bash --add     # writes the loader into ~/.bashrc
slu completions zsh  --add     # ~/.zshrc
slu completions fish --add     # ~/.config/fish/config.fish

Restart your shell afterwards; without --add it just prints the script. Works in Git Bash and WSL too.

What it edits

.git/config          one fetch rule for the remote's tags, when you press t in slu itag
refs/remote-tags/    git's copy of the remote's tags, kept apart from branches

Notes

  • scan terms are case-insensitive and default to password,secret,token,api_key,passwd,credentials, and being pickaxe-based they also read binary and encrypted blobs.
  • Git marks a branch gone only once its remote-tracking ref is pruned, so on a repo that never prunes tidy can miss branches and says so; tidy -p or s in ibranch prunes first, and git config --global fetch.prune true fixes it for good.
  • A stash's diff is against the commit it was made on, as git stash show -p prints it, and untracked files stashed with -u are not listed.
  • In Windows PowerShell 5.1, once the Microsoft.PowerShell.LocalAccounts module loads (running Get-LocalUser loads it), slu is its alias for Set-LocalUser: type slu.exe there.

Compatibility

Linux, macOS and Windows. Everything is passed through to your own git, so anywhere git runs, slu runs.

License

AGPL-3.0-only