157 lines
6.5 KiB
Markdown
157 lines
6.5 KiB
Markdown
# mgsh — git shell
|
|
|
|
A small interactive shell / command-line wrapper around a self-hosted bare git
|
|
server reachable over ssh. It manages a flat set of projects living under a base
|
|
directory (default `$HOME/src`, or `/db/src` on Linux). Go port of the original
|
|
Perl `mgsh` (`mgsh.perl`).
|
|
|
|
## Build
|
|
|
|
```sh
|
|
./build.sh # builds ./mgsh and bumps the patch version by 0.0.1
|
|
go build -o mgsh . # plain build, keeps the default version
|
|
```
|
|
|
|
`build.sh` reads `version.txt`, increments the patch component, injects it via
|
|
`-ldflags -X main.VERSION`, and writes it back — so `version.txt` always holds
|
|
the version of the binary just built. Dependencies are fetched via Go modules
|
|
(`go.mod` / `go.sum`) on first build.
|
|
|
|
Run the tests with `go test ./...`.
|
|
|
|
## Usage
|
|
|
|
Launch `mgsh` for the interactive shell, or run a single command directly from a
|
|
project directory, e.g. `mgsh push "message"`, `mgsh status`, `mgsh log`.
|
|
|
|
The interactive prompt is colored (Catppuccin Mocha) and shows the active
|
|
project, its git branch and a `*` dirty marker:
|
|
|
|
```
|
|
< src/myproject (master*) >
|
|
```
|
|
|
|
Features: command history (`~/.mgsh_history`), Tab completion (commands, local
|
|
projects for `cd`/`open`, server repos for `clone`/`show`, branches/tags for
|
|
`checkout`/`tag`, filesystem paths for `dist`), and colored `list`/`log`/error
|
|
output.
|
|
|
|
Exit with `quit`, `exit`, `Ctrl-D`, or `Ctrl-C` on an empty line.
|
|
|
|
### Shell escape
|
|
|
|
Unknown commands are **not** forwarded to a shell. To run a shell command,
|
|
prefix it with `!`:
|
|
|
|
```
|
|
< src/myproject > !ls -la
|
|
```
|
|
|
|
### Commands
|
|
|
|
Run `help` for the full list. Highlights:
|
|
|
|
| command | description |
|
|
|---------------------------|------------------------------------------------|
|
|
| `cd [project]` | change project |
|
|
| `push [comment]` | commit everything and push to the server |
|
|
| `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 |
|
|
| `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 |
|
|
| `list [-a] [pattern]` | list repositories on the server |
|
|
| `show <repo>` | show a repository log directly on the server |
|
|
| `archive [comment]` | snapshot the server-side repo into `./archive` |
|
|
| `init` | make a new repository from the current directory |
|
|
| `tag [add/checkout/delete]` | manage tags |
|
|
| `alias [name [cmd]]` | list, show or define a command alias |
|
|
| `unalias <name>` | remove a command alias |
|
|
| `rescan` | refresh the cached server repository list |
|
|
| `!<command>` | run `<command>` in the shell |
|
|
|
|
### Aliases
|
|
|
|
`alias <name> '<command>'` defines a reusable shortcut, persisted to
|
|
`~/.mgshrc` and reloaded on every start. The expansion is itself a mgsh
|
|
command line and may reference the alias arguments:
|
|
|
|
| placeholder | meaning |
|
|
|-------------|----------------------------------|
|
|
| `$1` … `$N` | the Nth argument (empty if unset)|
|
|
| `$*` / `$@` | all arguments, space-joined |
|
|
|
|
When the expansion contains no placeholder, the arguments are appended (classic
|
|
shell-alias behaviour). Because unknown commands are **not** forwarded to a
|
|
shell, a shell command inside an alias needs the `!` prefix:
|
|
|
|
```
|
|
alias co 'checkout $1' # co v2 -> checkout v2 (builtin)
|
|
alias p 'push $*' # p fixed bug -> push fixed bug (builtin)
|
|
alias ec '!echo $1' # ec hello -> echo hello (shell)
|
|
```
|
|
|
|
`alias` with no arguments lists all aliases, `alias <name>` shows one, and
|
|
`unalias <name>` removes it. Aliases cannot shadow builtin commands.
|
|
|
|
### Public mirror (`pushremote`)
|
|
|
|
Besides the internal ssh git server, `pushremote` mirrors the active project to
|
|
a public hosting server (Gitea, GitHub or GitLab) over its REST API. It reads
|
|
two settings from `~/.mgshrc`:
|
|
|
|
```ini
|
|
remoteurl = https://git.example.com # base URL of the server
|
|
remotekey = <personal-access-token> # API token
|
|
# remotetype = gitea # optional; auto-detected from remoteurl
|
|
# remotevisibility = private # visibility of created repos (default private)
|
|
# mirror = true # `push` also mirrors via pushremote
|
|
```
|
|
|
|
`pushremote` authenticates with the token, creates the repository (named after
|
|
the current project) if it does not exist yet, adds a credential-free remote
|
|
named `public`, and pushes all branches and tags. New repositories are
|
|
**private** unless `remotevisibility = public`; any words after the command
|
|
(`pushremote <description>`) are set as the repository description on creation.
|
|
The token is sent as a one-shot HTTP auth header, never written into the repo's
|
|
git config. The provider is auto-detected from `remoteurl` (`github.com` →
|
|
GitHub, `gitlab*` → GitLab, otherwise Gitea) and can be forced with
|
|
`remotetype`. Set `mirror = true` to have every `push` mirror automatically.
|
|
|
|
## Configuration
|
|
|
|
mgsh has **no built-in defaults**. Configuration comes entirely from `~/.mgshrc`
|
|
(overlaid with `MGSH_*` environment variables). On first run mgsh writes a blank,
|
|
annotated `~/.mgshrc` template (migrating any aliases from a pre-4.x
|
|
`~/.mgsh_aliases`) and then exits with an error until the required settings —
|
|
`base`, `githost`, `gitport`, `gituser`, `gitpath` — are filled in.
|
|
|
|
It uses simple `key = value` (or `key: value`) lines (`#` comments allowed);
|
|
alias definitions live in the same file:
|
|
|
|
```ini
|
|
# --- required ---
|
|
base = /Users/me/src
|
|
githost = git.example.com
|
|
gitport = 22
|
|
gituser = git
|
|
gitpath = /home/git
|
|
|
|
# --- optional ---
|
|
gitname = Your Name
|
|
gitemail = you@example.com
|
|
pushdefault = matching
|
|
editor = code # fallback opener for `open`
|
|
|
|
alias co 'checkout $1'
|
|
```
|
|
|
|
Environment overrides: `MGSH_BASE`, `MGSH_GITHOST`, `MGSH_GITPORT`,
|
|
`MGSH_GITUSER`, `MGSH_GITPATH`, `MGSH_GITKEY`, `MGSH_GITNAME`, `MGSH_GITEMAIL`,
|
|
`MGSH_PUSHDEFAULT`, `MGSH_EDITOR`, `MGSH_REMOTEURL`, `MGSH_REMOTEKEY`,
|
|
`MGSH_REMOTETYPE`, `MGSH_REMOTEVISIBILITY`, `MGSH_MIRROR`.
|
|
|
|
See `mgshrc.example` for an annotated template.
|