📙

【Git】Gitは管理下のファイルの面倒は見てくれるけど、データベースもストレージも依存関係も仕様も見ちゃいない

に公開

はじめに

https://zenn.dev/noranuko13/articles/b30c8ed65e8e27

対象

  • Gitのブランチを変更したときに、環境差分や不整合でハマりがちなITエンジニア向け。
    • 特にフレームワークを用いてWebアプリを作る開発者向け。

Gitの守備範囲

バージョン管理下にあるファイル

Gitはファイルの内容と操作履歴を記録・管理するツールです。

.gitignoreに指定のあるディレクトリやファイルは除外されてしまいます。アプリケーションが動いている環境や外部サービスの状態などなど、実はGitが知らないことの方がずっと多いです。

  • Gitブランチの切替 = ファイルの変更 ≠ 開発環境の状態の変更

変更の意味と実行結果は知らない

Gitは「管理下にあるファイルがどのように変更されたか」は把握していますが、「何のためのファイルで、何をするのか」は把握していません。ソースコードの意味を解釈するのは読んだ人間で、テキストファイルを元にプログラムを動かすと得られるのが実行結果です。

この認識のズレが「ブランチを切り替えたら動かない」という事象を引き起こします。例えばWebアプリの設定ファイルを変更したとして、再起動しないと反映されないという現象はGitの守備範囲外の話です。

Gitはブランチを切り替えることで、ファイルを対象のバージョンと同じ状態に変更してくれますが、その変更が持つ意図や副作用までは理解していません。

これは何にでも言えることですが、ツールを使う際は用途や性質を正しく理解し、その道具が本来達成しようとしている目的に合わせて使用しましょう。Gitはファイルのバージョン管理をしているだけです。それ以外は知ったこっちゃないのです。

Gitの守備範囲外

今回は主要なポイントを3点取り上げます。これら以外にも、

  • アプリケーションが初回起動時に読み込む設定。
  • アプリケーションの業務仕様。

など、ハマりポイントはいくつかあります。

データベースのマイグレーション

大規模Webフレームワークであればマイグレーション機能が用意されているものがほとんどです。専用のコマンドでマイグレーションファイルを作成し、データベースに対する変更をコードとして記述し、コマンドを実行することでデータベースに反映します。

https://railsguides.jp/active_record_migrations.html

つまりコマンドを実行しなければ反映されません。

featureブランチでマイグレーションファイルを作成し、開発環境のデータベースに適用したものとします。git switch mainでブランチを切り替えても、データベースが勝手に整合性の取れた状態に戻る訳ではありません。

削除したマイグレーションファイルの後に********** NO FILE **********と表示されるでしょう。これは、そのマイグレーションファイルが特定の環境で一度実行されたが、db/migrate/ディレクトリの下に見当たらない場合に表示されます。
9 古いマイグレーション

この場合、まずfeatureブランチで適用したマイグレーションをロールバックし、ブランチの分岐点のマイグレーションファイルとデータベースとの整合性を取る必要があります。

また検証環境のデータをdumpして投入しているプロジェクトでは、検証環境と同じリビジョンからの差分で考える必要があります。

パッケージの依存関係

パッケージマネージャーはマニフェストファイルとlockファイルをGitの管理下に置き、各環境でツールを用いて依存関係をインストール・解決します。

例えばnpmでは、package.jsonpackage-lock.jsonです。

https://docs.npmjs.com/cli/v11/configuring-npm/package-json

https://docs.npmjs.com/cli/v11/configuring-npm/package-lock-json

npm installnpm ciなどのコマンドを実行すると、node_modulesディレクトリが作成され、各種パッケージがインストールされます。

マイグレーションのときと原理は同じです。これらのファイルに変更がある場合、ブランチを切り替えただけではインストールされているパッケージは変更されません。そのまま実行しようとすると、多くの場合は警告やエラーを出して停止するでしょう。

またブランチのマージやリベースによってlockファイルに競合が起きたケースを考えてみましょう。Gitの競合を解決するという操作は、単にテキストファイルの差分を見て、どちらの変更を優先するか決めているだけです。依存関係グラフや実行環境全体の整合性までは見ていません。

パッケージマネージャーにしてみれば、Gitによる修正も手作業での修正も、npmの守備範囲外での変更になってしまいます。この場合は一旦変更を破棄し、再度同じコマンドを用いて依存関係の調整を行います。

ファイルストレージ

具体的にはS3やローカルの一時ファイルなどです。S3は外部サービスですし、一時ディレクトリはよく.gitignoreで管理外になっています。これらはGitでは管理されませんし、されるべきでもありません。

そして保存データの詳細はデータベースに保存されていることが多いでしょう。このため部分的な開発環境の作り直しや、一時ディレクトリの削除をしたときに、

  • データベースにレコードが存在しないのに、画像がストレージに保存されている。
  • データベースにレコードが存在するのに、画像がストレージに存在しない。

といった不整合が発生することがあります。

更にデータベースから取得した情報を元にファイルパスを生成していて、その部分のソースコードを改修した場合はどうなるでしょうか。過去データも含めたストレージのファイルの場所も全て対象のバージョンと同じ仕様に揃えないと、正しい状態で表示されなくなります。

よくある表示異常が「開発環境で画像が表示されない」というものです。容量が大きすぎるために意図的に、シードデータに画像が用意されていないことはあります。賛否両論あるかもしれませんが、ドキュメントや事前説明があれば問題ない範囲の運用だと思います。

おわりに

Gitを使うのに手一杯になっているだけで、少し冷静になって考えれば自分で気付けることかもしれません。Webフレームワーク初心者のうちは結構やらかしがちです。

最悪、開発環境構築をし直せばいいのですが、製品によっては5分10分かかるものもあるでしょう。原因を調査するにしても、本記事のような知識を持っていないと、見当違いの対処をしてしまったりします。それでまた30分溶かすのもしんどいです。

もしプルリクを出せるようになって、業務のコードを触るようになった新米エンジニアの方がいらっしゃいましたら、そうなる前にこの記事を共有していただけると捗るのではないかと思います。

Discussion