Turn overview into an inventory across local and server
overview showed dirty and ahead/behind per project, which git can do on its own. mgsh is the only thing that sees both the local base directory and the ssh server, and joining those answers the questions git cannot: which projects were never pushed to the server (candidates for `init`), and which exist there but not on this machine (candidates for `clone`). Both lists are printed after the summary. An unreachable server is reported as such, rather than as "everything is missing". Each row also names the machine that made the last commit and how long ago. That costs nothing: `push` has always stamped "[user@host]" into the commit message, and nothing ever read it back. On a setup spanning several machines it is usually the piece one actually wanted. Rows also show which mirror targets the repository has a remote for, which is local git config and therefore free. The walk is now concurrent and cheaper per project: `git status --porcelain=v2 --branch` yields branch, upstream, ahead/behind and dirty in one subprocess where three were used before. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ directory. Go port of the original Perl `mgsh` (`mgsh.perl`).
|
||||
## Contents
|
||||
|
||||
- [Build](#build) · [Usage](#usage) · [Commands](#commands) · [Aliases](#aliases)
|
||||
- [Overview](#overview) · [Credential check](#credential-check)
|
||||
- [Public mirror (`pushremote`)](#public-mirror-pushremote) ·
|
||||
[Releases](#releases)
|
||||
- [Configuration](#configuration) · [Settings reference](#settings-reference) ·
|
||||
@@ -80,7 +81,7 @@ Run `help` for the full list. Highlights:
|
||||
| `pushremote [desc]` | mirror the repo to a public server (gitea/github/gitlab) |
|
||||
| `pull` / `fetch` | pull / fetch from the server |
|
||||
| `status [-a]` / `diff` | short git status (`-a`: overview of all projects) |
|
||||
| `overview` | dirty / ahead-behind summary of all projects |
|
||||
| `overview` | inventory of all projects, local and on the server |
|
||||
| `log` | show the project log |
|
||||
| `edit [n]` | interactive rebase of the last n commits |
|
||||
| `clone [-a] <repo>` | clone a repository (or archive) from the server |
|
||||
@@ -125,6 +126,69 @@ pushremote targets (in push order):
|
||||
Tokens are masked, so the output is safe to paste into a bug report.
|
||||
`config -k` prints just the setting names, one per line.
|
||||
|
||||
### Overview
|
||||
|
||||
`overview` (or `status -a`) is the one view that needs mgsh: it is the only
|
||||
thing that sees the local base directory *and* the git server at once.
|
||||
|
||||
```
|
||||
< src > overview
|
||||
mgsh * ↑2 · desktop 3h · → hub,gitea
|
||||
notes ✓ · laptop 2d
|
||||
website ✓ (no upstream) · laptop 20d
|
||||
3 projects · 1 dirty · 1 in sync
|
||||
not on the git server: scratch, experiments (init)
|
||||
not cloned here: oldproject (clone)
|
||||
```
|
||||
|
||||
Per project: dirty marker, commits ahead/behind the upstream, the branch when it
|
||||
is not `master`/`main`, and the mirror targets the repository has a remote for.
|
||||
|
||||
The machine and age come from the commit itself — `push` writes `[user@host]`
|
||||
into every message, so `overview` can say where a project was last worked on
|
||||
without storing anything. On a setup spanning a laptop and a workstation that is
|
||||
usually the piece of information you actually wanted.
|
||||
|
||||
The two lists at the end are the join no git command can do: local projects the
|
||||
server has never seen (`init` them) and server repositories missing on this
|
||||
machine (`clone` them). If the server cannot be reached, mgsh says so instead of
|
||||
claiming everything is missing.
|
||||
|
||||
### Credential check
|
||||
|
||||
`push` runs `git add --all .`, so anything lying in the project gets committed —
|
||||
and with `mirror = true` it reaches a public server in the same breath. That is
|
||||
the only action in mgsh that cannot be undone: a deleted server repository comes
|
||||
back from an archive, a published credential does not.
|
||||
|
||||
So before anything is committed, the staged diff is checked for private keys,
|
||||
GitHub/GitLab/Slack/AWS/PyPI tokens and credential-shaped assignments:
|
||||
|
||||
```
|
||||
< src/notes > push new notes
|
||||
2 possible credential(s) in what is about to be committed:
|
||||
.env:3 credential assignment
|
||||
API_KEY="<the offending line is shown in full here>"
|
||||
deploy_key:1 private key
|
||||
<the BEGIN … PRIVATE KEY header is shown here>
|
||||
(set 'secretscan = off' to skip this check)
|
||||
push anyway? y/N ?
|
||||
```
|
||||
|
||||
Declining stops the push with nothing committed; the changes stay staged, so
|
||||
`git restore --staged <file>` and a `.gitignore` entry are all it takes.
|
||||
|
||||
For a line that only *looks* like a credential and is meant to stay, put
|
||||
`mgsh:allow` in it — a comment on that line is enough. That is better than
|
||||
turning the whole check off for one false positive.
|
||||
|
||||
This is not a complete secret scanner and does not try to be one. It aims for a
|
||||
high hit rate on what actually leaks, with few enough false alarms that the
|
||||
prompt still means something: values that are plainly environment references,
|
||||
constants, template slots (`<token>`, `${VAR}`) or masked stand-ins are ignored —
|
||||
a test checks that mgsh's own README and `mgshrc.example`, both full of
|
||||
credential-shaped text, stay quiet. Switch it off with `secretscan = off`.
|
||||
|
||||
### Aliases
|
||||
|
||||
`alias <name> '<command>'` defines a reusable shortcut, persisted to
|
||||
@@ -309,6 +373,7 @@ project `.mgshrc` may override the setting.
|
||||
| `remote.<name>.visibility` | project | visibility for that target |
|
||||
| `remotes` | project | comma- or space-separated list restricting and ordering the mirror targets |
|
||||
| `mirror` | project | truthy (`1`/`true`/`yes`/`on`) → every `push` also mirrors |
|
||||
| `secretscan` | project | `off` disables the credential check `push` runs before committing (on by default; only an explicit `off` disables it) |
|
||||
|
||||
The three settings written to the global git config are applied at startup, and
|
||||
only when they actually differ, so a plain `mgsh status` does not rewrite
|
||||
|
||||
Reference in New Issue
Block a user