Git
Chapters ▾ 2nd Edition

8.1 Git のカスタマイズ - Git の設定

ここまで本書では、Git の基本動作やその使用法について扱ってきました。また、Git をより簡単に効率よく使うためのさまざまなツールについても紹介しました。 本章では、重要な設定項目やフックシステムを使用して、よりカスタマイズされた方法で Git を操作する方法について扱います。 これらを利用すれば、みなさん自身やその勤務先、所属グループのニーズにあわせた方法で Git を活用できるようになるでしょう。

Git の設定

使い始める で手短にごらんいただいたように、git config コマンドで Gitの設定が行えます。 最初にすることと言えば、名前とメールアドレスの設定でしょう。

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

ここでは、同じようにして設定できるより興味深い項目をいくつか身につけ、Git をカスタマイズしてみましょう。

まず、簡単におさらいしましょう。Git では、いくつかの設定ファイルを使ってデフォルト以外の挙動を定義します。 最初に Git が見るのは /etc/gitconfig で、ここにはシステム上の全ユーザーの全リポジトリ向けの設定値を記述します。 git config にオプション --system を指定すると、このファイルの読み書きを行います。

次に Git が見るのは ~/.gitconfig (または ~/.config/git/config )で、これは各ユーザー専用のファイルです。 Git でこのファイルの読み書きをするには、--global オプションを指定します。

最後に Git が設定値を探すのは、現在使用中のリポジトリの設定ファイル (.git/config) です。 この値は、そのリポジトリだけで有効なものです。

これらの “レベル” (システム、グローバル、ローカル)の間では、いずれも後から読んだ値がその前の値を上書きします。したがって、たとえば .git/config に書いた値は /etc/gitconfig での設定よりも優先されます。

Note

Git の設定ファイルはプレーンテキストなので、これらのファイルを手動で編集し、正しい構文で内容を追加することで、上記のような設定を行うことも可能ですが、通常は git config コマンドを使ったほうが簡単です。

基本的なクライアントのオプション

Git の設定オプションは、おおきく二種類に分類できます。クライアント側のオプションとサーバー側のオプションです。 大半のオプションは、クライアント側のもの、つまり個人的な作業環境を設定するためのものとなります。 大量の、本当に大量の オプションが使用できますが、ここでは、もっとも一般的で、もっともよく使われているものだけを取り上げます。 その他のオプションの多くは特定の場合にのみ有用なものなので、ここでは扱いません。 Git で使えるすべてのオプションを知りたい場合は、次のコマンドを実行しましょう。

$ man git-config

このコマンドは、利用できるすべてのオプションを、簡単な説明とともに一覧表示します。 この内容は、 http://git-scm.com/docs/git-config.html にあるリファレンスでも見ることができます。

core.editor

デフォルトでは、コミットやタグのメッセージを編集するときには、ユーザーがデフォルトエディタとして設定したエディタ( $VISUAL または $EDITOR)が使われます。デフォルトエディタが設定されていない場合は vi エディタが使われます。 このデフォルト設定を別のものに変更するには core.editor を設定します。

$ git config --global core.editor emacs

これで、シェルのデフォルトエディタに関係なく、Git でメッセージを編集する際には Emacs が起動されるようになりました。

commit.template

システム上のファイルへのパスをここに設定すると、Git はそのファイルをコミット時のデフォルトメッセージとして使います。 たとえば、次のようなテンプレートファイルを作って ~/.gitmessage.txt においたとしましょう。

subject line

what happened

[ticket: X]

git commit のときにエディタに表示されるデフォルトメッセージをこれにするには、commit.template の設定を変更します。

$ git config --global commit.template ~/.gitmessage.txt
$ git commit

すると、コミットメッセージの雛形としてこのような内容がエディタに表示されます。

subject line

what happened

[ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C

コミットメッセージについてチーム内に所定の決まりがあるのなら、その決まりに従ったテンプレートをシステム上に作って Git にそれを使わせるようにするとよいでしょう。そうすれば、その決まりに従ってもらいやすくなります。

core.pager

core.pager は、Git が logdiff などを出力するときに使うページャを設定します。 more などのお好みのページャを設定したり (デフォルトは less です)、空文字列を設定してページャを使わないようにしたりできます。

$ git config --global core.pager ''

これを実行すると、すべてのコマンドの出力を、どんなに長くなったとしても全部 Git が出力するようになります。

user.signingkey

署名入りの注釈付きタグ (作業内容への署名 で取り上げました) を作る場合は、GPG 署名用の鍵を登録しておくと便利です。 鍵の ID を設定するには、このようにします。

$ git config --global user.signingkey <gpg-key-id>

これで、git tag コマンドでいちいち鍵を指定しなくてもタグに署名できるようになりました。

$ git tag -s <tag-name>

core.excludesfile

プロジェクトごとの .gitignore ファイルでパターンを指定すると、git add したときに Git がそのファイルを無視してステージしないようになります。これについては ファイルの無視 で説明しました。

ですが、作業中のすべてのリポジトリで、ある特定のファイルを無視したい場合もあります。 Mac OS X を使っているのなら、 .DS_Store というファイルに見おぼえがあるでしょう。 使っているエディタが Emacs か Vim なら、 ~ で終わるファイルのことを知っていることと思います。

このような設定を行うには、グローバルな .gitignore のようなファイルが必要です。 ~/.gitignore_global ファイルへ次の内容を書き込んで、

*~
.DS_Store

その上で git config --global core.excludesfile ~/.gitignore_global を実行すれば、これらのファイルで手を煩わすことは二度となくなります。

help.autocorrect

Git でコマンドを打ち間違えると、こんなふうに表示されます。

$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.

Did you mean this?
    checkout

Git は気を利かせて、何をしたかったのか推測はしてくれますが、実行まではしません。 help.autocorrect を 1 にしておくと、 Git は実際にそのコマンドを実行しようとします。

$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...

“0.1 seconds” という箇所に注目してください。 help.autocorrect は整数値で、0.1秒単位での時間を表しています。 そのため、仮に 50 を設定したなら、自動修正したコマンドが実行される前に 5 秒の猶予が与えられます。

Git における色

Git では、ターミナルへの出力に色をつけることができます。ぱっと見て、すばやくお手軽に出力内容を把握できるようになるでしょう。 さまざまなオプションで、お好みに合わせて色を設定しましょう。

color.ui

Git は自動的に大半の出力に色づけをします。ですが、この挙動が気に入らないなら、そのためのマスタースイッチがあります。 ターミナルへの出力への色付けをすべてオフにするなら、以下のようにします。

$ git config --global color.ui false

デフォルトの設定は auto で、直接ターミナルへ出力する場合には色付けを行いますが、パイプやファイルへリダイレクトした場合にはカラーコントロールコードを出力しません。

また always を指定すると、ターミナルであってもパイプであっても色をつけます。 always を使うことは、まずないでしょう。たいていの場合は、カラーコードを含む結果をリダイレクトしたければ、 Git コマンドに --color フラグを渡せばカラーコードの使用を強制できます。 ふだんはデフォルトの設定で要望を満たせるでしょう。

color.*

どのコマンドをどのように色づけするかをより細やかに指定したい場合、コマンド単位の色づけ設定を使用します。 これらの項目には truefalse あるいは always が指定できます。

color.branch
color.diff
color.interactive
color.status

さらに、これらの項目ではサブ設定が使え、出力の一部について特定の色を使うように指定することもできます。 たとえば、diff の出力で、メタ情報を黒地に青の太字で出力させたい場合は次のようにします。

$ git config --global color.diff.meta "blue black bold"

色として指定できる値は normalblackred、 `greenyellowbluemagentacyanwhite のいずれかです。先ほどの例の bold のように属性も指定できます。bolddimul (下線つき)、 blinkreverse (文字と背景の色を逆にする)のいずれかを指定できます。

外部のマージツールおよび diff ツール

Git には、内部的な diff の実装が組み込まれています。本書でこれまで見てきた内容は、それを使用しています。ですが、外部のツールを使うよう設定することもできます。 また、コンフリクトを手動で解決するのではなくグラフィカルなコンフリクト解消ツールを使うよう設定することもできます。 ここでは Perforce Visual Merge Tool (P4Merge) を使って diff の表示とマージの処理を行えるようにする例を示します。これはすばらしいグラフィカルツールで、しかも無料で使えるからです。

P4Merge はすべての主要プラットフォーム上で動作するので、実際に試してみたい人は試してみるとよいでしょう。 この例では、Mac や Linux 形式のパス名を例に使います。Windows の場合は、/usr/local/bin のところを環境に合わせたパスに置き換えてください。

まず、P4Merge を からダウンロードします。 次に、コマンドを実行するための外部ラッパースクリプトを用意します。 この例では、Mac 用の実行パスを使います。他のシステムで使う場合は、p4merge のバイナリがインストールされた場所に置き換えてください。 次のような内容のマージ用ラッパースクリプト extMerge を用意してください。これは、 p4merge にすべての引数を渡して呼び出します。

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*

diff のラッパーは、7 つの引数が渡されていることを確認したうえでそのうちのふたつをマージスクリプトに渡します。 デフォルトでは、Git は次のような引数を diff プログラムに渡します。

path old-file old-hex old-mode new-file new-hex new-mode

ここで必要な引数は old-filenew-file だけなので、ラッパースクリプトではこれらを渡すようにします。

$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"

また、これらのツールは実行可能にしておかなければなりません。

$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff

これで、自前のマージツールや diff ツールを使えるように設定する準備が整いました。 設定項目はひとつだけではありません。まず merge.tool でどんなツールを使うのかを Git に伝え、 mergetool.<tool>.cmd でそのコマンドを実行する方法を指定し、mergetool.<tool>.trustExitCode では「そのコマンドの終了コードでマージが成功したかどうかを判断できるのか」を指定し、diff.external では diff の際に実行するコマンドを指定します。つまり、このような 4 つのコマンドを実行することになります。

$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
  'extMerge \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff

あるいは、~/.gitconfig ファイルを編集してこのような行を追加します。

[merge]
  tool = extMerge
[mergetool "extMerge"]
  cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
  trustExitCode = false
[diff]
  external = extDiff

すべて設定し終えたら、このような diff コマンドを実行すると、

$ git diff 32d1776b1^ 32d1776b1

結果をコマンドラインに出力するかわりに、Git から P4Merge が呼び出され、次のようになります。

P4Merge.
Figure 142. P4Merge.

ふたつのブランチをマージしてコンフリクトが発生した場合は git mergetool を実行します。すると P4Merge が立ち上がり、コンフリクトの解決を GUI ツールで行えるようになります。

このようなラッパーを設定しておくと、あとで diff ツールやマージツールを簡単に変更できます。 たとえば extDiffextMerge で KDiff3 を実行させるように変更するには extMerge ファイルをこのように変更するだけでよいのです。

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*

これで、Git での diff の閲覧やコンフリクトの解決の際に KDiff3 が立ち上がるようになりました。

Git にはさまざまなマージツール用の設定が事前に準備されており、特に設定しなくても利用できます。 サポートされているツールを確認するには、次のコマンドを実行します。

$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
        emerge
        gvimdiff
        gvimdiff2
        opendiff
        p4merge
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        araxis
        bc3
        codecompare
        deltawalker
        diffmerge
        diffuse
        ecmerge
        kdiff3
        meld
        tkdiff
        tortoisemerge
        xxdiff

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.

KDiff3 を diff ツールとしてではなくマージのときにだけ使いたい場合は、kdiff3 コマンドにパスが通っている状態で次のコマンドを実行します。

$ git config --global merge.tool kdiff3

extMergeextDiff を準備せずにこのコマンドを実行すると、マージの解決の際には KDiff3 を立ち上げて diff の際には通常の Git の diff ツールを使うようになります。

書式設定と空白文字

書式設定や空白文字の問題は微妙にうっとうしいもので、とくにさまざまなプラットフォームで開発している人たちと共同作業をするときに問題になりがちです。 使っているエディタが知らぬ間に空白文字を埋め込んでしまっていたり Windows で開発している人が行末にキャリッジリターンを付け加えてしまったりなどしてパッチが面倒な状態になってしまうことも多々あります。 Git では、こういった問題に対処するための設定項目も用意しています。

core.autocrlf

自分が Windows で開発している一方、チームの中に Windows 以外の環境で開発している人がいる場合(逆も同様)には、改行コードの問題に巻き込まれることがありがちです。 Windows ではキャリッジリターンとラインフィードでファイルの改行を表すのですが、Mac や Linux ではラインフィードだけで改行を表すという違いが原因です。 これはささいな違いではありますが、さまざまなプラットフォームにまたがる作業では非常に面倒なものです。Windows のエディタには、LFだけの改行をだまってCRLFに置き換えたり、ユーザがEnterキーを押下した際にCRとLFの両方を挿入したりするものが数多くあります。

Git はこの問題に対処するために、コミットする際には行末の CRLF を LF に自動変換し、ファイルシステム上にチェックアウトするときには逆の変換を行うようにできます。 この機能を使うには core.autocrlf を設定します。

Windows で作業をするときにこれを true に設定すると、コードをチェックアウトするときに行末の LF を CRLF に自動変換してくれます。

$ git config --global core.autocrlf true

Linux や Mac などの行末に LF を使うシステムで作業をしている場合は、Git にチェックアウト時の自動変換をされてしまうと困ります。しかし、行末が CRLF なファイルが紛れ込んでしまった場合には Git に自動修正してもらいたいものです。 コミット時の CRLF から LF への変換はさせたいけれどもそれ以外の自動変換が不要な場合は、core.autocrlf を input に設定します。

$ git config --global core.autocrlf input

この設定は、Windows にチェックアウトしたときの CRLF への変換は行いますが、Mac や Linux へのチェックアウト時は LF のままにします。

Windows のみのプロジェクトで作業をしているのなら、この機能を無効にしてキャリッジリターンをそのままリポジトリに記録してもよいでしょう。その場合は、値 false を設定します。

$ git config --global core.autocrlf false

core.whitespace

Git には、空白文字に関する問題を見つけて修正するための設定もあります。 空白文字に関する主要な六つの問題に対応するもので、そのうち三つはデフォルトで有効になっています。残りの三つはデフォルトでは有効になっていませんが、有効化することもできます。

デフォルトで有効になっている設定は、行末の空白文字を見つける blank-at-eol 、ファイル末尾の空白文字を見つける blank-at-eof 、行頭のタブ文字より前にある空白文字を見つける space-before-tab です。

デフォルトでは無効だけれども有効にすることもできる三つの設定は、行頭がタブ文字でなく空白文字になっている行を見つける indent-with-non-tab (空白文字の数は tabwidth オプションで制御可能)、行内のインデント部分にあるタブ文字を見つける tab-in-indent 、行末のキャリッジリターンを許容する cr-at-eol です。

これらのオン・オフを切り替えるには、core.whitespace にカンマ区切りで項目を指定します。 無効にしたい場合は、設定文字列でその項目を省略するか、あるいは項目名の前に - をつけます。 たとえば cr-at-eol 以外のすべてを設定したい場合は、このようにします。

$ git config --global core.whitespace \
    trailing-space,space-before-tab,indent-with-non-tab

git diff コマンドを実行したときに Git がこれらの問題を検出すると、その部分を色付けして表示します。修正してからコミットするようにしましょう。 この設定は、git apply でパッチを適用する際にも助けとなります。 空白に関する問題を含むパッチを適用するときに警告を発してほしい場合には、次のようにします。

$ git apply --whitespace=warn <patch>

あるいは、問題を自動的に修正してからパッチを適用したい場合は、次のようにします。

$ git apply --whitespace=fix <patch>

これらの設定は、git rebase コマンドにも適用されます。 空白に関する問題を含むコミットをしたけれどまだそれを公開リポジトリにプッシュしていない場合は、 git rebase --whitespace=fix を実行すれば、パッチを書き換えて空白問題を自動修正してくれます。

サーバーの設定

Git のサーバー側の設定オプションはそれほど多くありませんが、いくつか興味深いものがあるので紹介します。

receive.fsckObjects

デフォルトでは、Git はプッシュで受け取ったオブジェクトの SHA-1 チェックサムが一致していて有効なオブジェクトを指しているということをチェックさせることができます。 ですが、デフォルトではこのチェックは行わないようになっています。このチェックは比較的重たい処理であり、リポジトリのサイズが大きかったりプッシュする量が多かったりすると、毎回チェックさせるのには時間がかかるでしょう。 毎回のプッシュの際に Git にオブジェクトの一貫性をチェックさせたい場合は、receive.fsckObjects を true にして強制的にチェックさせるようにします。

$ git config --system receive.fsckObjects true

これで、Git がリポジトリの整合性を確認してからでないとプッシュが認められないようになります。壊れたデータをまちがって受け入れてしまうことがなくなりました。

receive.denyNonFastForwards

すでにプッシュしたコミットをリベースしてもう一度プッシュした場合、あるいはリモートブランチが現在指しているコミットを含まないコミットをプッシュしようとした場合は、プッシュが拒否されます。 これは悪くない方針でしょう。しかしリベースの場合は、自分が何をしているのかをきちんと把握していれば、プッシュの際に -f フラグを指定して強制的にリモートブランチを更新することもできます。

このような強制更新機能を無効にするには、receive.denyNonFastForwards を設定します。

$ git config --system receive.denyNonFastForwards true

もうひとつの方法として、サーバー側の receive フックを使うこともできます。こちらの方法については後ほど簡単に説明します。 receive フックを使えば、特定のユーザーだけ強制更新を無効にするなどより細やかな制御ができるようになります。

receive.denyDeletes

denyNonFastForwards の制限を回避する方法として、いったんブランチを削除してから新しいコミットを参照するブランチをプッシュしなおすことができます。 これを無効にするには、 receive.denyDeletes を true に設定します。

$ git config --system receive.denyDeletes true

これは、プッシュによるブランチやタグの削除を一切拒否し、誰も削除できないようにします。 リモートブランチを削除するには、サーバー上の ref ファイルを手で削除しなければなりません。ACL を使って、ユーザー単位でこれを制限することもできますが、その方法は Git ポリシーの実施例 で扱います。