チャプター ▾ 第2版

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

これまで Git の基本的な動作と使い方について説明し、Git が提供する多くのツールを紹介してきました。この章では、いくつかの重要な設定とフックシステムを導入することで、Git をよりカスタマイズされた方法で操作する方法について説明します。これらのツールを使用すると、Git を自分自身、会社、またはグループが必要とする方法で正確に動作させることが容易になります。

Git の設定

はじめにで簡単に説明したように、Git の設定は git config コマンドで指定できます。最初に行ったことの 1 つは、名前とメールアドレスを設定することでした。

$ 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 ディレクトリ (.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 でも見つけることができます。

高度な使用例については、上記のドキュメントで「条件付きインクルード」を調べてください。

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

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) を使用して diff とマージ解決を行う方法を説明します。これは優れたグラフィカルツールであり、無料だからです。

試してみたい場合は、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 $*

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

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

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

$ git diff 32d1776b1^ 32d1776b1

コマンドラインに diff 出力が表示される代わりに、Git は P4Merge を起動します。それは次のように見えます。

P4Merge
図 168. P4Merge

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

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

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

これで、Git は diff の表示とマージの競合解決に 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 を diff に使用するのではなく、マージ解決にのみ使用したい場合で、かつ kdiff3 コマンドがパスに含まれている場合は、次を実行できます。

$ git config --global merge.tool kdiff3

extMerge および extDiff ファイルを設定する代わりにこれを実行すると、Git はマージ解決に KDiff3 を使用し、diff には通常の Git diff ツールを使用します。

書式設定と空白

書式設定と空白の問題は、特にクロスプラットフォームでのコラボレーションにおいて、多くの開発者が遭遇する最もイライラする微妙な問題のいくつかです。エディターがサイレントに空白の変更を導入するため、パッチやその他の共同作業で微妙な空白の変更が導入されるのは非常に簡単です。また、ファイルが Windows システムに触れると、行末が置換される可能性があります。Git には、これらの問題を解決するのに役立ついくつかの設定オプションがあります。

core.autocrlf

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

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

$ git config --global core.autocrlf true

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

$ git config --global core.autocrlf input

この設定により、Windows のチェックアウトでは CRLF 行末が残り、macOS および Linux システムとリポジトリでは 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-tab (tabwidth オプションで制御されます)、行のインデント部分のタブを監視する 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 は git diff コマンドを実行したときにこれらの問題を検出し、色付けを試みるため、コミットする前に修正できる可能性があります。また、これらの値を使用して、git apply でパッチを適用するときに役立ちます。パッチを適用するときに、指定された空白の問題を含むパッチを適用している場合に警告するように Git に要求できます。

$ git apply --whitespace=warn <patch>

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

$ git apply --whitespace=fix <patch>

これらのオプションは、git rebase コマンドにも適用されます。空白の問題をコミットしたが、まだアップストリームにプッシュしていない場合は、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

これを行うもう一つの方法は、後で説明するサーバーサイドの受信フックを使用することです。このアプローチでは、特定のユーザーのサブセットへの非ファストフォワードを拒否するなど、より複雑なことを行うことができます。

receive.denyDeletes

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

$ git config --system receive.denyDeletes true

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

scroll-to-top