pull.rebaseとrebase.autoStashの設定:Gitログを一直線に保ち、作業中コードの紛失を防ぐ

Git tutorial - IT technology blog
Git tutorial - IT technology blog

コード取得時にGitが実行する2つの処理方式

スプリントタスクで3つのファイルを編集している最中に、同僚からmainへホットフィックスをpushしたと連絡があったとします。すぐにそのパッチを取り込む必要があります。よく使うコマンドはgit pullですが、このコマンドの裏側で、Gitにはソースコードを統合するための全く異なる2つの仕組みが存在します。

1. デフォルトのGit Pull(マージ戦略)

デフォルトでは、ローカルに新しいコミットが存在する場合、git pullは中間コミットであるマージコミットを自動生成します。例えば、Merge branch 'main' of github.com:...のようなコミットです。

6〜8人ほどの開発チームで頻繁にコードをpushしていると、わずか1週間でgit log --graphはクモの巣のように入り組んだ状態になってしまいます。コミット履歴は激しく断片化し、バグ調査のためにgit bisectを使おうとしても、不要な枝分かれをいくつも辿らなければならず、調査に2倍の時間がかかってしまいます。

2. Rebaseフラグ付きのGit Pull

git pull --rebaseは異なるアプローチをとります。つまり、タイムラインを並び替えるアプローチです。

Gitはまずローカルのコミットを一時的に脇へ退避させます。次に、リモートの最新コミットをすべて先に取得します。最後に、退避させていたコミットをそのブランチの先頭に1つずつ積み直します。これにより、プロジェクトの履歴はきれいな直線(リニアヒストリー)を保ち、誰が見ても機能の開発順序が一目瞭然になります。

最大の難所:書きかけのコード(Dirty Working Tree)

問題は、pullする前にコミットすることは稀だという点です。大抵の場合、ローカルにはテスト用の書きかけコードが残っています。

未コミットの変更がある状態でgit pull --rebaseを実行すると、即座に処理が中断され、“error: cannot rebase: You have unstaged changes”というエラーが発生します。この場合、手動で行う手順はかなり面倒です。

  1. git stashを実行してコードを一時退避する。
  2. git pull --rebaseを実行して最新コードを取得する。
  3. git stash popを実行して作業中のコードを復元する。

ステップ3をうっかり忘れると、コードが全部消えてしまったのかと青ざめることになります。

各ソリューションの直接比較

よくある3つのアプローチを比較したものが以下になります:

  • デフォルトのpullをそのまま使用:使いやすく、コミットハッシュを書き換えないため初学者にも安全です。ただし、不要なマージコミットが大量に発生し(1スプリントあたり平均15〜30個の不要コミット)、リポジトリの履歴を濁らせてしまうデメリットがあります。
  • 手動でpull –rebaseを実行:コミットツリーをクリーンかつ一直線に保てます。しかし、stash > pull > popという3つのコマンドを毎回実行するのは手間で、急いでいる時に手順を抜かしやすくなります。
  • pull.rebaseとrebase.autoStashの併用:100%自動化されます。実行するコマンドはgit pullひとつだけです。Gitが自動的に作業中の変更を退避し、ブランチをrebaseした上で、コードを安全に復元してくれます。

チームへの実践的な導入経験

私が以前参加していた10人規模のFintechプロジェクトでは、クロスしたマージコミットに起因するコンフリクトの解消のためだけに、リリース直前に約3時間も費やしたことがありました。過去のコードが、レビュー済みの新しいコードを誤って上書きしてしまう事故も発生していました。

チーム全体でautoStash付きのrebase設定を有効にすることをルール化してからは、このような問題は一切なくなりました。コンフリクトの発生頻度は目に見えて減少し、Gitログのグラフが常に一直線になったことで、リードによるPRのレビューやリリースブランチへのcherry-pickが非常にスムーズになりました。

この設定は、特に次のような方に適しています:

  • アジャイル/スクラム体制で開発しており、機能ブランチを頻繁にdevelopへrebaseする方。
  • CI/CDでConventional Commitsに基づくチェンジログを自動生成するために、明瞭なログを維持したい方。
  • 作業効率を上げ、日々の手動stash作業から解放されたい方。

詳細な設定手順

ターミナルを開き、以下の2つのコマンドを実行するだけです。この設定は初回に一度実行するだけで完了します。

マシン全体に適用する設定(グローバル設定 – 推奨)

# 1. git pullのデフォルト動作をrebaseに設定
git config --global pull.rebase true

# 2. rebase前に自動でstashし、完了後に自動で復元
git config --global rebase.autoStash true

特定プロジェクトのみに適用する設定(ローカル設定)

会社のリポジトリのポリシーでマージコミットを維持することが義務付けられている場合は、個人のプロジェクトに対してローカルでのみ適用してください:

cd /path/to/my-project
git config pull.rebase true
git config rebase.autoStash true

設定内容の確認

設定がGitに正しく反映されているか確認するには、次のコマンドを実行します:

git config --global --get-regexp "pull|rebase"

画面に以下のように出力されれば設定完了です:

pull.rebase true
rebase.autostash true

ターミナル上での実際の挙動

設定後、例えばservices/auth.goを編集したままコミットしていない状態を想定します。リモートに最新の変更が入った際も、実行するコマンドはこれだけです:

git pull

Gitがバックグラウンドですべての工程を自動処理してくれます:

Created autostash: 8f2c1b4
First, rewinding head to replay your work on top of it...
Fast-forwarded main to origin/main.
Applying autostash: 8f2c1b4
Applied autostash.

auth.goファイルは編集途中の状態がそのまま保持されます。リモートの新しいコミットもすべてスムーズに取り込まれ、コミット履歴は不要なマージコミットを1つも挟むことなく、すっきりと一直線の状態を維持できます。

Share: