Git --everything-is-local
Chapters ▾ 1st Edition

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

Git の設定

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

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

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

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

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

最後に Git が設定値を探すのは、現在使用中のリポジトリの設定ファイル (.git/config) です。この値は、そのリポジトリだけで有効なものです。後から読んだ値がその前の値を上書きします。したがって、たとえば .git/config に書いた値は /etc/gitconfig での設定よりも優先されます。これらのファイルを手動で編集して正しい構文で値を追加することもできますが、通常は git config コマンドを使ったほうが簡単です。

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

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

$ git config --help

また、git config のマニュアルページには、利用できるすべてのオプションについて詳しい説明があります。

core.editor

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

$ git config --global core.editor emacs

これで、シェルのデフォルトエディタを設定していない場合に Git が起動するエディタが Emacs に変わりました。

commit.template

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

subject line

what happened

[ticket: X]

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

$ git config --global commit.template $HOME/.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

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

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

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

$ git tag -s <tag-name>

core.excludesfile

プロジェクトごとの .gitignore ファイルでパターンを指定すると、git add したときに Git がそのファイルを無視してステージしないようになります。これについては第 2 章で説明しました。しかし、これらの内容をプロジェクトの外部で管理したい場合は、そのファイルがどこにあるのかを core.excludesfile で設定します。ここに設定する内容はファイルのパスです。ファイルの中身は .gitignore と同じ形式になります。

help.autocorrect

このオプションが使えるのは Git 1.6.1 以降だけです。Git でコマンドを打ち間違えると、こんなふうに表示されます。

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

Did you mean this?
     commit

help.autocorrect を 1 にしておくと、同じような場面でもし候補がひとつしかなければ自動的にそれを実行します。

Git における色

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

color.ui

あらかじめ指定しておけば、Git は自動的に大半の出力に色づけをします。何にどのような色をつけるかをこと細かに指定することもできますが、すべてをターミナルのデフォルト色設定にまかせるなら color.ui を true にします。

$ git config --global color.ui true

これを設定すると、出力がターミナルに送られる場合に Git がその出力を色づけします。ほかに false という値を指定することもでき、これは出力に決して色をつけません。また always を指定すると、すべての場合に色をつけます。すべての場合とは、Git コマンドをファイルにリダイレクトしたり他のコマンドにパイプでつないだりする場合も含みます。

color.ui = always を使うことは、まずないでしょう。たいていの場合は、カラーコードを含む結果をリダイレクトしたい場合は Git コマンドに --color フラグを渡してカラーコードの使用を強制します。ふだんは color.ui = true の設定で要望を満たせるでしょう。

color.*

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

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

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

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

色として指定できる値は normal、black、red、green、yellow、blue、magenta、cyan あるいは white のいずれかです。先ほどの例の bold のように属性を指定することもできます。bold、dim、ul、blink および reverse のいずれかを指定できます。

git config のマニュアルページに、すべてのサブ設定がまとめられていますので参照ください。

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

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

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

まず、P4Merge をここからダウンロードします。

http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools

最初に、コマンドを実行するための外部ラッパースクリプトを用意します。この例では、Mac 用の実行パスを使います。他のシステムで使う場合は、p4merge のバイナリがインストールされた場所に置き換えてください。次のようなマージ用ラッパースクリプト extMerge を用意しました。これは、すべての引数を受け取ってバイナリをコールします。

$ 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.*.cmd でそのコマンドを実行する方法を指定し、mergetool.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.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

すべて設定し終えたら、

$ git diff 32d1776b1^ 32d1776b1

このような diff コマンドを実行すると、結果をコマンドラインに出力するかわりに P4Merge を立ち上げ、図 7-1 のようになります。


図 7-1. 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 にはさまざまなマージツール用の設定が事前に準備されており、特に設定しなくても利用することができます。事前に設定が準備されているツールは kdiff3、opendiff、tkdiff、meld、xxdiff、emerge、vimdiff そして gvimdiff です。KDiff3 を diff ツールとしてではなくマージのときにだけ使いたい場合は、kdiff3 コマンドにパスが通っている状態で次のコマンドを実行します。

$ git config --global merge.tool kdiff3

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

書式設定と空白文字

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

core.autocrlf

自分が Windows で開発していたり、チームの中に Windows で開発している人がいたりといった場合に、改行コードの問題に巻き込まれることがありがちです。Windows ではキャリッジリターンとラインフィードでファイルの改行を表すのですが、Mac や Linux ではラインフィードだけで改行を表すという違いが原因です。ささいな違いではありますが、さまざまなプラットフォームにまたがる作業では非常に面倒なものです。

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 のままにします。またリポジトリにコミットする際には LF への変換を行います。

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

$ git config --global core.autocrlf false

core.whitespace

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

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

デフォルトでは無効だけれども有効にすることもできる設定は、行頭にある八文字以上の空白文字を見つける indent-with-non-tab と行末のキャリッジリターンを許容する 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コマンドにも適用されます。空白に関する問題を含むコミットをしたけれどまだそれを公開リポジトリにプッシュしていない場合は、rebase--whitespace=fix オプションをつけて実行すれば、パッチを書き換えて空白問題を自動修正してくれます。

サーバーの設定

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

receive.fsckObjects

デフォルトでは、Git はプッシュで受け取ったオブジェクトの一貫性をチェックしません。各オブジェクトの SHA-1 チェックサムが一致していて有効なオブジェクトを指しているということを Git にチェックさせることもできますが、デフォルトでは毎回のプッシュ時のチェックは行わないようになっています。このチェックは比較的重たい処理であり、リポジトリのサイズが大きかったりプッシュする量が多かったりすると、毎回チェックさせるのには時間がかかるでしょう。毎回のプッシュの際に 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 の制限を回避する方法として、いったんブランチを削除してから新しいコミットを参照するブランチをプッシュしなおすことができます。その対策として、新しいバージョン (バージョン 1.6.1 以降) の Git では receive.denyDeletes を true に設定することができます。

$ git config --system receive.denyDeletes true

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