VERSION
This is v2.1.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
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 '(hooks = client.hooks(full_name)).any? && begin print full_name ; print "\t" ; puts hooks.map { |hook| ["", hook.name, hook.config.url].join("\t") } ; end'
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 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 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
-
homepage for
git-multi
: https://github.com/pvdb/git-multi -
the GitHub API: https://developer.github.com/v3/
-
the
jq
command-line utility: http://stedolan.github.io/jq/