Skip to content

manic-systems/geminus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Geminus

Zig Build Status Nix Build Status
The final authority on repo management.

Synopsis
Usage | Usage
Configuration | Installation

What Does it Do?

TL;DR: Geminus manages Git and Jujutsu repositories, and does so in a sane way. It solves the problem of "where do I clone this repo to?", or "where did I have this repo cloned again?". It does so in a way that's as simple, convenient and foolproof as possible. Running gem https://git.my-remote.com/alice/my-repo clones my-repo to root/git.my-remote.com/alice/my-repo (where root is ~/git by default). That's it. That's the whole thing. If you think this project is overill for just that, you're absolutely correct, and you can leave now. Feel free to create your own shell snippet to do just that, and make sure to check out the shell snippets in shell.zig. This whole work is dedicated to the public domain, so feel free to take what you need. :) To the rest, here's what this actually solves:

  • Repos are always where you expect them to be.
  • You don't accidentally clone multiple times.
  • Repos with the same name don't conflict.
  • You don't have to think where to clone a repository to.

Doesen't sound all that useful at first? Truth be told, it might not make a big difference compared to just blindly copying repos to random locations, but it takes another thing off your mind, permanently. We already do this for git forges, why not do it for local machines as well?

Because a native executable cannot change its parent shell's current directory, gem init <shell> emits shell wrappers that call the binary and cd to the returned checkout path.

Yes, I know it's got the same binary name as the CLI tool for managing Ruby gems. No, I do not care. To get started with Geminus, skip to the Usage section.

Status

Geminus is built with Zig 0.16. The repository provides a Nix flake for local development, package builds, CI checks, and shell-integration tests. The installed binary is called gem; the project/package name is geminus.

Usage

gem <repo-ref>                    clone or enter the canonical checkout
gem where <repo-ref>              print the intended local checkout path
gem fix                           fix the current checkout path/remote
gem config                        print effective ZON configuration
gem init nushell|bash|zsh|fish|elvish
                                    emit shell integration

Options:

--json                            machine-readable JSON output
--shell                           tab-separated shell-wrapper output

Repository References

Accepted reference forms include:

https://github.com/owner/repo.git
ssh://git@github.com/owner/repo.git
git://github.com/owner/repo.git
git@github.com:owner/repo.git
github.com/owner/repo
git clone git@github.com:owner/repo.git
https://github.com/owner/repo/tree/branch-name
https://github.com/owner/repo/pull/123
https://github.com/owner/repo/issues?q=is%3Aissue+state%3Aopen
https://gitlab.com/group/project/-/merge_requests/17
https://git.example.com/group/sub/project/-/merge_requests/17

Commands

gem <repo-ref>

Default command. Resolve the canonical local path, enter the existing checkout when it already exists and matches the same remote, or clone it when missing. The plain text output is the final path.

gem fix

Run inside a repository. gem finds the repository root, reads the configured remote, computes the canonical path, updates the remote URL, and moves the checkout when it is inside the configured root and the destination is free.

gem config

Print the effective configuration as ZON after defaults and user overrides are applied.

gem init nushell|bash|zsh|fish|elvish

Emit a shell wrapper. The wrapper calls gem in a machine-readable mode and changes the parent shell's current directory to the returned checkout path.

Shell Integration

Shell integration is sadly needed, since gem needs to change the shell's current directory to the location of the repository. This is only possible by utilizing a shell script.

Bash:

eval "$(gem init bash)"

Zsh:

eval "$(gem init zsh)"

Fish:

gem init fish | source

Nushell:

gem init nushell | save --force ~/.config/nushell/autoload/gem.nu

Elvish:

mkdir -p ~/.config/elvish
gem init elvish >> ~/.config/elvish/rc.elv

Configuration

Configuration is written in Zig object notation and to either $XDG_CONFIG_HOME/geminus/config.zon, or to ~/.config/geminus/config.zon as a fallback.

The default configuration looks like this:

.{
    .root = "~/git",
    .layout = "{forge}/{owner}/{repo}",
    .vcs = .auto,
    .preserve_case = true,
    .default_remote = "origin",
    .hosts = .{
        .{
            .host = "github.com",
            .alias = "github.com",
            .preferred_protocol = .ssh,
        },
        .{
            .host = "gitlab.com",
            .alias = "gitlab.com",
            .preferred_protocol = .ssh,
        },
        .{
            .host = "codeberg.org",
            .alias = "codeberg.org",
            .preferred_protocol = .ssh,
        },
    },
}

An example user config could look like this:

.{
    .root = "~/src",
    .layout = "{forge}/{path}",
    .vcs = .jj_colocated,
    .preserve_case = true,
    .default_remote = "origin",
    .hosts = .{
        .{
            .host = "git.example.com",
            .alias = "example.com",
            .preferred_protocol = .https,
        },
    },
}

Fields

root

The root of of the directory where all cloned repositories should be located. Both ~ and ~/... expand through $HOME, and the (expanded) root must be absolute.

layout

layout refers to the repository's relative path under root. Supported tokens are:

{forge}       normalized host alias, e.g. codeberg.org
{host}        raw input host, e.g. https://codeberg.org
{owner}       first repository path segment e.g. alice
{repo}        final repository path segment without .git, e.g. my-repo
{path}        full repository path without .git, e.g. codeberg.org/alice/my-repo
{vcs}         git or jj

vcs

One of .auto, .git, .jj_colocated, or .jj_standalone. .auto colocates repositories using jj when available and falls back to git.

preserve_case

When true, repository paths keep remote casing. When false, path components are lowercased.

default_remote

Remote name used by gem fix. Defaults to origin.

hosts

Host overrides. Each entry has a required host, optional alias, and optional preferred_protocol. Protocol values are .ssh, .https, .git, .file, and .preserve.

Output Modes

Plain text is optimized for direct shell use:

/home/user/git/github.com/owner/repo

JSON is intended for structured integrations:

gem --json where github.com/owner/repo

Shell output is a stable tab-separated format for shell wrappers:

gem --shell github.com/owner/repo

Installation

Building

To build Geminus, you'll need a copy of the Zig compiler, version 0.16.X. You can then build it using:

zig build -Doptimize=ReleaseSafe

To install the binary and man page under a prefix, run:

zig build -Doptimize=ReleaseSafe --prefix ~/.local

This installs:

~/.local/bin/gem
~/.local/share/man/man1/gem.1

This repository provides Geminus as a Nix flake output under both .#default and .#gem. You can add the gem package to your system as follows:

Using Tack:

# pins.toml

[inputs]
[inputs.geminus]
url = "github:manic-systems/geminus"

Then add it to your system configuration.

Using flakes:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
    geminus = {
      url = "github:manic-systems/geminus";
      # Optionally:
      # inputs.nixpkgs.follows = "nixpkgs"
    };
  };

  outputs = { nixpkgs, geminus }: {
    nixosConfigurations.foo = nixpkgs.lib.nixosSystem {
      modules = [
        (
          { pkgs, ... }:
          {
            environment.systemPackages = [
              geminus.packages.${pkgs.stdenv.hostPlatform.system}.gem
            ];
          }
        )
      ];
    };
  };
}

Exit Codes

0   success
1   repository or command operation failed
2   usage, parse, plan, or configuration error
4   conflict or refused move
6   clone failed

About

The final authority on repo management.

Topics

Resources

License

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors