Git
目次 ▾ 第2版

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

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

Git の設定

はじめに」で簡単に説明したように、`git config` コマンドを使用して Git の設定を指定できます。最初に行った操作の 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

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

例えば、~/.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

この設定は、logdiffなどのGit出力ページャーを決定します。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(下線)、blinkreverse(前景と背景の入れ替え)から選択できます。

外部マージとdiffツール

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 $*

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

これで、カスタムのマージ解決とdiffツールを使用するように構成ファイルを設定できます。これには、使用する戦略をGitに指示するmerge.tool、コマンドの実行方法を指定するmergetool.<tool>.cmd、そのプログラムの終了コードが成功したマージ解決を示すかどうかをGitに指示するmergetool.<tool>.trustExitCode、diffの実行コマンドをGitに指示するdiff.externalなど、多数のカスタム設定が必要です。そのため、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ツールとマージツールを簡単に変更できることです。たとえば、extDiffextMergeツールを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.

diffにKDiff3を使用するのではなく、マージ解決のみに使用したい場合、およびkdiff3コマンドがパスにある場合は、次を実行できます。

$ git config --global merge.tool kdiff3

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

フォーマットと空白

フォーマットと空白の問題は、特にクロスプラットフォームでのコラボレーション時に、多くの開発者が遭遇する、最もイライラする微妙な問題の1つです。パッチやその他のコラボレーション作業で微妙な空白の変更が導入されることは非常に簡単です。これは、エディタがそれらを黙って導入し、ファイルがWindowsシステムに触れた場合、改行が置き換えられる可能性があるためです。Gitには、これらの問題に対処するためのいくつかの構成オプションがあります。

core.autocrlf

Windowsでプログラミングしていて、そうでない人と協力している場合(またはその逆)、いつか改行の問題に遭遇する可能性があります。これは、Windowsがファイルの改行にキャリッジリターン文字とラインフィード文字の両方を使用するのに対し、macOSとLinuxシステムはラインフィード文字のみを使用するためです。これは、クロスプラットフォーム作業の微妙だが非常に厄介な事実です。Windowsの多くのエディタは、既存のLFスタイルの改行をCRLFに置き換えたり、ユーザーがEnterキーを押したときに改行文字を挿入したりします。

Gitは、ファイルをインデックスに追加するときにCRLF改行をLFに変換し、コードをファイルシステムにチェックアウトするときにその逆を行うことで、これに対処できます。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改行が残るはずです。

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、行末のキャリッジリターンがOKであることをGitに指示するcr-at-eolです。

有効にするものをGitに指示するには、core.whitespaceをオンまたはオフにしたい値に設定し、コンマで区切ります。オプションを無効にするには、名前の前に-を付けるか、設定文字列から完全に削除してデフォルト値を使用します。たとえば、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コマンドにも適用されます。空白に関する問題をコミットしたが、まだアップストリームにプッシュしていない場合は、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ファイルを手動で削除する必要があります。ACLを使用して、ユーザーごとにこれを行うより興味深い方法もあります。詳しくはGitによるポリシー強制の例を参照してください。

scroll-to-top