章 ▾ 第2版

8.1 Gitのカスタマイズ - 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がこれらの値を探す最初の場所は、システム全体に適用される[path]/etc/gitconfigファイルで、これはシステム上のすべてのユーザーとすべてのリポジトリに適用される設定を含みます。git config--systemオプションを渡すと、このファイルからのみ読み書きを行います。

Gitが次に探す場所は、ユーザーごとの~/.gitconfig(または~/.config/git/config)ファイルです。--globalオプションを渡すと、このファイルに読み書きさせることができます。

最後に、Gitは現在使用しているリポジトリのGitディレクトリ(.git/config)内の設定ファイルで設定値を探します。これらの値は、その単一のリポジトリに固有のものであり、git config--localオプションを渡すことと等価です。どのレベルで作業するかを指定しない場合、これがデフォルトになります。

これらの「レベル」(システム、グローバル、ローカル)はそれぞれ前のレベルの値を上書きします。したがって、例えば.git/configの値は[path]/etc/gitconfigの値を上書きします。

Gitの設定ファイルはプレーンテキストなので、手動でファイルを編集して正しい構文を挿入することでもこれらの値を設定できます。ただし、一般的にはgit configコマンドを実行する方が簡単です。

基本的なクライアント設定

Gitが認識する設定オプションは、クライアントサイドとサーバーサイドの2つのカテゴリに分類されます。オプションの大部分はクライアントサイドのもので、個人的な作業設定を構成します。非常に多くの設定オプションがサポートされていますが、その大部分は特定の特殊なケースでのみ役立ちます。ここでは、最も一般的で役立つオプションのみを説明します。あなたのGitのバージョンが認識するすべてのオプションのリストを見たい場合は、次のコマンドを実行できます。

$ man git-config

このコマンドは、利用可能なすべてのオプションをかなり詳細にリスト表示します。この参照資料はhttps://git.dokyumento.jp/docs/git-configでも見つけることができます。

高度なユースケースでは、上記のドキュメントで「Conditional includes」を調べることをお勧めします。

core.editor

デフォルトでは、Gitはシェル環境変数VISUALまたはEDITORのいずれかを介してデフォルトのテキストエディタとして設定したものを使用します。設定されていない場合はviエディタにフォールバックして、コミットメッセージやタグメッセージを作成・編集します。そのデフォルトを別のものに変更するには、core.editor設定を使用できます。

$ git config --global core.editor emacs

これで、デフォルトのシェルエディタとして何が設定されていても、GitはEmacsを起動してメッセージを編集します。

commit.template

これをシステム上のファイルのパスに設定すると、Gitはコミット時にそのファイルをデフォルトの初期メッセージとして使用します。カスタムコミットテンプレートを作成する利点は、コミットメッセージを作成する際の適切な形式とスタイルを自分自身(または他の人)に思い出させることができる点です。

たとえば、~/.gitmessage.txtにある次のようなテンプレートファイルを考えてみましょう。

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]

このコミットテンプレートが、コミッターに件名を短く保つこと(git log --oneline出力のため)、その下に詳細を追加すること、および問題やバグトラッカーのチケット番号が存在する場合はそれに言及することを促している点に注目してください。

git commitを実行したときにエディタに表示されるデフォルトメッセージとしてこれを使用するようにGitに指示するには、commit.template設定値を設定します。

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

そうすると、コミット時にエディタはプレースホルダーのコミットメッセージとして次のように開きます。

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[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

この設定は、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がそれらを未追跡ファイルとして認識したり、git addを実行したときにステージングしようとしないようにできます。これはファイルの無視で説明しました。

しかし、作業するすべてのリポジトリに対して特定のファイルを無視したい場合があります。お使いのコンピュータがmacOSを実行している場合、.DS_Storeファイルにはおそらく馴染みがあるでしょう。もし好みのエディタがEmacsやVimであれば、~.swpで終わるファイル名についてご存知でしょう。

この設定により、一種のグローバルな.gitignoreファイルを作成できます。もし~/.gitignore_globalファイルに次の内容で作成した場合、

*~
.*.swp
.DS_Store

…そしてgit config --global core.excludesfile ~/.gitignore_globalを実行すると、Gitはそれらのファイルについて二度とあなたを煩わせることはありません。

help.autocorrect

コマンドを誤って入力すると、次のように表示されます。

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

The most similar command is
    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秒」のことに注目してください。help.autocorrectは実際には10分の1秒を表す整数です。したがって、これを50に設定すると、Gitは自動修正されたコマンドを実行する前に、あなたが考えを変えるための猶予を5秒与えます。

Gitのカラー表示

Gitはカラフルなターミナル出力を完全にサポートしており、これによりコマンド出力を視覚的に素早く簡単に解析するのに大いに役立ちます。いくつかのオプションは、好みに応じて色を設定するのに役立ちます。

color.ui

Gitはほとんどの出力を自動的に色付けしますが、この動作が気に入らない場合は、マスター設定があります。Gitのすべての色付きターミナル出力をオフにするには、次のようにします。

$ git config --global color.ui false

デフォルト設定はautoで、これは出力が直接ターミナルに送られる場合は色付けしますが、パイプやファイルにリダイレクトされる場合は色制御コードを省略します。

また、ターミナルとパイプの違いを無視するためにalwaysに設定することもできます。これを望むことはほとんどないでしょう。ほとんどのシナリオでは、リダイレクトされた出力にカラーコードが必要な場合は、代わりにGitコマンドに--colorフラグを渡して、カラーコードを使用するように強制することができます。デフォルト設定がほとんどの場合、あなたが望むものとなるでしょう。

color.*

どのコマンドがどのように色付けされるかについてより具体的に指定したい場合は、Gitはコマンド固有の色付け設定を提供します。これらはそれぞれtruefalse、またはalwaysに設定できます。

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

さらに、これらのそれぞれには、各色を上書きしたい場合に、出力の一部に特定の色の設定を使用できるサブ設定があります。たとえば、diff出力のメタ情報を青い前景、黒い背景、太字のテキストに設定するには、次のように実行できます。

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

色は、normalblackredgreenyellowbluemagentacyan、またはwhiteのいずれかの値に設定できます。前の例のように太字などの属性が必要な場合は、bolddimul(下線)、blink、およびreverse(前景と背景の入れ替え)から選択できます。

外部マージ・差分ツール

Gitには独自のdiffの実装がありますが(本書で示してきたもの)、代わりに外部ツールを設定することもできます。また、手動で競合を解決する代わりに、グラフィカルなマージ競合解決ツールを設定することもできます。ここでは、Perforce Visual Merge Tool(P4Merge)を使って差分表示とマージ解決を行う方法を実演します。これは優れたグラフィカルツールであり、無料で利用できるからです。

これを試したい場合、P4Mergeはすべての主要なプラットフォームで動作するため、利用できるはずです。ここではmacOSおよびLinuxシステムで動作するパス名を使用します。Windowsの場合は、/usr/local/binを環境内の実行可能パスに変更する必要があります。

まず、PerforceからP4Mergeをダウンロードしてください。次に、コマンドを実行するための外部ラッパースクリプトを設定します。ここではmacOSの実行可能ファイルのパスを使用します。他のシステムでは、p4mergeバイナリがインストールされている場所になります。すべての引数を指定してバイナリを呼び出すextMergeというマージラッパースクリプトを設定します。

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

diffラッパーは、7つの引数が提供されていることを確認し、そのうちの2つをマージスクリプトに渡します。デフォルトでは、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

これで、カスタムのマージ解決ツールと差分ツールを使用するように設定ファイルをセットアップできます。これにはいくつかのカスタム設定が必要です。merge.toolはGitに使用する戦略を伝え、mergetool.<tool>.cmdはコマンドの実行方法を指定し、mergetool.<tool>.trustExitCodeはプログラムの終了コードがマージ解決の成功を示しているかどうかをGitに伝え、diff.externalは差分表示に実行するコマンドをGitに伝えます。したがって、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

これらがすべて設定された後、次のような差分コマンドを実行すると、

$ git diff 32d1776b1^ 32d1776b1

コマンドラインで差分出力を得る代わりに、GitはP4Mergeを起動します。これは次のようになります。

P4Merge
図168. P4Merge

2つのブランチをマージしようとしてマージ競合が発生した場合、git mergetoolコマンドを実行できます。これによりP4Mergeが起動し、そのGUIツールを通じて競合を解決できます。

このラッパー設定の利点は、差分ツールとマージツールを簡単に変更できることです。たとえば、extDiffextMergeツールをKDiff3ツールを実行するように変更するには、extMergeファイルを編集するだけです。

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

これで、Gitは差分表示とマージ競合解決にKDiff3ツールを使用するようになります。

Gitは、cmd設定を自分で設定しなくても、他の多くのマージ解決ツールを使用できるようにプリセットされています。サポートされているツールのリストを見るには、これを試してください。

$ 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を差分表示には使わず、マージ解決のみに使いたい場合で、kdiff3コマンドがパスに含まれているのであれば、次のように実行できます。

$ git config --global merge.tool kdiff3

extMergeextDiffファイルをセットアップする代わりにこれを実行すると、Gitはマージ解決にKDiff3を使用し、差分表示には通常のGit diffツールを使用します。

フォーマットと空白文字

フォーマットと空白文字の問題は、特にクロスプラットフォームでの共同作業において、多くの開発者が遭遇する、よりイライラする微妙な問題の一部です。エディタが静かに空白文字の変更を導入するため、パッチや他の共同作業で微妙な空白文字の変更が発生することは非常に簡単であり、ファイルがWindowsシステムに触れると、行末が置き換えられる可能性があります。Gitには、これらの問題に対処するためのいくつかの設定オプションがあります。

core.autocrlf

Windowsでプログラミングしており、そうでない人たち(またはその逆)と共同作業している場合、どこかの時点で改行コードの問題に遭遇する可能性があります。これは、Windowsがファイルの改行にキャリッジリターン文字とラインフィード文字の両方を使用するのに対し、macOSやLinuxシステムはラインフィード文字のみを使用するためです。これは微妙ですが、クロスプラットフォーム作業において信じられないほど煩わしい事実です。Windowsの多くのエディタは、既存のLF形式の改行コードをCRLFに自動的に置き換えたり、ユーザーがEnterキーを押したときに両方の改行文字を挿入したりします。

Gitは、ファイルをインデックスに追加する際にCRLF改行コードをLFに自動変換し、その逆にコードをファイルシステムにチェックアウトする際にLFをCRLFに変換することで、この問題に対処できます。この機能はcore.autocrlf設定で有効にできます。Windowsマシンを使用している場合、これをtrueに設定します。これにより、コードをチェックアウトする際にLF改行コードがCRLFに変換されます。

$ git config --global core.autocrlf true

LF改行コードを使用するLinuxまたはmacOSシステムを使用している場合、ファイルをチェックアウトする際にGitに自動変換させたくないでしょう。ただし、CRLF改行コードを持つファイルが誤って導入された場合は、Gitに修正させたいかもしれません。コミット時にCRLFをLFに変換し、その逆は行わないようにGitに指示するには、core.autocrlfinputに設定します。

$ git config --global core.autocrlf input

この設定により、WindowsでのチェックアウトではCRLF改行コードが、macOSおよびLinuxシステムではLF改行コードが、そしてリポジトリ内ではLF改行コードが維持されるはずです。

Windowsのみのプロジェクトを行うWindowsプログラマーの場合、この機能をオフにし、設定値をfalseにすることで、キャリッジリターンをリポジトリに記録できます。

$ git config --global core.autocrlf false

core.whitespace

Gitは、いくつかの空白文字の問題を検出して修正するようにプリセットされています。主に6つの空白文字の問題を検出できます。そのうち3つはデフォルトで有効になっており無効にでき、3つはデフォルトで無効になっていますが有効にできます。

デフォルトで有効になっている3つは、行末のスペースを探すblank-at-eol、ファイルの末尾の空行を検出するblank-at-eof、および行頭のタブの前のスペースを探すspace-before-tabです。

デフォルトで無効になっているが有効にできる3つは、タブの代わりにスペースで始まる行を探すindent-with-non-tabtabwidthオプションで制御されます)、行のインデント部分にあるタブを監視するtab-in-indent、および行末のキャリッジリターンが問題ないことをGitに伝えるcr-at-eolです。

core.whitespaceを、有効または無効にしたい値をコンマで区切って設定することで、Gitにどれを有効にしたいかを伝えることができます。オプションを無効にするには、その名前の前に-を付けます。または、設定文字列から完全に省略することでデフォルト値を使用できます。たとえば、space-before-tab以外のすべてを設定したい場合は、次のようにできます(trailing-spaceblank-at-eolblank-at-eofの両方をカバーする略称です)。

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

または、カスタマイズする部分のみを指定することもできます。

$ git config --global core.whitespace \
    -space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol

git diffコマンドを実行すると、Gitはこれらの問題を検出し、コミットする前に修正できるように色付けを試みます。また、git applyでパッチを適用する際にも、これらの値が役立ちます。パッチを適用する際、指定された空白文字の問題があるパッチを適用している場合に、Gitに警告するように要求できます。

$ git apply --whitespace=warn <patch>

または、Gitにパッチを適用する前に問題を自動的に修正させることができます。

$ git apply --whitespace=fix <patch>

これらのオプションは、git rebaseコマンドにも適用されます。空白文字の問題をコミットしたが、まだ upstream にプッシュしていない場合は、git rebase --whitespace=fixを実行することで、Gitがパッチを書き換える際に空白文字の問題を自動的に修正させることができます。

サーバー設定

Gitのサーバーサイドで利用できる設定オプションはそれほど多くありませんが、注目すべきいくつかの興味深いものがあります。

receive.fsckObjects

Gitは、プッシュ中に受信したすべてのオブジェクトがそのSHA-1チェックサムと一致し、有効なオブジェクトを指していることを確認できます。ただし、デフォルトではこれを行いません。これは非常に負荷の高い操作であり、特に大きなリポジトリやプッシュでは、操作が遅くなる可能性があります。プッシュごとにオブジェクトの一貫性をGitにチェックさせたい場合は、receive.fsckObjectsをtrueに設定することで強制できます。

$ git config --system receive.fsckObjects true

これで、各プッシュが受け入れられる前に、Gitがリポジトリの整合性をチェックし、不正な(または悪意のある)クライアントが破損したデータを導入していないことを確認します。

receive.denyNonFastForwards

すでにプッシュしたコミットをリベースしてから再度プッシュしようとしたり、リモートブランチが現在指しているコミットを含まないコミットをリモートブランチにプッシュしようとしたりすると、拒否されます。これは一般的に良いポリシーですが、リベースの場合、あなたが何をしているかを理解しており、プッシュコマンドに-fフラグを付けてリモートブランチを強制的に更新できると判断することもあるでしょう。

Gitに強制プッシュを拒否させるには、receive.denyNonFastForwardsを設定します。

$ git config --system receive.denyNonFastForwards true

これを行うもう1つの方法は、後ほど説明するサーバーサイドのreceiveフックを使用することです。このアプローチでは、特定のユーザーのサブセットに対して非fast-forwardを拒否するなど、より複雑なことを行うことができます。

receive.denyDeletes

denyNonFastForwardsポリシーの回避策の1つは、ユーザーがブランチを削除してから新しい参照で再度プッシュすることです。これを避けるには、receive.denyDeletesをtrueに設定します。

$ git config --system receive.denyDeletes true

これにより、ブランチやタグの削除がすべて拒否されます。どのユーザーも削除できません。リモートブランチを削除するには、サーバーからrefファイルを手動で削除する必要があります。また、Gitによる強制ポリシーの例で学ぶように、ACLを介してユーザーごとにこれを行うさらに興味深い方法もあります。

scroll-to-top