• Stars
    star
    675
  • Rank 66,577 (Top 2 %)
  • Language
    JavaScript
  • Created over 11 years ago
  • Updated over 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Multiple git repository management tool

Features

  • Tag all the things! gr @work foo will run the command foo in all the paths tagged @work.
  • Auto-discovery of git repositories for easy setup and tag management.
  • gr does not reinvent any git operations: instead, it passes through and runs any unknown commands. All your git-fu will still work! e.g. gr @work git fetch is the same as running git fetch in each all the paths tagged @work.
  • Built-in commands for common pain points:
    • status for one-line summaries of repos (modified, behind/ahead, tags)
  • Extensible via plugins and middleware: REST API/Connect-style request handlers (function(req, res, next) { ... }

Changelog

  • Looking for more committers! Let me know if you're interested; gr currently meets my fairly limited needs but I know it can become even more useful given a larger core team and/or a stronger vision around how it can support usage in a team working on multiple repos.
  • 0.5.5: Submodule directory detection fixes, thanks @bimlas! Better behavior when the EDITOR environment variable is not set, thanks @petercoulton!
  • 0.5.4: Added gr export and gr import for sharing .grconfig, thanks @timja-kainos! Added current branch to status, thanks @n1ywb!
  • 0.5.3: minor improvements to internals, thanks @timja-kainos!
  • 0.5.2: gr now handles git submodules better, thanks @cojomojo! gr also prints out tags with newlines which makes for a more readable output, thanks @nwinkler!
  • 0.5.1: gr discover now handles paths outside the home directory as expected, thanks @farmerchris!
  • 0.5.0: gr discover is now an alias for gr tag discover; gr discover now accepts path arguments, shows progress during a scan and only scans five levels deep by default. Thanks @coderjoe for the patches!
  • 0.4.1: gr status now only invokes git once per directory, thanks @coderjoe!
  • 0.4.0: Added several usability improvements and bug fixes, courtesy of @nichtich (better handling of missing directories, support for simple paths). Added a fix that improves errors related to directory permissions, courtesy of @pnxs.
  • 0.3.0: Switched from #foo to @foo for tags; while the #foo syntax looks cool, most shells will treat it as a comment unless the tag is surrounded by quotes. Looking back at the design, I'd rather go for usability over pretty looking commands. Updated the documentation to match this change.

Example

gr works by tagging directories with tags:

gr +@work ~/mnt/gluejs ~/mnt/microee

After this, you can run any commands on the tagged directories simply by prefixing them with gr @work. For example:

gr @work status

Outputs (actual output is colorized):

~/mnt/gluejs           2 modified [ahead 2]      @work
~/mnt/microee          Clean                     @work

E.g. path, modified, ahead/behind remote, tags. Alternatively, you can use plain git commands for a more verbose report:

gr @work git status -sb

Outputs:

in ~/mnt/gluejs

## glue2
 M lib/runner/package-commonjs/index.js
 M index.js

in ~/mnt/microee

## master

gr doesn't do any command rewriting, or introduce any new commands - I like git as it is.

Getting started

First, install Node.js. Node.js adds the node and the npm command. On Ubuntu you need the nodejs-legacy package.

Next, to install gr (the name was already taken on npm):

npm install -g git-run

You may need to prefix this with sudo.

Setting up tags

Use the auto-discovery feature to set up tags quickly:

gr tag discover

By default auto-discovery searches all paths under your home directory. gr discover is also an alias for gr tag discover (since v0.5.0).

Note that discover only scans up to five levels deep by default (since v0.5.0); if you need to scan even deeper in your path tree you should just pass in an explicit set of starting points to gr tag discover.

If you'd prefer, you can specify a directory under which auto-discovery should search (since in v0.5.0):

gr tag discover /mnt/external/projects

Once auto-discovery completes, it will generate a list, and open it in your default console editor.

It will look like this:

# Found the following directories with `.git` directories.
#
# Please add any tags you want by adding one or more `@tag`
# entries after the path name.
# For example:
#   ~/foo @work @play
# will tag ~/foo with @work and @play.
#
~/foo
~/bar/baz

Add tags after each path, save the file, and exit.

Your tags are now set up!

Verify with gr status or gr tag list. Use gr @work status or gr @work ls -lah to see how commands are executed. (status is a built-in command; ls -lah is not, so it is run in each of the paths.)

You can run auto-discovery multiple times. It makes tag-related bulk changes quite easy.

Tab completion

To add tab completion:

  • open your ~/.zshrc or ~/.bashrc (~/.bash_profile on OSΒ X)
  • add the line . <(gr completion) at the end of the file
  • then, to apply this change to your current session, run source ~/.zshrc (or source ~/.bashrc or source ~/bash_profile)

Now, when you type gr <tab>, you'll see the list tags you've created. If you notice any bugs, let me know via an issue.

How I use gr

Some examples:

COMMAND TASK
gr @work git fetch and then gr @work status Update all my work repos. This fetches the newest information from the remote, and then prints a one-line-at-a-time summary.
gr @work git diff or gr @work git diff --cached See diffs
gr @work jshint . --exclude=**/node_modules Run jshint
gr @write make Rebuild all my writing via make
gr @work npm ls List install npm modules
gr @work git --no-pager log --decorate --graph --oneline -n 3 Print a graph-like log

Of course, I don't actually type these out; I'm using zsh aliases instead. grd is for diff, grdc is for diff --cached; grl is for the log. For example, in .zshrc:

alias grs="gr status"
alias grl="gr git --no-pager log --decorate --graph --oneline -n 3"

You can set up similar aliases for bash; Google is your friend here.

Usage

Usage:

gr <options> <targets> <cmd>

Options

Currently, there is just one option: --json, which switched to a machine-readable output and is used for integration tests.

Targets

Targets can be paths or tags. For example:

gr ~/foo ~/bar status
gr @work ls -lah
  • Path targets should be directories.
  • Tags refer to sets of directories. They managed using the tag built-in.

If no targets are given, then all tagged paths are used. For example, gr status will report the status of all repositories.

Tagging

Short form:

@tag            List directories associated with "tag"
@tag <cmd>      Run a command in the directories associated with "tag"
-t <tag> <cmd>  Run a command in the directories associated with "tag"
+@tag           Add a tag to the current directory
-@tag           Remove a tag from the current directory
+@tag <path>    Add a tag to <path>
-@tag <path>    Remove a tag from <path>

Long form:

tag add <tag>   Alternative to +@tag
tag rm <tag>    Alternative to -@tag
tag add <t> <p> Alternative to +@tag <path>
tag rm <t> <p>  Alternative to -@tag <path>
tag list        List all tags (default action)
tag discover    Auto-discover git paths under ~/

Example:

gr +@work ~/bar

Internally, the tags are stored in the config file ~/.grconfig.json. For example, the tag @books for the path /home/m/mnt/css-book would be stored as:

{
 "tags": {
  "books": [
    "/home/m/mnt/css-book"
  ]
}

For some use cases, it may be easier to just edit this file rather than use the commands tag add and tag rm.

Commands

The command can be either one of the built-in commands, or a shell command. For example:

gr @work status
gr ~/foo ~/bar ls -lah

To explicitly set the command, use --:

gr ~/foo -- ~/bar.sh
gr @work -- git remote -v

Tags can also be specified more explicitly. For example gr -t work -t play is the same as gr @work @play.

Built-in commands:

gr tag ..
  add <t>         Add a tag to the current directory
  rm <t>          Remove a tag from the current directory
  add <t> <path>  Add a tag to <path>
  rm <t> <path>   Remove a tag from <path>

gr tag discover <paths> Auto-discover git paths under  the list of <paths>
                       (If omitted, <paths> defaults to ~/)

gr tag list         List all known repositories and their tags

gr list        List all known repositories and their tags

gr status       Displays the (git) status of the selected directories.
gr status -v    Runs "git status -sb" for a more verbose status.

gr config ..
  get <k>       Get a config key (can also be a path, e.g. "tags.foo")
  set <k> <v>   Set a config key (overwrites existing value)
  add <k> <v>   Add a value to a config key (appends rather than overwriting)
  rm <k> <v>    Remove a value from a config key (if it exists)
  list          List all configuration (default action)

gr help        Show this help
gr version     Version info

Plugins

TODO:

  • bootstrap: bootstraps a set of repositories from a config file.

Installing plugins

Generally speaking, you need to do two things:

  1. install the plugin globally via npm: npm install -g foo
  2. configure gr to use the plugin: gr config add plugins foo

The new commands should now be available.

Writing plugins

Plugins are functions which are invoked once for each repository path specified by the user. This makes it easier to write plugins, since they do not need to handle executing against multiple repository paths explicitly.

Plugins are treated a bit like a REST API: they are defined as "routes" on the gr object.

Each plugin consists of an index file which is loaded when gr is started, and which should add new "routes":

module.exports = function(gr) {
  // set up new commands on the gr object
  gr.use(['foo', 'help'], function(req, res, next) {
    console.log('Hello world');
    req.exit(); // stop processing
  });
  gr.use('foo', function(req, res, next) {
    console.log(req.argv, req.path);
    req.done(); // can be called multiple times
  });
};

Of course, req and res in the handlers are not HTTP requests, but rather objects representing the target directory (a regular object) and process.stdout.

Each "route" is called multiple times, each with one path. Thus, assuming @work matches two paths, gr @work status is translated into multiple indvidual function calls; one for each directory/repository tagged @work.

  status({ path: '/home/m/foo', argv: ... }, process.stdout, next);
  status({ path: '/home/m/bar', argv: ... }, process.stdout, next);

There are three ways to stop processing:

  1. Call res.done(). This means that the command should be called again for the next path. This is useful for processing commands that target directories.
  2. Call res.exit(). This means that the command is complete, and gr should exit. For example, we don't want to show a help text multiple times if the user calls gr @work help.
  3. Call next. This means that the current handler does not want to handle the current request. Similar to how Connect works, this is mostly used for writing middleware or falling back on a different action.

The req object describes the current request.

  • req.argv: the command line arguments passed to the command, excluding ones that have already matched. For example: given app.use(['foo', 'add'], ...) and gr foo add bar, argv = [ 'bar' ].
  • req.config: the configuration object used by gr; allows you to read and write configuration values (see the code for details).
  • req.path: the full path to the repository directory for this call
  • req.gr: the instance of gr (see index.js)
  • req.format: The desired output format, either human or json.

The res object controls

  • res.done: Call this function when you have completed processing the task.

The next function is used if you decide not to handle the current request. Calling next will make the next matching request handler run. If you encounter an error, call next(err) to output the error.

Writing middleware

Middleware are functions that extract additional metadata.

  • req.git.remotes: TODO - a hash of remotes (for example: { origin: 'git...'}). Extracted via the git middleware.

A list of plugin ideas

Here are some plugin ideas:

  • extend auto-discovery beyond git
  • run tests
  • run jshint / gjslint (only modified?)
  • do npm / package.json linting
  • generate docs
  • fetch and report status as one action
  • report npm versions (and whether the version of the package on npm is up to date)
  • generate a changelog (between tagged versions)
  • check that npm modules are up to date
  • run npm link on all modules
  • generate a list of authors
  • generate a list of licences
  • xargs compatibility
  • Ability to confirm each command (to make it possible to skip)
  • Ability expose other statuses (e.g., npm outdated)

Make your plugin searchable

If you write a plugin, make sure to add the gr keyword to (in package.json). This makes it easy to find plugins by searching npm by tag.

Also, file a PR against this README if you want to have your plugin listed here.

Status matching idea

(This is just a random idea) Using "meta-tags" to target commands based on git ls-files.

  • clean: Clean working directory - in other words, no tracked files are modified; no untracked files exist.
  • untracked: Has files that are not tracked (but that have not been added to tracking)
  • modified: Has files that are tracked and modified (but that have not been staged)
  • deleted: Has files that are tracked and deleted
  • staged: Has files that are staged for commit (but that have not been committed)
  • unmerged: Has files that have not been merged
  • unclean: Does not have a clean working directory.

For example: gr @clean git fetch

Inspired by

More Repositories

1

distsysbook

The book Distributed systems: for fun and profit
HTML
2,538
star
2

markdown-styles

Markdown to static HTML generator and multiple CSS themes for Markdown
HTML
1,843
star
3

singlepageappbook

Content and site generator for Single page apps in depth (my book on single page applications)
HTML
1,712
star
4

nwm

Tiling window manager for X11 written in Node.js
JavaScript
786
star
5

npm_lazy

A lazy local cache for NPM to make your local deploys faster
JavaScript
753
star
6

electroshot

Capture website screenshots with optional device and network emulation as jpg, png or pdf (with web fonts!) using Electron / Chrome.
JavaScript
549
star
7

minilog

Lightweight client & server-side logging with Stream-API backends
JavaScript
378
star
8

cssbook

The book "Learn CSS layout the pedantic way"
CSS
225
star
9

ghost-render

Render static blog sites from Markdown using Ghost themes
JavaScript
224
star
10

gluejs

Build CommonJS modules for the browser via a chainable API
JavaScript
165
star
11

useradmin

User administration and auth for Kohana 3
PHP
106
star
12

fastlint

Lint faster by only running linters and other tools on files that have recently changed or files that are different from `master` in git.
JavaScript
89
star
13

vectorclock

A simple implementation of vector clocks in Javascript.
JavaScript
78
star
14

token

Time-limited, HMAC-based authentication token generation
JavaScript
65
star
15

perfect

A perfect minimal hash function generator
JavaScript
63
star
16

siobench

Basic socket.io benchmarking
JavaScript
44
star
17

nplay

Console-based mp3 player with Winamp key bindings and jump-to-file
JavaScript
42
star
18

markdown-styles-lambda

Automatic static site generation on `git push` using AWS Lambda and markdown-styles using a Gulp-style API.
JavaScript
33
star
19

tmux-cpu

Display CPU usage in your tmux status bar or in the terminal.
JavaScript
32
star
20

archey.js

Archey.js is a system information tool written in JS (based on Archey)
JavaScript
29
star
21

nodebook

A book about using Node.js
HTML
29
star
22

vnodehash

Consistent hashing using virtual nodes.
JavaScript
29
star
23

datalog.js

A trivial Datalog with top-down and bottom up evaluation written in Javascript to learn how Datalog evaluation works.
JavaScript
28
star
24

pipe-iterators

Like underscore for Node streams. Functions for iterating over object mode streams: forEach, map, mapKey, reduce, filter, fromArray, toArray, fromAsync, devnull, pipe, head, tail, through, thru, writable, readable, duplex, pipeline.
JavaScript
27
star
25

file-dedupe

Fast duplicate file detection library
JavaScript
25
star
26

microee

A tiny EventEmitter-like client and server side library for routing events
JavaScript
21
star
27

amdetective

Like node-detective, but for AMD/r.js files
JavaScript
19
star
28

tmux-mem

Display memory usage in your tmux status bar or in the terminal
JavaScript
16
star
29

snapshot

Serialize circular references, custom objects and other types not supported by JSON
JavaScript
16
star
30

pixiedust

RESTful lazy chainable API generator
JavaScript
14
star
31

htmlparser-to-html

Converts the JSON that the htmlparser/htmlparser2 package produces back to HTML
JavaScript
13
star
32

sioconfig

Socket.io HAProxy and Stunnel configs, and a test tool
JavaScript
12
star
33

nwm-user

Custom nwm configuration
JavaScript
11
star
34

hmvc-cfs

Cascading file system
JavaScript
11
star
35

wildglob

JavaScript
9
star
36

minimal

A router and http client - without unnecessary additions, modifications, or complications
JavaScript
8
star
37

node-winamp

Node.js remote control app for Winamp over LAN + client bindings
JavaScript
7
star
38

nodeko

Node.js window manager for X11 (written at NodeKO 2011)
C++
6
star
39

mg

JavaScript
6
star
40

miniee

An EventEmitter-like Client and server side library for routing events w/regexps
JavaScript
6
star
41

heartbeat

Combine multiple recurring timers to a single interval
JavaScript
6
star
42

7z-encrypted-backup

JavaScript
5
star
43

npm_push

Deprecated, see npm_lazy instead
JavaScript
5
star
44

tmux-colors

Write tmux-compatible color strings and have them work both in the terminal and in tmux.
JavaScript
5
star
45

glob-parse

Returns a parsed representation of a glob string; does not require Minimatch.
JavaScript
5
star
46

minitask

A standard/convention for running tasks over a list of files based around Node core streams2
JavaScript
4
star
47

changes

Check that your own npm packages are up to date
JavaScript
4
star
48

espresso

Syntax highlighting theme for Sublime Text 2 and Guake
Shell
4
star
49

markdown-stream-utils

Utility functions for processing markdown files using object mode streams. Used by markdown-styles and by ghost-render.
JavaScript
4
star
50

requireincontext

Wrapper to require() js files in a custom context
JavaScript
3
star
51

nbar

Status bar for nwm
C
3
star
52

glob-github

Run glob expressions against the Github Repo Contents API and return the matching files and metadata; with caching and handling of concurrent requests
JavaScript
3
star
53

fake.io

Fake Engine IO server and client for running tests without starting a server
JavaScript
3
star
54

apache_ai

Summarizes Apache error logs by removing unnecessary uniquely identifying information
JavaScript
3
star
55

unbundle-model

A model layer, implements a model and a collection.
JavaScript
3
star
56

controlflow

Node control flow patterns from my book
JavaScript
2
star
57

package-json-resolver

Library for reading package.json files for the gluejs build system
JavaScript
2
star
58

github.js

Github API v3 JS client
JavaScript
2
star
59

mds-csv

csv highlighting support for markdown-styles / generate-md
JavaScript
2
star
60

fail

Generic failure detector for connections
JavaScript
2
star
61

lost

A system for locating things by their name (and for binding things to names)
JavaScript
2
star
62

dom-to-htmlparser

Converts the DOM into htmlparser-compatible JSON
JavaScript
1
star
63

nodeunit-runner

A simple nodeunit test runner for invoking tests via node
JavaScript
1
star
64

tcp-loadbalancer

TCP load balancer for running load balanced scenario tests
JavaScript
1
star
65

sloppy

Sloppy quorum implementation
JavaScript
1
star
66

chromium-emulated-networks

The list of emulated network conditions from Chromium's devtools as JSON. Useful for configuring a specific latency and bandwidth profile.
1
star
67

fffuuu

A TCP socket client with transparent reconnection support and message buffering while disconnected.
JavaScript
1
star
68

chromium-emulated-devices

The list of emulated devices from Chromium's devtools as JSON. Useful for plucking out device resolutions, pixel ratios and user agent strings.
1
star
69

video-tools

Shell
1
star
70

identify-github-event

Map Github webhook events to their names
JavaScript
1
star
71

npmjs-github-crawler

Gets github metadata for the repos in the npm database
JavaScript
1
star
72

zendesk.js

Zendesk Javascript client (work in progress)
JavaScript
1
star