2026年6月8日
GitDeveloper ToolsProductivity

Git のデフォルト設定は、あなたの時間を無駄にしている

git が標準で切ってある日々の苛立ちを一掃する、11個のグローバル設定と20個のエイリアス(アップストリームブランチ、マージノイズ、アイデンティティの取り違え、繰り返すリベースコンフリクト)。

4 分で読めます

これは自分が全マシンで動かしている git 設定だ(11個のグローバル設定と20個のエイリアス)。どれも特定の日々の苛立ちを一つ潰すためにそこにある。全部持っていっていい。

少し前、あるチームメイトが自分が新しいブランチをプッシュするところを見て、こう止めた。

「待って、今のどうやってうまくいったの? --set-upstream なしで?」

設定1行の話だった。彼は何年もその場しのぎの回避策を打ち続けていた。

その会話が、この記事が存在する理由だ。ほとんどの開発者は git を工場出荷時の設定のまま動かしている。そして git の工場出荷時設定は、あなたのために設計されているわけではない。互換性のために設計されている。git は、一度驚かせるくらいなら千回中断させる方を選ぶ。

だから誰もが同じ日々の税金を、もうほとんど気づかないまま静かに払い続けている。

  • fatal: The current branch has no upstream branch、あまりに何度も打ったせいで、もう体が覚えている修正コマンド
  • 普通の pull がマージするせいで、マージコミットが履歴を汚染している
  • Mac の全プロジェクトの git status に .DS_Store が出てくる
  • 5回目の同じリベースコンフリクトを解決している
  • 会社のリポジトリに個人のメールアドレスでコミットしてしまう

これらはすべて、git が標準で出荷しているのに切ってある、たった1行の修正で直る。

git の工場出荷時設定という日々の税金(それぞれの苛立ちと、1行の修正)

以下は自分の実際の設定だ。どのマシンにも持ち歩くものだ。git がサポートするものを全部書き出したわけではない。ここにある行はすべて、実際の苛立ちを一つ潰すことでその場所を勝ち取っている。二幕構成にした。まずグローバル設定、git の挙動そのものを至るところで変えるから。次にエイリアス、それを運転する速度を変えるから。

🪪 第一幕:アイデンティティ(あなたを恥ずかしい目に遭わせかねない設定)

まずは結果を伴う設定から。

git config --global user.name "Paurush Rai"
git config --global user.email "personal@email.com"

当たり前のことだ。だがほとんどの開発者が設定していない部分がある。仕事用/個人用の自動振り分けだ。

自分は雇用主のコードを ~/Developer/company/ の下に置いている。~/.gitconfig の中の一つのブロックで済む。

[includeIf "gitdir:~/Developer/company/"]
    path = ~/.gitconfig-work

そして ~/.gitconfig-work にはこれだけが書いてある。

[user]
    email = work@company.com

リポジトリがどこにあるかによって git のアイデンティティを自動で振り分ける includeIf

これでアイデンティティはリポジトリがどこにあるかで決まる。company/ に何かをクローンすれば → 自動的に仕事用メール。それ以外はすべて → 個人用。覚える必要も、リポジトリごとの設定も、会社の監査ログに個人メールが載ることも、週末のサイドプロジェクトに仕事用メールが載ることもない。

(work ファイルにないものに注目してほしい。名前だ。includeIf はグローバル設定の上に重なるので、work ファイルは差分だけ、つまりメールアドレスだけを宣言する。それ以外はすべて継承される。)

これは見た目以上に重要だ。コミットのメールアドレスは永続的だから。間違ったアイデンティティでプッシュすれば、それは永遠に履歴に残る。GitHub はそのメールを所有しているアカウントにコミットを帰属させる。アイデンティティは、最後に何を打ち込んだか覚えていた結果ではなく、リポジトリの属性であるべきだ。

⚙️ 第一幕続き:挙動の設定

11行。それぞれが特定の、繰り返し起きる苛立ちを一つ潰す。

「no upstream branch」を二度と見ない

git config --global push.autoSetupRemote true

すべての開発者が暗記しているエラー(fatal: The current branch has no upstream branch)は、git が当たり前のことをする許可を求めるために存在している。この設定はその許可を恒久的に与える。新しいブランチの最初の push がそのまま通る。(これがチームメイトの話を止めさせた1行だ。)

意図しないマージコミットの発生を止める

git config --global pull.rebase true

デフォルトの git pull は fetch + merge だ。これが "Merge branch 'main' of github.com..." というコミットで履歴を壁紙のように埋め尽くす原因になる。これを設定すると、pull はローカルのコミットを、届いたものの上に再生する。線形な履歴、ノイズなし。

新しいリポジトリを main で始める

git config --global init.defaultBranch main

これがないと、git init のたびに master で始まり、後でリネームする羽目になる。1行で、もう二度と考えなくていい。

死んだブランチを溜め込むのをやめる

git config --global fetch.prune true

リモート上でブランチが削除されると(たいていはマージ済みの PR)、ローカルの origin/that-branch はいつまでも残り続ける。これは fetch のたびに古い参照を自動削除する。ブランチ一覧が常に正直な状態を保つ。

.DS_Store を全リポジトリから永遠に締め出す

git config --global core.excludesfile ~/.gitignore_global
echo ".DS_Store" > ~/.gitignore_global

グローバルな ignore ファイルは、各リポジトリ独自の .gitignore の上に重なって適用される。macOS のゴミファイルやエディタのスワップファイルを、プロジェクトごとではなくマシン全体で一度だけ処理できる。

コンフリクト解決の三位一体

git config --global merge.conflictstyle zdiff3
git config --global rerere.enabled true
git config --global rebase.autostash true

合わせてコンフリクト解決を一変させる3つの設定。

zdiff3 はコンフリクトマーカーに3つ目のセクションを追加する(両者が出発した元のテキストだ)。標準のマーカーは「自分」と「相手」しか見せず、意図を推測させる。共通の祖先が見えれば、推測が読解に変わる。

zdiff3 のコンフリクトマーカーが、両側と一緒に元の共通祖先を表示している様子

rerere(「reuse recorded resolution」)は、11個の中の隠れたヒット作だ。git は各コンフリクトをどう解決したかを記録し、同じコンフリクトが再び現れたとき(リベースは同じコンフリクトを繰り返すのが好きだ)、自動でその解決を再生する。5回目の同一コンフリクトは、勝手に解決される。

autostash は「cannot rebase: you have unstaged changes」という儀式を取り除く。git が作業内容をスタッシュし、リベースし、それを復元する。やっていたことはそのまま残る。

生活の質、2行

git config --global diff.algorithm histogram
git config --global branch.sort -committerdate

Histogram はデフォルトの Myers アルゴリズムより意味のある形できれいな diff を生成する。git が無関係な行同士を対にしてしまう、あの散らかったブロックが減る。そしてブランチを直近の活動でソートすることで、git branch は今実際に作業しているものを先頭に表示する。アルファベット順の考古学ではない。

⌨️ 第二幕:エイリアス

設定は git の挙動を変える。エイリアスはあなたの速度を変える。何を節約するかでグループ分けした、厳選の20個を持ち歩いている。

20個の git エイリアス、デイリードライバー・見通しの良さ・恐れずにやり直す・プロの一手の4グループに分類

デイリードライバー

st     = status -sb
cm     = commit -m
sw     = switch
co     = checkout
amend  = commit --amend --no-edit

status -sb については一言添える価値がある。2行のステータス表示だ。ブランチの状態と変更されたファイル、何年も前に読むのをやめたアドバイスの段落は抜き。

見通しの良さ

lg     = log --oneline --graph --decorate -20
last   = log -1 HEAD --stat
d      = diff
ds     = diff --staged
whoami = !echo "$(git config user.name) <$(git config user.email)>"

git lg は自分の「今どこにいる」確認用だ。20個のコミットをグラフとして描画する。そして git whoami は第一幕の話に決着をつける。どのリポジトリで実行しても、次のコミットに署名するアイデンティティがそのまま表示される。company/ の中では仕事用メール、それ以外では個人用。信頼を、1コマンドで検証できる。

恐れずにやり直す

unstage = restore --staged
undo    = reset --soft HEAD~1
wip     = !git add -A && git commit -m "wip: checkpoint"

undo は何も破壊せずにコミットを取り消す。変更はステージングに戻ってくる。wip は危険な手術の前にすべてをスナップショットする。git にまつわる不安のほとんどは、安全な戻り方を知らないことから来る。これらが、その安全な戻り方そのものだ。

プロの一手

pf      = push --force-with-lease
fixup   = commit --fixup
ri      = rebase -i --autosquash
cleanup = !git branch --merged | grep -vE "^\*|main|master" | xargs git branch -d

pf が重要な一つだ。--force-with-lease はリモートが自分が最後に見た状態のままであるときにだけ強制プッシュする。つまり、その間に届いたチームメイトの作業を物理的に上書きできない。生の --force の方が良い選択になる状況は存在しない。これをエイリアスにしておくことで、自分の指が危険な方を打つことは二度となくなる。

fixup と ri のペアは、履歴をきれいに保つワークフローだ。以前のコミットを狙い撃ちした修正コミットを作り、対話的リベース一発ですべてを自動的にたたみ込む。

🎯 恒久化するための部分

設定について、こういうことがある。作るのは簡単だ。維持することこそが本当の問題だ。今のマシンにしか存在しない設定は、次のマシンで記憶から組み立て直す羽目になる設定だ。

自分の ~/.gitconfig は単体のファイルではない。変化のたびに自動でコミットしてプッシュする dotfiles リポジトリへのシンボリックリンクだ。最近新しいエイリアスを追加したとき、バックグラウンドエージェントは自分がテストを終える前に、それを GitHub にコミットしていた。

(そのシステムは、シンボリックリンクと launchd エージェントだけで成り立ち、cron もサードパーティツールも使わない。それ自体が別の記事として書いた。)

その結果:このセットアップ全体、アイデンティティの振り分けと20個のエイリアスすべてが、たった一つの install.sh でどのマシンにも着地する。一度設定すれば、永遠に持ち続けられる。

📋 全部まとめて、コピペで使える版

# identity (edit these!)
git config --global user.name "Your Name"
git config --global user.email "you@personal.com"
 
# behavior
git config --global init.defaultBranch main
git config --global push.autoSetupRemote true
git config --global pull.rebase true
git config --global fetch.prune true
git config --global core.excludesfile ~/.gitignore_global
echo ".DS_Store" > ~/.gitignore_global
git config --global merge.conflictstyle zdiff3
git config --global rerere.enabled true
git config --global rebase.autostash true
git config --global diff.algorithm histogram
git config --global branch.sort -committerdate
 
# aliases
git config --global alias.st "status -sb"
git config --global alias.cm "commit -m"
git config --global alias.sw "switch"
git config --global alias.co "checkout"
git config --global alias.amend "commit --amend --no-edit"
git config --global alias.lg "log --oneline --graph --decorate -20"
git config --global alias.last "log -1 HEAD --stat"
git config --global alias.d "diff"
git config --global alias.ds "diff --staged"
git config --global alias.unstage "restore --staged"
git config --global alias.undo "reset --soft HEAD~1"
git config --global alias.wip '!git add -A && git commit -m "wip: checkpoint"'
git config --global alias.pf "push --force-with-lease"
git config --global alias.fixup "commit --fixup"
git config --global alias.ri "rebase -i --autosquash"
git config --global alias.cleanup '!git branch --merged | grep -vE "^\*|main|master" | xargs git branch -d'
git config --global alias.root "rev-parse --show-toplevel"
git config --global alias.aliases "config --get-regexp ^alias"
git config --global alias.whoami '!echo "$(git config user.name) <$(git config user.email)>"'

さらにアイデンティティの振り分けも、仕事用コードを専用のディレクトリに置いているなら。

git config --global includeIf."gitdir:~/Developer/company/".path ~/.gitconfig-work
printf '[user]\n    email = you@work.com\n' > ~/.gitconfig-work

教訓

これらの設定は、一つひとつを見れば大したものではない。それこそがポイントだ。

git のデフォルトは、誰も驚かせないことを最適化しており、その結果、全員を中断させる。上の各行は、繰り返し起きる中断一つを静寂に変える。そして静寂は積み重なる。あなたが触れることになるすべてのリポジトリで節約される数秒と、避けられる誤ったメールでのコミットを掛け合わせれば、この30分の設定は、ツールにかける時間の中でも屈指のレバレッジになる。

チームメイトは、push.autoSetupRemote を見たその日の午後に設定した。何年も打ち続けていた回避策が、たった1行で消えた。ただ、誰かがその税金を払わずに済んでいるのを見ることで、それが任意だったと気づく必要があっただけだ。

この記事を、文章になったその瞬間だと思ってほしい。cat ~/.gitconfig を実行して、そこに実際に何が入っているか見てみてほしい。

デフォルトは互換性のためにある。設定はあなたのためにある。

あなたの gitconfig には何が入っていますか?

自分はいつも次の1行修正を探している。もし場所を勝ち取った設定やエイリアスがあれば教えてほしい。自分の半分はそうやって見つけたものだ。