1.4.6 • Published 2 years ago

@silphid/gpm v1.4.6

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

Git Package Manager

The Git Package Manager (or gpm to his closest friends) is a command line interface (CLI) tool for working with multiple interdependent Git repositories (named packages), running Git commands on multiple packages at once, and automatically creating symlinks between them.

Concepts

Package

A package is a reusable module of source code corresponding to a single Git repository. It can have other packages as dependencies and/or it can itself be the dependency of another package.

Manifest

A manifest is a YAML metadata file that describes a package, its dependencies and symlinks to create between them. Each package must have a manifest in its repository's root.

Getting started

Install git

brew install git

Install git-flow

brew install git-flow

git-flow is only required for the feature:start and feature:finish commands.

Configure your SSH key

Follow your Git server's instructions for setting up your SSH key properly (ie: GitHub, GitLab or BitBucket).

Note: I personally recommend not using any passphrase on your private key to keep things simple. I consider files on my computer to be safe enough, but that's up to you. If you want to remove the password from an existing private key, use the following instructions.

Install gpm

npm i -g @silphid/gpm

Initialize your root working directory

Create an empty directory on disk where you want all your packages to be cloned, run the following command to initialize it, and sit back while the magic sparkles before your eyes:

gpm init URL -b BRANCH

Where URL is your main package's Git URL in the form git@HOST:ACCOUNT/PACKAGE.git

Note: The optional -b BRANCH flag allows to specify which branch to checkout (defaults to master).

Enabling NerdFonts (optional)

gpm displays more beautifully with NerdFonts, but that is totally optional. It has special symbols for things such as branches, uncommitted or staged changes and unpushed commits.

  1. Download and install NerdFonts on your machine.
  2. Configure your terminal to use NerdFonts.
  3. Tell gpm to use NerdFonts for your project:
gpm nerd

Usage

$ npm install -g @silphid/gpm
$ gpm COMMAND
running command...
$ gpm (-v|--version|version)
@silphid/gpm/1.4.6 darwin-x64 node-v14.16.0
$ gpm --help [COMMAND]
USAGE
  $ gpm COMMAND
...

Listing packages

gpm l

This displays a tree of packages starting from your main package and down into its dependencies recursively. It also shows currently selected packages (see below), currently checked out branches, pending changes and commits to be pushed. It will also display a warning when currently checked out branch does not match the one its parent package depends on (as specified in its manifest).

Note: Most commands display the list automatically after running. To prevent this, use their --no-list flag.

Selecting packages to work with

By default, all commands apply to selected packages. To change that selection:

gpm s

Shorthand for: gpm select

Starting a feature branch

gpm start FEATURE

Committing changes

  1. Make sure to first review and stage your changes using your regular Git client;
  2. Then commit your staged changes with:
gpm commit 'My commit message'

Committing everything

Warning: This is not the recommended approach.

If you are totally confident you want to stage and commit all changes, including new files and deletions, just:

gpm commit -A 'My commit message'

Shorthand for: gpm add && gpm commit 'My commit message'

Finishing your feature branch

gpm finish

Checking out an existing branch

gpm co BRANCH

Shorthand for: gpm checkout BRANCH

Creating and checking out a new branch

gpm co -b BRANCH

Checking out branch specified in dependent manifests

gpm co -B

Checking out commit specified in dependent manifests

gpm co -C

Note: This results in a detached HEAD. In order to make modification, create a new branch from there.

Deleting a branch

gpm del BRANCH

Shorthand for: gpm delete BRANCH

To also remove the remote counterpart:

gpm del -r BRANCH

Publishing manifests to registry

The following command copies a simplified version of selected manifests to the registry and then commits and pushes registry to origin:

gpm publish

Applying a command only to current or to all packages

By default all commands apply to all selected packages, but you may use the -a flag to apply them to all packages or the -c flag to apply them to the current package only.

For example, to pull all packages, regardless of selection, use:

gpm pull -a

Or to pull only current package:

gpm pull -c

Note: A package is considered current if your current working directory is set to that package's directory or any of its sub-directories.

Commands

gpm add

Stage all changes in selected packages.

USAGE
  $ gpm add

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/add.ts

gpm adjust

Adjust selected packages' dependencies to current branches and commits.

USAGE
  $ gpm adjust

OPTIONS
  -a, --all         include all packages
  -c, --current     include only package of current directory
  -d, --dependants  adjust manifests of dependant packages instead of selected packages themselves
  -l, --[no-]list   whether to display list after command
  -p, --prompt      prompt for packages to include for this command only

See code: src/commands/adjust.ts

gpm checkout [BRANCH]

Checkout given branch in selected packages (or appropriate branch, if none specified).

USAGE
  $ gpm checkout [BRANCH]

ARGUMENTS
  BRANCH  branch/tag/commit to checkout in current package

OPTIONS
  -B, --branch     checkout dependency branch specified in dependent manifests
  -C, --commit     checkout dependency commit specified in dependent manifests
  -a, --all        include all packages
  -b, --create     create a new branch if it does not already exist
  -c, --current    include only package of current directory
  -d, --discard    discard all local changes
  -f, --feature    use feature branch
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

ALIASES
  $ gpm co

See code: src/commands/checkout.ts

gpm clean

Remove redundant dependencies.

USAGE
  $ gpm clean

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/clean.ts

gpm commit MESSAGE

Commit all staged changes in selected packages.

USAGE
  $ gpm commit MESSAGE

ARGUMENTS
  MESSAGE  commit message

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only
  -s, --staged     only commit staged changes

See code: src/commands/commit.ts

gpm config:delete KEY

Delete given config property.

USAGE
  $ gpm config:delete KEY

ARGUMENTS
  KEY  key of property

See code: src/commands/config/delete.ts

gpm config:get KEY

Get value of given configuration property.

USAGE
  $ gpm config:get KEY

ARGUMENTS
  KEY  key of property

See code: src/commands/config/get.ts

gpm config:ls

List all configuration properties.

USAGE
  $ gpm config:ls

See code: src/commands/config/ls.ts

gpm config:set KEY VALUE

Set configuration property to given value.

USAGE
  $ gpm config:set KEY VALUE

ARGUMENTS
  KEY    key of property
  VALUE  value of property

See code: src/commands/config/set.ts

gpm convert [REPO]

Convert existing Git repository to GPM package.

USAGE
  $ gpm convert [REPO]

ARGUMENTS
  REPO  URL of Git repository to convert to package

OPTIONS
  -l, --[no-]list  whether to display list after command

See code: src/commands/convert.ts

gpm delete BRANCH

Delete local (and optionally remote) branch in selected packages.

USAGE
  $ gpm delete BRANCH

ARGUMENTS
  BRANCH  name of branch to delete

OPTIONS
  -a, --all          include all packages
  -c, --current      include only package of current directory
  -f, --feature      use feature branch
  -l, --[no-]list    whether to display list after command
  -p, --prompt       prompt for packages to include for this command only
  -r, --[no-]remote  also delete remote branch

ALIASES
  $ gpm del

See code: src/commands/delete.ts

gpm dematerialize

Reverse materialize command by copying files back to their original dependency locations and recreating symlinks pointing to them.

USAGE
  $ gpm dematerialize

OPTIONS
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command

ALIASES
  $ gpm demat

See code: src/commands/dematerialize.ts

gpm discard

Discard all local changes in selected packages.

USAGE
  $ gpm discard

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/discard.ts

gpm finish [NAME]

Finish feature branch in selected packages.

USAGE
  $ gpm finish [NAME]

ARGUMENTS
  NAME  name of feature (branch name will be 'feature/{username}/{feature}')

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/finish.ts

gpm flow

Configure git flow in selected packages.

USAGE
  $ gpm flow

OPTIONS
  -a, --all          include all packages
  -c, --current      include only package of current directory
  -l, --[no-]list    whether to display list after command
  -p, --prompt       prompt for packages to include for this command only
  --develop=develop  develop branch to use for git flow
  --master=master    master branch to use for git flow
  --user=user        user name to use for git flow feature branches

See code: src/commands/flow.ts

gpm git [ARG1] [ARG2] [...]

Execute arbitrary git command on selected packages.

USAGE
  $ gpm git [ARG1] [ARG2] [...]

ARGUMENTS
  ARG1  first argument
  ARG2  second argument
  ...   other arguments

OPTIONS
  -a, --all      include all packages
  -c, --current  include only package of current directory
  -p, --prompt   prompt for packages to include for this command only

See code: src/commands/git.ts

gpm help [COMMAND]

display help for gpm

USAGE
  $ gpm help [COMMAND]

ARGUMENTS
  COMMAND  command to show help for

OPTIONS
  --all  see all commands in CLI

See code: @oclif/plugin-help

gpm import [NAME] [BRANCH]

Add a dependency to selected packages.

USAGE
  $ gpm import [NAME] [BRANCH]

ARGUMENTS
  NAME    Name of dependency to add (defaults to prompting user)
  BRANCH  Branch of dependency (defaults to currently checked out branch)

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/import.ts

gpm init [REPO]

Configure current directory as root, clone main package and its dependencies, and create symlinks between them.

USAGE
  $ gpm init [REPO]

ARGUMENTS
  REPO  main package Git URL in the form git@github.com:my_account/package_name.git[#branch]

OPTIONS
  -b, --branch=branch  [default: master] main package branch to checkout
  -l, --[no-]list      whether to display list after command
  --develop=develop    develop branch to use for git flow
  --master=master      master branch to use for git flow
  --user=user          user name to use for git flow feature branches

See code: src/commands/init.ts

gpm link

Create symlinks in selected packages.

USAGE
  $ gpm link

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/link.ts

gpm list

List all packages hierarchically, with their current branch.

USAGE
  $ gpm list

OPTIONS
  -a, --all       do not skip redundant sub-trees
  -b, --branches  list all local branches

DESCRIPTION
  If there is a mismatch between currently checked out branch and branch expected in dependency, it also displays a 
  warning.

ALIASES
  $ gpm ls
  $ gpm l

See code: src/commands/list.ts

gpm materialize

Remove symlinks and replace them with copies of original files.

USAGE
  $ gpm materialize

OPTIONS
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command

DESCRIPTION
  To reverse this command, use the dematerialize command.

  Warning: Use at your own risk, as you will be working with copies of your dependencies and changes to those won't 
  appear in your actual dependency folders until you dematerialize your links. That command can be useful very 
  temporarily to work with tools (such as debuggers) that are unsettled by symlinks. You can only materialize links in a 
  single module at once, to avoid having multiple copies of the same files and to make sure changes to those files can 
  be copied back to the original files upon dematerialization.

ALIASES
  $ gpm mat

See code: src/commands/materialize.ts

gpm merge [BRANCH]

Merge given branch of selected packages into current branch.

USAGE
  $ gpm merge [BRANCH]

ARGUMENTS
  BRANCH  name of branch to merge into current branch

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -f, --feature    use feature branch
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only
  --abort          abort current merge operation

See code: src/commands/merge.ts

gpm nerd

Configure gpm to use NerdFonts for nicer display.

USAGE
  $ gpm nerd

OPTIONS
  --off  turn NerdFonts off

DESCRIPTION
  NerdFonts has special symbols for things like branches, uncommitted or staged changes and unpushed commits. First 
  download the font from https://nerdfonts.com, install it on your machine and configure it in your terminal. Then run 
  this command in your project to tell gpm to use it.

See code: src/commands/nerd.ts

gpm pkg:update

Deprecated: Use 'gpm adjust' instead Adjust selected packages' dependencies to current branches and commits.

USAGE
  $ gpm pkg:update

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

ALIASES
  $ gpm pkg:up

See code: src/commands/pkg/update.ts

gpm print

Print manifest file of selected packages.

USAGE
  $ gpm print

OPTIONS
  -a, --all      include all packages
  -c, --current  include only package of current directory
  -p, --prompt   prompt for packages to include for this command only

See code: src/commands/print.ts

gpm pull

Pull selected packages.

USAGE
  $ gpm pull

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/pull.ts

gpm push

Push selected packages.

USAGE
  $ gpm push

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/push.ts

gpm resolve

Resolve conflicts in manifest files of selected packages.

USAGE
  $ gpm resolve

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -o, --ours       whether to resolve using ours (HEAD)
  -p, --prompt     prompt for packages to include for this command only
  -t, --theirs     whether to resolve using theirs (HEAD)

See code: src/commands/resolve.ts

gpm select

Select which packages to include by default in all commands.

USAGE
  $ gpm select

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -n, --none       deselect all packages

ALIASES
  $ gpm s

See code: src/commands/select.ts

gpm start NAME

Create feature branch in selected packages.

USAGE
  $ gpm start NAME

ARGUMENTS
  NAME  name of feature (branch name will be 'feature/{username}/{feature}')

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/start.ts

gpm tag NAME

Create and push tag in selected packages.

USAGE
  $ gpm tag NAME

ARGUMENTS
  NAME  name of tag to create

OPTIONS
  -a, --all      include all packages
  -c, --current  include only package of current directory
  -p, --prompt   prompt for packages to include for this command only

See code: src/commands/tag.ts

gpm unlink

Delete symlinks in selected packages.

USAGE
  $ gpm unlink

OPTIONS
  -a, --all        include all packages
  -c, --current    include only package of current directory
  -l, --[no-]list  whether to display list after command
  -p, --prompt     prompt for packages to include for this command only

See code: src/commands/unlink.ts

gpm update

Update dependencies of selected packages (pull registry, clone/pull packages, create symlinks).

USAGE
  $ gpm update

OPTIONS
  -a, --all         include all packages
  -c, --current     include only package of current directory
  -l, --[no-]links  whether to create symlinks
  -l, --[no-]list   whether to display list after command
  -p, --prompt      prompt for packages to include for this command only
  -p, --[no-]pull   whether to pull changes

ALIASES
  $ gpm up

See code: src/commands/update.ts

Converting an existing project to gpm

Create a manifest for each package

Create a package.yaml manifest file (as described below, in the Manifest file format section) in the root of each package's repository.

Setup a registry repository

Create an empty Git repository that will act as registry for your manifests. Copy all your package manifests into the root folder of that repository, while taking care of renaming them to <package-name>.yaml.

Manifest file format

A manifest file looks like this:

repo: 'git@github.com:my-account/my-package.git'
links:
  exports: path/to/sources/to/be/exposed/to/dependents
  imports: path/where/dependencies/symlinks/will/be/created
  internals:
    - source: path/where/symlink1/points
      target: path/where/symlink1/will/be/created
    - source: path/where/symlink2/points
      target: path/where/symlink2/will/be/created
dependencies:
  - repo: 'git@github.com:my-account/sub-package1.git'
    branch: master
    commit: 8a30553c0f322bf776706aa88074aaebe48751d2
  - repo: 'git@github.com:my-account/sub-package2.git'
    branch: master
    commit: 2d1991446ab31e54e24230e08454414413c6a654

Note: Values containing any special YAML character (:{}[],&*#?|-<>=!%@\) must be enclosed within double-quotes (such as the repository property in above example).

repository

URL of this package's Git repository, such as it would be provided to the git clone command.

Note: The name of the repository is determined by the last part of the URL without the .git extension.

links.exports

Relative path within this package to expose to dependent packages as symlink.

Only useful if this package is a dependency of some other package.

Optional: Defaults to root directory of package.

Exporting multiple sources directories as symlinks

To expose multiple directories as symlinks, specify an object instead of a string, where each key is the name of the link to create and the value is the directory to expose:

links:
  exports:
    first: path/to/first/sources/dir
    second: path/to/second/sources/dir
    third: path/to/third/sources/dir

links.imports

Relative path where to create all dependencies' symlinks.

Only useful if this package has dependencies.

Optional: When omitted, not external symlinks are created.

links.internals

List of symlinks to create internally (both source and target are within this same package).

Optional: When omitted, not internal symlinks are created.

Each item in list must have the following properties:

source

Path to directory the symlink will be pointing to.

target

Path where to create symlink, including symlink name.

dependencies

List of this package's dependencies URLs that will be automatically cloned/pull when executing the gpm update command. Each dependency can have the following properties:

repo

Required Git URL of dependency repository.

branch

Optional branch to use (defaults to master).

commit

Optional commit SHA1. That property is automatically set when dependency is checked out to a different branch or commit. It is used to allow switching branch or going back to a specific point in time in a coherent fashion across multiple packages. For example, if you checkout an arbitrary old commit in your main branch, you can then use the following command to also checkout all dependency packages to the exact commits that were referenced at that time:

gpm co -aC

You would then be on detached HEADs. If you want to create new branches starting from those commits, in order to make modifications, use:

gpm co -ab BRANCH

Or, to switch back to branches specified in manifests:

gpm co -aB

Uninstalling the .pkg

Warning: Make sure you know what you are doing! You could potentially harm your system badly!

Run this command to find the tool's install location:

pkgutil --pkg-info com.silphid.gpm

In front of location: you should see something like usr/local/lib/gpm.

Then run the following command with your own location value (notice the extra leading /):

sudo rm -rf /usr/local/lib/gpm

To clean-up even further, you can remove the receipt with:

sudo pkgutil --forget com.silphid.gpm

For more information, refer to this article: Uninstalling packages (.pkg files) on Mac OS X

Release notes

v1.4.5

  • Add gpm materialize/mat and gpm dematerialize/demat commands to convert symlinks into physical copies of the folders they point to and back into symlinks. That command can be useful very temporarily to work with tools (such as debuggers) that are unsettled by symlinks.
  • Fix gpm unlink to actually delete symlinks.

v1.4.4

  • gpm finish now is performed in bottom-up order to ensure manifests are updated correctly with latest branch/commit (to avoid needing a gpm adjust + gpm commit afterwards).
  • Add --prompt / -p flag to most commands, to prompt for which packages to apply current command to (previous selection is maintained for future commands).
  • Add --feature / -f flag to gpm merge (automatically prefix branch name with feature/USERNAME/, just like other branch-related commands).
  • gpm commit now defaults to committing all changes (instead of only staged ones). Use --staged / -s to commit only staged changes.
  • gpm finish, gpm merge and gpm pull should no longer prompt for commit messages.

v1.4.3

  • gpm resolve now automatically stages resolved manifest files.
  • Fix gpm commit to not skip repositories in merging state, even if they have no changes.

v1.4.2

  • Add gpm unlink to delete symlinks in selected packages' imports folder.
  • All commands that create symlinks will delete existing symlinks first.
  • Fix gpm discard to also delete untracked files.

v1.4.1

  • Change gpm pull to use merge instead of rebase.
  • Tolerate conflict markers in manifest files.
    • Automatically resolves conflicted manifest files in-memory to HEAD to allow gpm to load them and remain functional.
  • Add to gpm select command the flags --all/-a, --current/-c and --none/-n to quickly select all/current/no packages.
  • Add gpm resolve command to resolve conflicts in manifest files either to --ours or --theirs (defaults to ours).
  • Add gpm flow command to configure git flow branches.
  • Add gpm git command to invoke arbitrary git commands on all selected packages (ie: gpm git status).

v1.4.0

  • Add gpm merge command to merge a branch into selected packages.
  • Remove repo property from manifests (was redundant and could become out-of-sync with reality).