Extending git

Stefan Saasen
Stefan Saasen

Mercurial は(内部的にではあるものの)明確に定義された API を備えていて、Mercurial の機能を拡張する エクステンション を書くのに使用できますが、git の拡張モデルは小さくシンプルなプログラムを書くという UNIX 哲学 に従いつつ、同様の効果を達成しています。つまり、git の "拡張" はいくつかの簡単なルールに従い、任意の言語を使って作成でき、しかも git に内蔵されているかのようなコマンドを追加することができるのです。

Example: git activity

To see the activity on all the branches in a repository I've implemented a git activity command. git activity shows the latest commit on every branch, sorted by recency.

It shows the following output when executed in the Rails repository:

Rails Output

The script is written in bash and fairly straightforward. We set up colours and parse some command line options the scripts supports (e.g. to turn off colours, to limit the output) and then run git for-each-ref to output information about each ref.

set -e
OUTPUT_FILTER="cat" # no-op
commit_id_format=$(tput setaf 1)
date_format=$(tput bold; tput setaf 4)
author_format=$(tput setaf 2)
ref_name_format=$(tput setaf 3)
bold=$(tput bold)
reset=$(tput sgr0)
function usage() {
echo ""
echo "git activity"
echo ""
echo " See 'man git-activity' for further information"
# actually parse the options and do stuff
while [[ $1 = -?* ]]; do
case $1 in
exit 0
echo "Fetch updates"
git fetch -q
#OUTPUT_FILTER="tail -n ${limit}"
*) ;;
# Use newline as a field separator
IFS=$(echo -en "\n\b")
# Use tac if available, otherwise tail with the possibly-not-always-available
# -r flag (for reverse output)
TAC=$(which tac || echo 'tail -r')
for line in $(git for-each-ref ${GIT_OPTS} refs/remotes --format="%(authordate:relative)|%(objectname:short)|%(authorname)|%(refname:short)|%(subject)" --sort="-authordate"); do
fields=(`echo $line | tr "|" "\n"`)
printf "${date_format}%15s${reset} ${commit_id_format}%s${reset} - ${author_format}[%s]${reset} (${ref_name_format}%s${reset}): %s\n" ${fields[*]}
done | eval $TAC # reverse sort the output to show the newest entry last

このスクリプトを Git のサブコマンドとして使用可能にするために、守るべき重要なルールは、以下のとおりです。

  • It should be named git-COMMANDNAME, in this case it's called git-activity
  • and it needs to be executable and available on the $PATH In my example the custom git-activity script is in the /usr/local/bin directory but it can be in any directory that is on the $PATH:
[5002] λ > type git-activity
git-activity is /usr/local/bin/git-activity
[5002] λ > git activity

Providing a manual/help page

If the custom command has an accompanying man page, the git help command will show the help information as well. E.g. the man page for the activity command is located in /usr/local/share/man/man1/git-activity.1 and can be show by either man git-activity or git help activity.

The manpath command can be used to show the locations the system uses to locate man pages:

[5003] λ > manpath /Users/ssaasen/.opam/system/man:/usr/local/share/man:/usr/share/man:\ /Users/ssaasen/.cabal/share/man:/opt/scala/man

The output for git help activity is (using https://bitbucket.org/ssaasen/git-pastiche/src/master/man/git-activity.1):

Git activity man page

Bonus tip Man pages can easily be generated from Markdown using Pandoc:

[5010] λ > pandoc -s -w man doc/git-activity.1.md -o ./distribution/man/git-activity.1
# Display the man page for testing
[5011] λ > nroff -man ./distribution/man/git-activity.1
# Show the actual man page being used after copying it to a known manpath location:
[5012] λ > man -wa git-activity


By following a couple of simple rules and by embracing the Unix model of composing functionality out of small, focused programs and scripts, it turns out that it is surprisingly easy to extend git's functionality and making custom commands part of the git command suite.


The source for git-activity and a few other commands can be found here: https://bitbucket.org/ssaasen/git-pastiche

その他の追加の Git コマンドは、以下をご覧ください。

Git を学習する準備はできていますか?