Git/GitHub
この講座では、バージョン管理システムであるGitと、GitのホスティングサービスであるGitHubについて学びます。
- バージョン管理の必要性と基本概念
- Gitの基本操作(init、add、commit、status、log、diff)
- ブランチの作成・切り替え・マージ
- ブランチ戦略(Git Flow、GitHub Flow、トランクベース開発)
- GitHubを使ったリモートリポジトリの操作
- プルリクエストとコードレビューの文化
.gitignoreによるセキュリティ対策- コミットメッセージのベストプラクティス
1. バージョン管理とは
1.1 なぜバージョン管理が必要なのか
ソフトウェア開発では、コードの変更を日々繰り返します。バージョン管理がない場合、以下のような問題が発生します。
- 「昨日まで動いていたコードが動かなくなった」→ どの変更が原因かわからない
- 「本番環境のコードがどのバージョンかわからない」→ 障害対応ができない
- 「複数人で同じファイルを編集したら片方の変更が消えた」→ 作業のやり直し
バージョン管理システム(VCS: Version Control System)は、ファイルの変更履歴を記録・管理するシステムです。「いつ、誰が、何を、なぜ変更したか」を記録することで、上記の問題を解決します。
| 💡 ポイント |
|---|
| ソフトウェア開発において、バージョン管理はすべての基盤です。チーム開発ではGitリポジトリを中心にコードを共有・管理し、変更履歴を追跡することで品質を維持します。バージョン管理を理解することは、開発者としての第一歩です。 |
| 💡 ポイント |
|---|
| バージョン管理はソフトウェア開発だけのものではありません。インフラ領域でも、Dockerfileやdocker-compose.ymlの管理、Terraformによるインフラ構成のコード管理(Infrastructure as Code)、サーバの設定ファイルやCI/CDパイプラインの定義など、さまざまな場面で活用されています。コードとして管理することで「いつ、誰が、どの設定を変更したか」を追跡でき、障害時の原因調査や環境の再構築が容易になります。 |
1.2 バージョン管理システムの種類
バージョン管理システムには、大きく分けて集中型と分散型の2種類があります。
集中型
集中型のバージョン管理システムは、1つの中央サーバにすべての変更履歴を保存し、開発者はそのサーバに接続して作業を行います。代表的なツールとしてSVN(Subversion)があります。仕組みがシンプルでわかりやすい反面、中央サーバに接続できない環境ではコミットや履歴の確認ができないという制約があります。現在でも一部のプロジェクトや組織で利用されていますが、後述する分散型の普及に伴い、新規に採用されるケースは少なくなっています。
分散型
分散型のバージョン管理システムは、各開発者のローカル環境に変更履歴の完全なコピーを持ちます。代表的なツールがGitです。サーバに接続しなくてもコミットや履歴の確認ができるため、オフライン環境でも作業を継続できます。また、中央サーバに障害が発生しても、各開発者のローカルに完全な履歴が残っているため、復旧が容易です。
現在のソフトウェア開発では、分散型のGitが事実上の標準です。
| 💡 ポイント |
|---|
| ファイルサーバ上で「report_20250115.py」「report_最新版.py」のようにファイル名に日付やバージョンを付けて管理する方法や、Google DriveやDropboxなどのクラウドストレージの履歴機能を使う方法もあります。しかし、これらの方法では「どの変更が何の目的で行われたか」を記録できず、複数人が同時に編集した場合の競合解決も困難です。バージョン管理システムを使うことで、変更の意図をコミットメッセージとして記録でき、複数人の同時編集も安全に統合できます。 |
2. Gitの概要
2.1 Gitとは
Gitは、Linus Torvalds氏(Linuxの開発者)が2005年に開発した分散型バージョン管理システムです。Gitには、以下のような特徴があります。
まず、ほとんどの操作がローカルで完結するため、非常に高速に動作します。コミットや履歴の確認、差分の比較といった日常的な操作は、ネットワークに接続しなくてもローカル環境だけで実行できます。そのため、リモートサーバとの通信が必要な集中型のシステムと比べて、操作のレスポンスが格段に速いのが特徴です。
次に、各開発者がリポジトリの完全なコピーをローカルに持つ分散型の仕組みを採用しています。これにより、サーバに障害が発生してもローカルに完全な履歴が残っているため、作業を中断することなく継続でき、復旧も容易です。
さらに、開発の流れを分岐させる「ブランチ」という仕組みの操作が非常に軽量です。ブランチについては後ほど詳しく説明しますが、Gitではこの分岐の作成や切り替え、統合といった操作を高速かつ手軽に行えるため、効率的な開発ワークフローを実践できます。
2.2 Gitの基本概念
Gitを使いこなすために、以下の基本概念を理解しておきましょう。
リポジトリ
リポジトリ(Repository)は、ファイルの変更履歴を保存する場所です。プロジェクトのフォルダでgit initコマンドを実行すると、フォルダ内に.gitという隠しディレクトリが作成され、そのフォルダがGitリポジトリになります。.gitディレクトリの中に、すべてのコミット履歴やブランチの情報が保存されています。
コミット
コミット(Commit)は、ファイルの変更を履歴として記録する操作です。コミットを行うと、その時点のファイルの状態がスナップショットとして保存されます。各コミットには一意のID(ハッシュ値)が付与され、「いつ、誰が、何を変更したか」をメッセージとともに記録できます。この履歴をたどることで、過去の任意の時点の状態に戻ることも可能です。
ブランチ
ブランチ(Branch)は、開発の流れを分岐させる仕組みです。メインの開発ライン(mainブランチ)から新しいブランチを作成することで、メインのコードに影響を与えずに新機能の開発やバグ修正を進められます。作業が完了したら、変更をメインのブランチに統合(マージ)します。
マージ
マージ(Merge)は、分岐したブランチの変更を別のブランチに統合する操作です。たとえば、新機能を開発していたブランチの変更をmainブランチに取り込む場合にマージを使います。Gitはそれぞれのブランチで行われた変更を自動的に統合しますが、同じ箇所を異なる内容で変更していた場合は「コンフリクト(競合)」が発生し、手動での解決が必要になります。
2.3 Gitの3つのエリア
Gitでは、ファイルは以下の3つのエリアを移動します。この流れを理解することがGit操作の基本です。
┌─────────────┐ git add ┌──────────────────┐ git commit ┌─────────────────┐
│ ワーキング │ ──────────────→ │ ステージング │ ──────────────→ │ ローカル │
│ ディレクトリ │ │ エリア │ │ リポジトリ │
│ │ │ (コミット待ち) │ │ (履歴として保存) │
└─────────────┘ └──────────────────┘ └─────────────────┘
ワーキングディレクトリ
ワーキングディレクトリは、実際にファイルを編集する作業場所です。普段コードを書いたり修正したりしているプロジェクトのフォルダそのものがワーキングディレクトリにあたります。ここで行った変更は、まだGitには記録されていない状態です。変更をGitに記録するには、次のステージングエリアを経由してコミットする必要があります。
ステージングエリア
ステージングエリアは、次のコミットに含める変更を一時的に登録する場所です。ワーキングディレクトリで変更したファイルをgit addコマンドでステージングエリアに追加することで、「この変更をコミットに含める」という意思表示をします。ステージングエリアがあることで、変更した複数のファイルのうち「今回コミットしたいファイルだけ」を選んでコミットできます。たとえば、バグ修正と新機能の実装を同時に行った場合、それぞれを別のコミットとして記録することで、変更履歴をわかりやすく保てます。
ローカルリポジトリ
ローカルリポジトリは、git commitによって確定された変更履歴が保存される場所です。ステージングエリアに登録された変更をコミットすると、その時点のファイルの状態がスナップショットとしてローカルリポジトリに記録されます。コミットされた変更はここに蓄積されていくため、過去の任意の時点の状態を確認したり、その状態に戻したりすることができます。
3. Gitの基本操作
続いて、Gitの基本操作の方法をみていきましょう。次のGit/GitHubでコード管理しようでハンズオンを用意しているので、ここではまずイメージを掴んでもらえれば大丈夫です。
リポジトリの初期化(git init)
プロジェクトのフォルダをGitリポジトリとして初期化します。
git init
このコマンドを実行すると、フォルダ内に.gitという隠しディレクトリが作成され、Gitによるバージョン管理が開始されます。
変更のステージング(git add)
ファイルの変更をステージングエリアに追加します。
特定のファイルをステージングする場合は、以下のようにファイル名を指定します。
git add ファイル名
すべての変更をステージングする場合は、以下のコマンドを使用します。
git add .
| 💡 ポイント |
|---|
git add .はカレントディレクトリ以下のすべての変更をステージングします。意図しないファイル(パスワードを含む設定ファイルなど)をコミットしてしまう危険があるため、git statusで対象ファイルを確認してから実行する習慣をつけましょう。 |
変更のコミット(git commit)
ステージングした変更を履歴として記録します。
git commit -m "コミットメッセージ"
-mオプションの後に、変更内容を説明するメッセージを記述します。コミットメッセージの書き方については後のセクションで詳しく説明します。
コミットを実行すると、ステージングエリアに登録されていた変更がローカルリポジトリに記録され、正式な変更履歴の一部になります。つまり、git addの段階ではまだ「コミットの候補」として準備しているだけであり、git commitを実行して初めて変更がGitの履歴管理の対象として確定します。
状態の確認(git status)
ワーキングディレクトリとステージングエリアの状態を確認します。
git status
以下のような情報が表示されます。
On branch main
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: app.py
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
modified: config.yaml
Untracked files:
(use "git add <file>..." to include in what will be committed)
new_file.txt
Changes to be committed は、git addによってステージングエリアに登録済みの変更です。この状態のファイルは、次にgit commitを実行するとローカルリポジトリに記録されます。
Changes not staged for commit は、ファイルに変更が加えられているものの、まだgit addでステージングされていない状態です。このままではgit commitを実行してもコミットの対象にはなりません。コミットに含めるには、先にgit addでステージングする必要があります。
Untracked files は、Gitでまだ一度も管理されたことがない新しいファイルです。新しく作成したファイルは最初この状態になります。git addでステージングすることで、Gitの管理対象に加えることができます。
履歴の確認(git log)
コミット履歴を確認します。
git log
以下のように、各コミットの詳細情報(コミットID、作成者、日時、メッセージ)が表示されます。
commit 3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b
Author: yamada <yamada@example.com>
Date: Fri Feb 28 10:30:00 2026 +0900
ユーザ入力のバリデーションを追加
commit 9e8d7c6b5a4f3e2d1c0b9a8f7e6d5c4b3a2f1e0d
Author: yamada <yamada@example.com>
Date: Thu Feb 27 15:00:00 2026 +0900
設定ファイルのパスを修正
commit 1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b
Author: yamada <yamada@example.com>
Date: Wed Feb 26 09:00:00 2026 +0900
初期コミット
コンパクトな表示にする場合は、--onelineオプションを使用します。
git log --oneline
以下のように、コミットIDの先頭7文字とメッセージが1行ずつ表示されます。
3a4b5c6 ユーザ入力のバリデーションを追加
9e8d7c6 設定ファイルのパスを修正
1a2b3c4 初期コミット
差分の確認(git diff)
ファイルの変更内容を確認します。
ワーキングディレクトリの変更(ステージングされていない変更)を表示します。
git diff
たとえば、app.pyのprint("Hello")をprint("Hello, World!")に変更した場合、以下のように表示されます。
diff --git a/app.py b/app.py
index 1a2b3c4..5d6e7f8 100644
--- a/app.py
+++ b/app.py
@@ -1,3 +1,3 @@
def main():
- print("Hello")
+ print("Hello, World!")
return 0
-(マイナス)が付いた行は削除された内容、+(プラス)が付いた行は追加された内容を表しています。この例では、print("Hello")がprint("Hello, World!")に置き換えられたことがわかります。
ステージング済みの変更を表示する場合は、--stagedオプションを使用します。
git diff --staged
出力形式はgit diffと同じですが、こちらはステージングエリアに登録済みの変更(次のコミットに含まれる変更)が表示されます。
| 💡 ポイント |
|---|
ターミナル上のgit diffの出力は、慣れないうちは読みづらく感じることがあります。実際の開発現場では、差分をわかりやすく色分けして表示してくれるツールを使うのが一般的です。たとえば、Visual Studio CodeにはGit連携機能が標準で搭載されており、変更箇所が色付きで視覚的に表示されます。また、この後説明するGitHub上でプルリクエストを確認する際にも、追加行は緑、削除行は赤でハイライトされた見やすい差分表示を利用できます。 |
4. ブランチ
4.1 ブランチとは
ブランチは、開発の流れを分岐させる仕組みです。メインの開発ライン(mainブランチ)に影響を与えずに、新機能の開発やバグ修正を行えます。
たとえば、検索機能を追加したい場合、mainブランチからfeature/add-searchという新しいブランチを作成します。このブランチ上で検索機能の実装を進めている間も、mainブランチはそのままの状態を保っています。検索機能の実装が完了したら、feature/add-searchブランチの変更をmainブランチにマージ(統合)することで、mainブランチに検索機能が反映されます。このように、ブランチを使うことで本番のコードに影響を与えることなく安全に開発を進められます。
4.2 ブランチの基本操作
現在のリポジトリに存在するブランチの一覧を表示します。
git branch
現在チェックアウトしている(作業中の)ブランチには*マークが付いて表示されます。
* main
feature/add-search
fix/login-bug
新しいブランチを作成するには、git branchの後にブランチ名を指定します。ただし、このコマンドはブランチを作成するだけで、作業ブランチの切り替えは行いません。
git branch ブランチ名
作業するブランチを切り替えるには、git switchを使用します。切り替えると、ワーキングディレクトリのファイルが指定したブランチの状態に更新されます。
git switch ブランチ名
実際の開発では、新しいブランチを作成してすぐにそのブランチで作業を始めることがほとんどです。-cオプションを付けると、ブランチの作成と切り替えを1つのコマンドで同時に行えます。
git switch -c ブランチ名
| 💡 ポイント |
|---|
以前はブランチの切り替えにgit checkoutが使われていましたが、Git 2.23以降ではgit switchが推奨されています。checkoutはブランチ切り替え以外にも多くの用途があり紛らわしいため、ブランチ操作にはswitchを使うのが現在のベストプラクティスです。 |
4.3 マージ
あるブランチの変更を別のブランチに取り込む操作です。まず取り込み先のブランチに切り替えてから、マージを実行します。
git switch main
git merge feature/add-search
マージが完了したら、不要になったブランチを削除できます。
git branch -d feature/add-search
マージコンフリクト
マージを実行した際、同じファイルの同じ箇所を複数のブランチで異なる内容に編集していた場合、Gitはどちらの変更を採用すべきか判断できず、コンフリクト(競合)が発生します。
たとえば、mainブランチでgreeting.pyの挨拶メッセージを"Hello, Team!"に変更し、同時にfeature/add-searchブランチでも同じ箇所を"Hello, World!"に変更していた場合、マージを実行するとコンフリクトが発生します。コンフリクトが発生したファイルを開くと、以下のようなマーカーが挿入されています。
<<<<<<< HEAD
print("Hello, Team!")
=======
print("Hello, World!")
>>>>>>> feature/add-search
<<<<<<< HEADから=======までが現在のブランチ(main)の内容、=======から>>>>>>> feature/add-searchまでがマージしようとしているブランチの内容です。
コンフリクトを解決するには、マーカーを削除し、最終的に残したい内容にファイルを修正します。たとえば、以下のようにどちらかを選択するか、両方を組み合わせた内容に書き換えます。
print("Hello, World!")
修正が完了したら、git addでステージングし、git commitを実行してマージを完了させます。
git add greeting.py
git commit -m "fix: マージコンフリクトを解決"
| 💡 ポイント |
|---|
コンフリクトは、チーム開発では避けて通れないものです。こまめにブランチの変更を取り込む(mainブランチの最新を自分のブランチにマージする)習慣をつけることで、コンフリクトの発生頻度や規模を最小限に抑えることができます。また、Visual Studio Codeにはコンフリクト解決を支援する機能が搭載されており、「Accept Current Change」「Accept Incoming Change」「Accept Both Changes」といった選択肢をクリックするだけで簡単にコンフリクトを解決できます。 |
5. ブランチ戦略
チーム開発では、ブランチをどのように運用するかのルールを事前に定めておくことが重要です。このルールをブランチ戦略と呼びます。ブランチ戦略を定めることで、チームメンバ全員が統一されたワークフローで開発を進められ、コードの品質管理やリリース作業を効率的に行えます。ここでは、代表的な3つのブランチ戦略を紹介します。
5.1 Git Flow
Git Flowは、大規模なプロジェクトや、リリースサイクルが長いプロジェクト向けのブランチ戦略です。役割が明確に分かれた複数のブランチを使い分けることで、開発・リリース・緊急修正といった作業を整理して管理できるのが特徴です。
Git Flowでは、以下のようなブランチを定義して運用します。
| ブランチ | 役割 |
|---|---|
main |
本番環境にリリース済みのコード |
develop |
次のリリースに向けた開発コード |
feature/* |
新機能の開発用 |
release/* |
リリース前の最終調整用 |
hotfix/* |
本番環境の緊急修正用 |
開発者はdevelopブランチからfeatureブランチを作成して新機能を開発し、完了したらdevelopにマージします。リリースの準備が整ったらreleaseブランチを作成して最終調整を行い、mainにマージしてリリースします。本番環境で緊急の修正が必要な場合は、mainからhotfixブランチを作成して対応します。
Git Flowはブランチの役割が明確で体系的な管理ができる反面、ブランチの数が多く運用が複雑になるというデメリットがあります。
5.2 GitHub Flow
GitHub Flowは、Git Flowを大幅に簡略化したブランチ戦略で、シンプルさが最大の特徴です。使用するブランチはmainと作業用のブランチの2種類だけです。
GitHub Flowの基本的な流れは以下のとおりです。まず、mainブランチは常にデプロイ可能な状態を保ちます。新しい作業を始める際はmainからブランチを作成し、そのブランチ上で開発を行います。作業が完了したらプルリクエストを作成してチームメンバにレビューを依頼します。レビューで承認された後にmainにマージし、即座にデプロイします。
GitHub Flowは運用がシンプルなため、頻繁にデプロイを行うWebサービスの開発に適しています。
5.3 トランクベース開発
トランクベース開発(Trunk-Based Development)は、全員がmainブランチ(トランクと呼ばれます)に対して直接的かつ頻繁にコミットする戦略です。
ブランチを作成する場合も、非常に短命(1〜2日以内)にとどめ、すぐにmainにマージします。まだ公開したくない機能がある場合は、フィーチャフラグ(機能の有効・無効をコードの外側から切り替える仕組み)を活用して、コードはマージしつつも機能の公開タイミングを制御します。この戦略は自動テストやデプロイの自動化との相性が非常に良く、常にmainブランチが最新の状態に保たれるため、統合時のコンフリクトを最小限に抑えられます。
| 💡 ポイント |
|---|
| 近年のソフトウェア開発においては、GitHub Flowやトランクベース開発が広く採用されています。頻繁なリリースとチームでの効率的な共同作業を前提とした開発スタイルに適しているためです。プロジェクトの規模やチームの成熟度に応じて、適切な戦略を選択しましょう。 |
| 💡 ポイント |
|---|
ブランチ戦略はDevOpsと密接に関わっています。CI/CD(継続的インテグレーション/継続的デリバリー)のパイプラインは、ブランチ戦略に合わせて設計されることが一般的です。たとえば、mainブランチへのマージをトリガーに自動テストや自動デプロイを実行する仕組みを構築することで、品質を保ちながら迅速なリリースを実現できます。ブランチ戦略の選択は、チームの開発速度やリリースの頻度に直結するため、DevOpsの実践において重要な意思決定のひとつです。 |
6. リモートリポジトリとGitHub
6.1 リモートリポジトリとは
リモートリポジトリは、ネットワーク上(クラウドなど)に配置されたGitリポジトリです。チームメンバ間でコードを共有するために使用します。
ローカルリポジトリ(自分のPC上のリポジトリ)で行った変更をチームに共有するには、push(プッシュ)という操作でリモートリポジトリに変更を送信します。逆に、他のメンバがリモートリポジトリに反映した変更を自分のローカルリポジトリに取り込むには、pull(プル)という操作を行います。このように、pushとpullを通じてローカルリポジトリとリモートリポジトリの間で変更をやり取りすることで、チーム全体でコードを共有しながら開発を進めることができます。
6.2 GitHubとは
GitHubは、世界最大のGitホスティングサービスです。Gitのリモートリポジトリをクラウド上にホスティングする機能を中心に、ソフトウェア開発を効率化するさまざまな機能を提供しています。ここでは、GitHubの主要な機能を紹介します。
リモートリポジトリ
GitHubの最も基本的な機能が、リモートリポジトリのホスティングです。GitHubにリモートリポジトリを作成することで、チームメンバ全員がインターネットを通じて同じリポジトリにアクセスし、コードを共有できます。リポジトリはパブリック(誰でも閲覧可能)とプライベート(許可されたメンバのみアクセス可能)のどちらかに設定でき、プロジェクトの性質に応じて公開範囲を選択できます。
プルリクエスト
プルリクエスト(Pull Request、PR)は、自分が行ったコードの変更をチームメンバにレビューしてもらうための仕組みです。ブランチで作業した変更をmainブランチなどにマージする前に、プルリクエストを作成して変更内容を共有します。レビュアはコードの差分を確認し、コメントやフィードバックを送ることができます。この仕組みにより、コードの品質を保ちながらチームで効率的に開発を進めることができます。
Issue機能
Issuesは、プロジェクトに関するバグ報告や機能要望、タスクなどを管理するための機能です。それぞれのIssueにはタイトルや説明を記載でき、担当者の割り当てやラベルの付与、マイルストーンへの紐づけなども行えます。Issueを活用することで、チーム内でやるべき作業を可視化し、進捗を共有しながらプロジェクトを管理できます。
GitHub Actions
GitHub Actionsは、リポジトリに対するイベント(コードのpushやプルリクエストの作成など)をトリガーにして、テストの実行やアプリケーションのデプロイといった作業を自動化できる機能です。ワークフローと呼ばれる自動化の設定をYAMLファイルで定義し、リポジトリに含めることで利用できます。CI/CD(継続的インテグレーション/継続的デリバリー)の実現に欠かせない機能であり、DevOpsの実践においても重要な役割を果たします。
Wiki
Wikiは、プロジェクトに関するドキュメントをGitHub上で作成・管理するための機能です。セットアップ手順や設計ドキュメント、運用ルールなどをWikiページとしてまとめることで、チームメンバがいつでも参照できるナレッジベースを構築できます。
6.3 リモートリポジトリの操作
ローカルリポジトリとリモートリポジトリの間のデータの流れを図に示します。
flowchart LR
A[ワーキングディレクトリ] -->|git add| B[ステージングエリア]
B -->|git commit| C[ローカルリポジトリ]
C -->|git push| D[リモートリポジトリ]
D -->|git pull| C
D -->|git clone| C
ここでは、リモートリポジトリを操作するための基本的なGitコマンドを紹介します。
git remote add
git remote addは、ローカルリポジトリにリモートリポジトリのURLを登録するコマンドです。新しくローカルリポジトリを作成した場合、まだリモートリポジトリとの紐づけがないため、このコマンドで接続先を設定します。
git remote add origin https://github.com/ユーザ名/リポジトリ名.git
originはリモートリポジトリに付ける名前(エイリアス)です。慣例として、メインのリモートリポジトリにはoriginという名前を使用します。このコマンドを実行すると、以降はoriginという名前でリモートリポジトリを参照できるようになります。
登録済みのリモートリポジトリは、以下のコマンドで確認できます。
git remote -v
origin https://github.com/ユーザ名/リポジトリ名.git (fetch)
origin https://github.com/ユーザ名/リポジトリ名.git (push)
git push
git pushは、ローカルリポジトリのコミット履歴をリモートリポジトリに送信するコマンドです。ローカルで行った変更をチームメンバに共有するために使用します。
git push origin main
このコマンドは、ローカルのmainブランチの内容を、リモートリポジトリoriginのmainブランチに反映します。originの部分がリモートリポジトリ名、mainの部分が送信先のブランチ名です。初めてブランチをpushする場合は、-uオプションを付けることで、ローカルブランチとリモートブランチの紐づけ(追跡関係)を設定できます。
git push -u origin main
追跡関係を設定すると、以降はgit pushだけで同じリモートブランチにpushできるようになります。
git pull
git pullは、リモートリポジトリの最新の変更をローカルリポジトリに取り込むコマンドです。他のメンバがリモートリポジトリにpushした変更を、自分のローカル環境に反映するために使用します。
git pull origin main
このコマンドは、リモートリポジトリoriginのmainブランチの最新の変更を取得し、ローカルのmainブランチにマージします。チーム開発では、作業を始める前にgit pullで最新の変更を取り込む習慣をつけることが重要です。これにより、古いコードをもとに作業してしまうことを防ぎ、マージ時のコンフリクトを減らすことができます。
git clone
git cloneは、リモートリポジトリをローカルに複製するコマンドです。既存のプロジェクトに参加する際や、他の開発者のリポジトリを自分の環境に取得する際に使用します。
git clone https://github.com/ユーザ名/リポジトリ名.git
このコマンドを実行すると、リポジトリ名と同じ名前のフォルダが作成され、その中にリポジトリの全ファイルとコミット履歴がダウンロードされます。また、クローン元のURLが自動的にoriginとして登録されるため、git remote addを別途実行する必要はありません。
| 💡 ポイント |
|---|
git cloneは、リモートリポジトリのすべての履歴を含めて複製するため、クローン直後からローカルでgit logによる履歴の確認やブランチの切り替えなど、すべてのGit操作を行えます。チーム開発では、まずgit cloneでリポジトリを取得し、その後はgit pullとgit pushで変更をやり取りするのが基本的な流れです。 |
7. プルリクエストとコードレビュー
7.1 プルリクエストとは
プルリクエスト(Pull Request、PR)は、自分の変更を他のブランチにマージする前に、チームメンバにレビューを依頼する仕組みです。チーム開発では、作業ブランチで行った変更をいきなりmainブランチにマージするのではなく、プルリクエストを通じてレビューを受けてからマージするのが一般的です。ここでは、プルリクエストの作成からマージまでの一連の流れを説明します。
プルリクエストの基本的な流れを図に示します。
sequenceDiagram
participant 開発者
participant GitHub
participant レビュア
開発者->>GitHub: ブランチを作成してpush
開発者->>GitHub: プルリクエストを作成
GitHub->>レビュア: レビューを依頼
レビュア->>GitHub: コードレビュー
レビュア->>GitHub: 承認(Approve)
GitHub->>GitHub: mainブランチにマージ
まず、開発者はローカル環境で作業ブランチを作成し、機能の追加やバグの修正を行います。作業が完了したら、変更をコミットし、git pushで作業ブランチをリモートリポジトリに送信します。
次に、GitHub上でプルリクエストを作成します。プルリクエストには、変更の目的や内容を説明するタイトルと説明文を記載します。どのブランチからどのブランチへマージするか(たとえばfeature/add-searchからmainへ)を指定し、レビューを担当するメンバを選択します。
プルリクエストが作成されると、レビュアはGitHub上で変更内容の差分を確認できます。コードの各行に対してコメントを残したり、全体的なフィードバックを送ったりすることができます。また、GitHub Actionsなどの自動テストが設定されている場合は、プルリクエストの作成をトリガーにテストが自動的に実行され、その結果もプルリクエスト上で確認できます。
レビュアが変更内容に問題がないと判断した場合、プルリクエストを承認(Approve)します。修正が必要な場合は、コメントで指摘し、開発者が修正を行って再度pushします。pushした修正は自動的にプルリクエストに反映されるため、レビュアは修正内容を確認して再度レビューを行います。
すべてのレビュアから承認が得られ、自動テストも通過したら、プルリクエスト上の「Merge」ボタンをクリックして、作業ブランチの変更をmainブランチにマージします。マージが完了すると、作業ブランチは不要になるため、通常は削除します。GitHub上では、マージ完了後にブランチを削除するボタンが表示されるため、簡単にクリーンアップできます。
7.2 コードレビューの文化
コードレビューは、コードの品質を維持し、チーム全体の技術力を向上させるために欠かせないプロセスです。
開発者が書いたコードには、本人では気づきにくいミスや改善点が含まれていることがあります。コードレビューでは、第三者の視点からコードを確認することで、仕様通りに正しく動作するかという正確性の観点や、他の開発者が読んで理解しやすいコードになっているかという可読性の観点をチェックします。また、将来の変更や修正がしやすい構造になっているかという保守性や、セキュリティ上の問題がないかといった観点も、レビューを通じて確認します。さらに、変更に対して適切なテストが書かれているかを確認することで、将来の変更によるデグレード(既存機能の意図しない破壊)を防ぐことにもつながります。
コードレビューの効果はコードの品質向上だけにとどまりません。レビューを通じてチームメンバ同士がお互いのコードを読み合うことで、プロジェクト全体のコードに対する理解が深まり、知識の属人化を防ぐことができます。また、経験の浅いメンバにとっては、ベテランのフィードバックを受けることで技術的な成長の機会にもなります。
コードレビューは「間違いを指摘する場」ではなく、「チームで品質を高め合う場」です。レビューを受ける側もする側も、建設的なコミュニケーションを心がけることが大切です。迅速かつ丁寧なレビューが、開発の速度とコードの品質の両方を支えます。
| 💡 ポイント |
|---|
| 近年では、AIを活用したコードレビューも有効な手段として注目されています。たとえば、GitHubのプルリクエストにAIレビューツールを連携させることで、コードの問題点やセキュリティリスクを自動的に検出し、改善案を提示してもらうことができます。AIによるレビューは、人間のレビュアの負担を軽減するだけでなく、レビューの待ち時間を短縮する効果もあります。ただし、AIのレビューはあくまで補助的なものであり、ビジネスロジックの妥当性や設計判断といった観点は、チームメンバによるレビューが引き続き重要です。 |
| 💡 ポイント |
|---|
| プルリクエストが承認された後、誰がマージを実行するかは組織やチームによってルールが異なります。「レビュアが承認した後、プルリクエストの作成者(依頼者)自身がマージする」というルールのチームもあれば、「レビュアが承認とマージを一括して行う」というルールのチームもあります。特に、リリースタイミングに合わせてマージする必要がある場合や、他のブランチとの統合順序が重要な場合は、マージのタイミングを誰がコントロールするかが開発の進行に影響します。新しいプロジェクトやチームに参画した際は、マージのルールがどちらであるかを早めに確認しておくとよいでしょう。 |
8. .gitignoreの重要性
8.1 Gitで管理すべきでないファイル
Gitはデフォルトではすべてのファイルを管理対象として扱います。しかし、プロジェクトの中には、Gitで管理すべきでないファイルが数多く存在します。
特に注意が必要なのが機密情報を含むファイルです。AWSのアクセスキーやデータベースのパスワード、APIキーなどを記載したファイルをうっかりコミットしてしまうと、その内容がGitHub上で誰でも閲覧できる状態になってしまいます。さらに、Gitはすべての変更を履歴として記録しているため、一度コミットされた機密情報は、後からファイルを削除しても履歴の中に残り続けます。過去に、企業のAWSアクセスキーがGitHubに公開されてしまい、不正利用によって高額な請求が発生した事例も報告されています。
また、venv/のようなPythonの仮想環境フォルダは数千ファイルに及ぶことがあり、これをコミットするとリポジトリのサイズが膨大になります。__pycache__/や.DS_Storeのような自動生成ファイルも、管理対象に含めると不要な変更差分が発生し、レビューやコミット履歴の見通しが悪くなります。
こうした問題を防ぐために用意されている仕組みが、次に紹介する.gitignoreです。
8.2 .gitignoreとは
.gitignoreは、Gitの管理対象から除外するファイルやフォルダを指定するための設定ファイルです。リポジトリのルートディレクトリに.gitignoreという名前で作成し、除外したいファイルやフォルダのパターンを1行ずつ記述します。.gitignoreに記載されたファイルは、git addを実行しても自動的にステージングの対象外となるため、うっかりコミットしてしまう事故を防ぐことができます。
8.3 .gitignoreの書き方
.gitignoreの基本的な書き方を紹介します。ファイル名をそのまま記述するとそのファイルが除外され、フォルダ名の末尾に/を付けるとそのフォルダ全体が除外されます。*はワイルドカードとして任意の文字列にマッチし、#で始まる行はコメントとして扱われます。
以下は、Pythonプロジェクトにおける.gitignoreの例です。
# 環境変数・機密情報
.env
credentials.json
*.key
*.pem
# Python
__pycache__/
*.pyc
venv/
# IDE
.vscode/
.idea/
# OS
.DS_Store
Thumbs.db
この例では、.envやcredentials.jsonといった機密情報を含むファイル、__pycache__/やvenv/といったPythonの自動生成ファイルや依存パッケージ、.vscode/などのIDE設定ファイル、.DS_StoreのようなOS固有のファイルを除外しています。
以下は、よく.gitignoreに指定すべきファイル・フォルダの一覧です。
| ファイル・フォルダ | 理由 |
|---|---|
.env |
環境変数(パスワードやAPIキー)を含む |
credentials.json |
認証情報を含む |
*.key、*.pem |
秘密鍵ファイル |
__pycache__/ |
Pythonが自動生成するキャッシュファイル |
venv/ |
Python仮想環境(サイズが大きく再現可能) |
.vscode/、.idea/ |
IDE固有の設定ファイル |
.DS_Store |
macOSが自動生成するファイル |
| 💡 ポイント |
|---|
.gitignoreはプロジェクトの初期段階で設定することが重要です。一度コミットしてしまったファイルは、後から.gitignoreに追加しても履歴から自動的に削除されることはありません。プロジェクトを始める際は、使用する言語やフレームワークに合わせた.gitignoreのテンプレートがGitHub上で公開されているため、それを活用するのがおすすめです。 |
9. コミットメッセージのベストプラクティス
9.1 良いコミットメッセージとは
コミットメッセージは、変更内容を他の開発者や未来の自分に伝えるためのものです。数か月後にコミット履歴を見返したとき、どのような変更がなぜ行われたのかを理解できるかどうかは、コミットメッセージの書き方にかかっています。チーム開発においても、他のメンバがコミット履歴を追って変更の経緯を把握する場面は頻繁にあるため、誰が読んでも内容が伝わるコミットメッセージを書くことが重要です。
以下は、良いコミットメッセージの例です。
feature: ログ解析ツールにCSV出力機能を追加
解析結果をCSV形式でエクスポートする機能を実装。
--csv オプションで出力先のパスを指定できる。
このメッセージが優れている点は、1行目で変更の種別(feature=新機能)と概要が簡潔にまとまっており、一覧表示でも内容がひと目で把握できることです。さらに、2行目以降の詳細説明で具体的な実装内容やオプションの使い方が補足されているため、変更の目的と影響範囲を正確に理解できます。
なお、コミットメッセージにはGitが強制する文字数の上限はありませんが、広く採用されている慣例として、1行目(件名)は50文字以内に収めることが推奨されています。これは、GitHubのコミット一覧やプルリクエスト上では1行目が長いと途中で省略表示されてしまうためです。また、git log --onelineでも1行目のみが表示されるため、短く要点をまとめることで、履歴を素早く確認できるようになります。詳細な説明が必要な場合は、1行目の後に空行を挟んでから本文を記述し、各行は72文字程度で折り返すのが一般的です。
一方、以下は悪いコミットメッセージの例です。
修正
色々変更した
これらのメッセージは、何を修正したのか、何を変更したのかがまったくわかりません。後からコミット履歴を見返しても、実際にコードの差分を開いて確認しなければ変更内容を把握できず、効率的な開発の妨げになります。「修正」であれば「fix: ログイン時にセッションが保持されないバグを修正」のように、何をどう修正したのかを具体的に記述しましょう。
9.2 コミットメッセージの構成
一般的に採用されているコミットメッセージの形式です。
<種別>: <概要>
<詳細な説明(任意)>
よく使われる種別(プレフィクス)は以下のとおりです。
| 種別 | 用途 | メッセージ例 |
|---|---|---|
feature |
新機能の追加 | feature: ログ解析ツールにCSV出力機能を追加 |
fix |
バグ修正 | fix: ログイン時にセッションが保持されないバグを修正 |
docs |
ドキュメントの変更 | docs: READMEにセットアップ手順を追記 |
refactor |
リファクタリング(機能変更なし) | refactor: ユーザ認証処理を関数に分離 |
test |
テストの追加・修正 | test: ログ解析の異常系テストを追加 |
chore |
ビルドや設定の変更 | chore: .gitignoreにvenv/を追加 |
9.3 コミットの粒度
コミットは1つの論理的な変更ごとに作成するのが望ましいです。たとえば、「ログ解析のエラーハンドリングを追加」のように、1つの明確な目的に対応したコミットであれば、履歴を見返したときに変更の意図がすぐに理解できます。
一方、「ログ解析ツール全体を実装」のように1回のコミットに多くの変更をまとめてしまうと、複数の変更が混在して追跡しづらくなります。もし後から一部の変更だけを取り消したくなっても、他の変更と絡み合っているため対応が困難になります。
逆に、「変数名を1つ変更」のようにあまりに小さな単位でコミットを作成すると、コミット履歴が膨大になり、意味のあるまとまりとして変更を追跡することが難しくなります。
適切な粒度でコミットすることで、git logで変更履歴を追いやすくなり、問題が発生した際にgit revertで特定のコミットだけを取り消すことも容易になります。「このコミットで何をしたかを一文で説明できるか」を目安にすると、適切な粒度を判断しやすくなります。
| 💡 ポイント |
|---|
| コミットメッセージを日本語で書くか英語で書くかは、プロジェクトやチームのルールによって異なります。海外展開を見据えているプロジェクトや、チーム内に海外のメンバがいる場合などは、コミットメッセージを英語で統一しているケースがあります。一方で、日本語でコミットメッセージを書いているプロジェクトも数多くあります。「コミットメッセージは英語で書くもの」という印象を持っている方もいますが、重要なのはプロジェクトの既存のルールに合わせることです。チーム全体が日本語でコミットメッセージを書いている中で、自分だけ英語で書いてしまうと、他のメンバが変更内容をすぐに把握しづらくなり、かえってチームの生産性を下げてしまいます。新しいプロジェクトに参画した際は、過去のコミット履歴を確認し、どちらの言語で書かれているかを把握した上で、それに合わせるようにしましょう。 |
10. まとめ
この講座では、バージョン管理システムであるGitとGitHubについて学びました。
- バージョン管理は、ファイルの変更履歴を記録・管理するシステムで、ソフトウェア開発の基盤となる
- Gitは分散型バージョン管理システムで、ワーキングディレクトリ・ステージングエリア・リポジトリの3つのエリアを持つ
- 基本操作として、
git init、git add、git commit、git status、git log、git diffを使う - ブランチを使って開発を分岐させ、
git mergeで統合する - ブランチ戦略にはGit Flow、GitHub Flow、トランクベース開発があり、プロジェクトに応じて選択する
- GitHubはリモートリポジトリのホスティングサービスで、
git push/git pullで同期する - プルリクエストとコードレビューは、コードの品質を維持するための重要な文化
.gitignoreで機密情報や不要なファイルをGit管理から除外し、セキュリティを確保する- コミットメッセージは適切な粒度と明確な記述を心がける