VERSION

This is v4.0.0 of git multi … hooray!

SYNOPSIS

There are some options for git multi itself, in which case it is invoked as follows:

git multi --<option> [<option_arguments>]

To execute the same git command in multiple repositories, the invocation is as follows:

git multi <git_command> [<git_command_arguments>]

Both ways of running git multi take an optional, so-called "multi repo" argument to limit the operation to the list of repositories in the referenced "multi repo", ie. a single GitHub user or a single GitHub organization:

git multi ++<multi_repo> --<option> [<option_arguments>]

and…

git multi ++<multi_repo> <git_command> [<git_command_arguments>]

DESCRIPTION

Convenient way to execute the same git command in a set of related repositories, which could be all GitHub repos for a given user, or all repos for a given GitHub organization.

Multipe users and organizations can be configured, and by default git multi operates on all repositories for all users and all orgs; to limit the operation to a single user or a single org, the optional ++<multi_repo> argument can be used.

The list of repos for a user or an org is determined via a GitHub API v3 call and cached locally (in binary format) for performance and offline usage.

OPTIONS

--version

print out this script’s version number

--help

you’re looking at it: show the man page

--html

open the HTML version of the man page

--report

report on various repository stats and metrics

--count

print out the count of repos (per type)

--refresh

refresh the list of user & organization repos

--json

output repository details to JSON

--list

print out the names of all repos

--archived

print out the names of all repos

--forked

print out the names of all repos

--private

print out the names of all repos

--paths

print out the full path for each repos

--missing

print out names of repos that haven’t been cloned

--clone

clones missing repositories into ${HOME}/Workarea (by default)

--stale

list repos that have been deleted on github.com

--excess

list repos that don’t exist on github.com

--spurious

list cloned repos whose remote doesn’t match a github.com origin

--query (args)

query GitHub repo metadata for each repository

--find <ruby>

print out the repos for which the Ruby code evaluates to true

--eval <ruby>

execute the given Ruby code in the context of each repo

--raw <cmd>

execute the given shell command inside each git repository

--shell

run an interactive login shell inside each git directory

EXAMPLES

count the number of repos

git multi --list | wc -l

disk usage of each locally cloned repo

git multi --paths | xargs -n 1 du -hs

disk usage using the --raw option

git multi --raw 'du -hs .'

group and count the repos by GitHub-determined language

git multi --query language | cut -f 2 -d : | sort | uniq -c | sort -n -r

find out the most-used Ruby versions

git multi --raw '[ -f .ruby-version ] && cat .ruby-version' | cut -f 2 -d : | sort | uniq -c | sort -n -r

find GitHub repos without a description

git multi --query description | egrep ': *$'

fetch remote branches for all repos

git multi fetch -p

print out the local branch for each repo (using symbolic-ref)

git multi symbolic-ref --quiet --short HEAD

print out the local branch for each repo (using rev-parse)

git multi rev-parse --abbrev-ref=strict HEAD

find all repos for which the origin remote isn’t github.com

git multi config --get remote.origin.url | fgrep -v git@github.com:

a kind of "repository creation" report: count the number of repos created in each quarter

git multi --eval "class ::Time; def quarter() (month.to_f / 3.0).ceil; end; end; puts format('%d-Q%d', created_at.year, created_at.quarter)" | sort | uniq -c

for each repo, list all remote branches, sorted by the "age" of the last commit on each branch

git multi for-each-ref --sort="-authordate" --format="%(refname)%09%(authordate:relative)%09%(authorname)" refs/remotes/origin

same as above, but columnize the generated output (NOTE: replace ^I with CTRL-V/CTRL-I in your terminal)

git multi for-each-ref --sort="-authordate" --format="%(refname)%09%(authordate:relative)%09%(authorname)" refs/remotes/origin | column -t -s "^I"

same as above, but refresh the list of remote branches first

git multi fetch -p ; git multi for-each-ref --sort="-authordate" --format="%(refname)%09%(authordate:relative)%09%(authorname)" refs/remotes/origin

find all Rails projects

git multi --raw '[ -f Gemfile ] && fgrep -q -l rails Gemfile && echo uses Rails' | cat

find all Mongoid dependencies

git multi --raw '[ -f Gemfile.lock ] && egrep -i "^    mongoid (.*)" Gemfile.lock' | column -s: -t

find all projects that have been pushed to in the last week

git multi --find '((Time.now.utc - pushed_at) / 60 / 60 / 24) <= 7'

print out the number of days since the last push to each repository

git multi --eval 'puts "%s - %d days" % [full_name, ((Time.now.utc - pushed_at) / 60 / 60 / 24).ceil]'

find all projects that have seen activity this calendar year

git multi --find 'pushed_at >= Date.civil(Date.today.year, 1, 1).to_time.utc'

print out all webhooks

git multi --eval 'puts client.hooks(full_name).map { |hook| [full_name, hook.name, hook.config.url].join("\t") }'

delete all webhooks with matching URLs (in this case: notify.travis-ci.org)

git multi --eval 'client.hooks(full_name).find_all { |hook| hook.config.url =~ /notify.travis-ci.org/ }.each { |hook| client.remove_hook(full_name, hook.id) }'

print out all deploy keys

git multi --eval '(keys = client.list_deploy_keys(full_name)).any? && begin print full_name ; print "\t" ; puts keys.map(&:title).sort.join("\t") ; end'

find all organization repositories that depend on a given org repo, e.g. business_rules

git multi --graph | fgrep business_rules

generate a dependency graph of all organization repositories using yuml.me

DEPENDENCIES=$( git multi --graph | ruby -n -e 'parent, children = $_.split(": ") ; puts children.split(" ").map { |child| "[#{parent}]->[#{child}]" }' | tr '\n' ',' ) ; open "http://yuml.me/diagram/scruffy/class/${DEPENDENCIES}"

generate a dependency graph of all organization repositories using Graphviz

git multi --graph | ruby -n -e 'parent, children = $_.split(": ") ; puts children.split(" ").map { |child| "\"#{parent}\"->\"#{child}\";" }' | awk 'BEGIN { print "digraph {\nrankdir=\"LR\";\n" } ; { print ; } END { print "}\n" } ; ' | dot -Tpng > /tmp/ghor.png ; open -a Preview /tmp/ghor.png

QUERY ARGUMENTS

The following is a list of valid arguments for the git multi --query option:

archive_url          archived             assignees_url
blobs_url            branches_url         clone_url
collaborators_url    comments_url         commits_url
compare_url          contents_url         contributors_url
created_at           default_branch       deployments_url
description          disabled             downloads_url
events_url           fork                 forks
forks_count          forks_url            full_name
git_commits_url      git_refs_url         git_tags_url
git_url              has_downloads        has_issues
has_pages            has_projects         has_wiki
homepage             hooks_url            html_url
id                   issue_comment_url    issue_events_url
issues_url           keys_url             labels_url
language             languages_url        license
merges_url           milestones_url       mirror_url
name                 network_count        node_id
notifications_url    open_issues          open_issues_count
organization         owner                permissions
private              pulls_url            pushed_at
releases_url         size                 ssh_url
stargazers_count     stargazers_url       statuses_url
subscribers_count    subscribers_url      subscription_url
svn_url              tags_url             teams_url
temp_clone_token     trees_url            updated_at
url                  watchers             watchers_count

JQ INTEGRATION

jq is like sed for JSON data… all of the above query arguments can be used in conjunction with jq to query, filter, map and transform the GitHub repository attributes stored in the local, binary repository cache; here are some examples:

# print out each repository's name and its description
git multi --json | jq -r '.[] | .name + ": " + .description'
# print out the name of all "forked" repositories
git multi --json | jq -r '.[] | select(.fork == true) | .full_name'

FILES

${HOME}/Workarea

root directory where repos will been cloned

${HOME}/.git/multi/repositories.byte

local, binary cache of GitHub repository metadata

${HOME}/.git/multi/superprojects.config

definitions for so-called "superproject" multi repos

REFERENCES