Files
mgsh/README.md
T

6.5 KiB

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

./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:

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:

# --- 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.