【ITニュース解説】Lab 3: OSD600
2025年09月27日に「Dev.to」が公開したITニュース「Lab 3: OSD600」について初心者にもわかりやすく解説しています。
ITニュース概要
プログラムに詳細表示と行番号の2つの新機能を追加した。それぞれ別ブランチで開発し、メインブランチにマージ。マージ時に競合が発生したが、手動で解決し、Gitを使った複数機能の並行開発や、マージ衝突解決のプロセスを実践的に学べた。
ITニュース解説
システム開発では、複数の機能を同時に開発したり、チームで協力して作業を進めたりする際に、バージョン管理システムは不可欠なツールとなる。特に「Git」は、その中心的な役割を果たす。今回の作業では、「ContextWeaver」という自身のプロジェクトで、具体的な新機能追加を通してGitのワークフローを実践した。目的は、開発の進捗をユーザーに可視化する「冗長モード」と、ファイルの出力内容に行番号を付与する「行番号モード」という二つの機能を追加することだった。これらの機能は、別々に開発され、最終的にメインのコードに統合されるまでの過程で、Gitの様々な機能が活用された。
新しい機能を追加する際、既存の安定したコード(通常は「メインブランチ」と呼ばれる)に直接変更を加えるのはリスクが高い。もし開発中の機能に問題があった場合、メインブランチ全体が不安定になってしまう可能性があるからだ。そこで、Gitでは「ブランチ」という仕組みを利用する。ブランチは、メインのコードから分岐した作業領域のことで、それぞれの新機能は独立した「トピックブランチ」で開発された。 具体的には、まず「冗長モード」のためのブランチを作成し、そのブランチ上で機能の実装を進めた。この機能は、プログラムがファイルをスキャンしたり読み込んだりする際に、「ディレクトリを処理中…」や「ファイルを読み込み中…」といった進捗メッセージを画面に出力する。これにより、ユーザーはプログラムが何をしているのかをリアルタイムで把握できるようになった。 同様に、「行番号モード」のためにも別のブランチを作成し、この機能の実装を行った。このモードでは、ファイルの内容を出力する際に、各行の先頭に1から始まる行番号を自動で追加する。これは、特にコードレビューやデバッグの際に、特定の行を参照しやすくするために非常に有効な機能である。 それぞれの機能は、実装が完了するたびに「コミット」と呼ばれる形で変更履歴として記録された。コミットメッセージには、その変更が何を行ったのかを明確に記述し、その後、GitHubというオンラインのリポジトリに「プッシュ」して、開発内容を共有・保存した。
二つの機能がそれぞれ独立したブランチで完成した後、これらの新機能をメインのコードベースに統合する作業、つまり「マージ」の段階に入った。マージを行う前に、まずは自分の作業環境にあるメインブランチが、GitHub上の最新のメインブランチと完全に同じ状態であることを確認した。これは、他の誰かがメインブランチに変更を加えている可能性があるため、自分の作業が古くならないようにするための重要な手順である。 最初に「冗長モード」のブランチをメインブランチにマージした。この際、メインブランチにはそれ以降新しい変更が加えられていなかったため、Gitは「ファストフォワードマージ」という形式で統合を行った。ファストフォワードマージは、メインブランチがまるでそのトピックブランチの先に進んだかのように、単純に履歴を一直線につなぎ合わせる非常にシンプルなマージ方法だ。 次に「行番号モード」のブランチをマージしようとした。しかし、このマージはファストフォワードマージのようにはいかなかった。なぜなら、「冗長モード」の機能と「行番号モード」の機能、どちらもプログラムのコマンドラインオプションを定義する「src/main.py」という同じファイルを変更していたため、Gitが自動で変更を結合することができなかったのだ。このように、複数のブランチが同じファイルの同じ箇所を変更している場合に、Gitは「マージコンフリクト」と呼ばれる衝突を検出する。
マージコンフリクトが発生すると、Gitはどの変更を採用すべきか判断できないため、開発者に手動での解決を求める。今回のケースでは、コマンドラインオプションを定義する「argparse」という部分で衝突が起きた。マージコンフリクトが発生したファイルを開くと、Gitが衝突箇所を特殊なマーカーで示してくれる。開発者は、そのマーカーを参考に、どちらの変更を残すか、あるいは両方の変更をどのように組み合わせるかを慎重に判断し、ファイルを直接編集して問題を解決する必要がある。今回の場合は、冗長モードのオプションも、行番号モードのオプションも両方とも必要な機能だったため、両方のオプション定義が適切に共存できるようにコードを手動で修正した。コンフリクトが解決され、ファイルが保存された後、その変更を再びコミットすることで、マージプロセスを完了させることができた。
開発の過程では、マージコンフリクト以外にもう一つ課題に直面した。それは、ローカルで行った変更をGitHubにプッシュしようとした際に、プッシュが拒否されるという問題だ。これは、自分のローカル環境にあるメインブランチが、GitHub上にあるリモートのメインブランチよりも古い状態(つまり、「遅れている」状態)であるときに発生する。Gitは、古いコードの上に新しい変更を直接プッシュすることを安全上の理由から拒否するのだ。 この問題を解決するために、「リベース」というGitの機能を利用した。リベースは、自分の行なった変更の履歴を、最新のリモートブランチの先頭に「載せ替え」る操作である。これにより、自分の変更がリモートの最新の変更の上にきれいに適用され、履歴が一直線になるため、その後のプッシュがスムーズに行えるようになった。これらの問題に直面し、一つ一つ解決していくことで、Gitの実際のワークフローにおける実践的な経験を積むことができた。
今回の作業を通して、並行して複数のブランチを管理することの重要性と、それが機能開発の分離にどれほど役立つかを実感した。また、メインブランチに新しい変更がない場合に発生する「ファストフォワードマージ」と、履歴が分岐していて変更が衝突する可能性のある場合に必要となる「スリーウェイリカーシブマージ」(手動解決が必要なコンフリクトが発生する可能性のあるマージ)という、異なる種類のマージがあることを学んだ。マージコンフリクトの際には、機能が失われないように細心の注意を払って変更を結合する技術も身につけることができた。そして何よりも、複数の機能をマージした後には、それらが期待通りに連携して動作するかどうかを必ずテストすることの重要性を再認識した。 もし次回同じような作業を行う機会があれば、いくつか改善したい点がある。一つは、各機能ブランチをマージする前に、必ず最新のメインブランチの上に「リベース」することだ。これにより、マージコンフリクトの発生確率を減らし、よりクリーンなマージを実現できるだろう。また、一度に大きな変更を加えるのではなく、より細かく頻繁にコミットを行うことで、変更履歴が追いやすくなり、万が一コンフリクトが発生した場合でも、その解決が容易になるはずだ。さらに、複数の機能が組み合わさった際の動作を、開発ワークフローの早い段階でテストすることで、問題が大きくなる前に発見し、対処できるようになるだろう。
最終的に、開発した「冗長モード」と「行番号モード」の両機能は、メインブランチ上で期待通りに動作するようになった。例えば、python3 -m src.main . -Vとコマンドを実行すれば冗長モードが有効になり、python3 -m src.main . -lと実行すれば行番号が付与されたファイル内容が出力される。これらのフラグは同時に使用することも可能で、その場合は進捗メッセージが表示されつつ、行番号付きのファイル内容が出力される。プロジェクトの「README.md」ファイルも、これらの新しい機能の使い方を示す使用例で更新され、関連する二つの課題は、マージコミットへのリンクとともにクローズされた。この一連の作業は、並行してブランチを開発し、それらを安定したメインブランチに統合するという、実際のソフトウェア開発における貴重な実践経験を与えてくれた。