コミット
Gitのコミット機能は、単なる変更の記録以上の可能性を秘めています。複数著者の貢献を正確に記録し、過去のメッセージを修正し、組織としての開発活動を可視化する。これらの機能を適切に使いこなすことで、チーム開発の透明性と効率性が大きく向上します。
本記事では、GitHubの公式ドキュメントをもとに、実務で役立つコミット管理の実践的なテクニックを解説します。
1. コミットの基本:変更を記録する単位
コミットは、ブランチ内の1つ以上のファイルに対する意味のある変更のまとまりを保存します。各コミットには、SHA(ハッシュ)と呼ばれる一意のIDが割り当てられ、以下の情報が記録されます。
- 具体的な変更内容
- 変更が行われた日時
- 変更を行った人物
コミットを行う際には、変更内容を簡潔に説明するコミットメッセージが必須です。このメッセージが、後から変更履歴を追跡する際の重要な手がかりとなります。
2. 複数著者でのコミット作成:ペアプログラミングの可視化
モブプログラミングやペアプログラミングを行う際、複数人が1つのコミットに貢献することがあります。Co-authored-by: トレーラーを使用することで、すべての貢献者を適切にクレジットできます。
2.1 必要な情報の収集
共同著者を追加する前に、各共同著者の適切なメールアドレスを把握する必要があります。
- GitHubアカウントに関連付けられたメールアドレスを使用することで、コミットが貢献としてカウントされます
- メールアドレスを非公開にしている場合は、GitHubが提供するno-replyメールアドレスを使用します
- no-replyメールアドレスは、メール設定ページの「メールアドレスを非公開にする」の下で確認できます
2.2 コマンドラインでの実装
# コミットメッセージと説明を入力
# 説明の後に2行の空行を追加
$ git commit -m "ユーザビリティテストをリファクタリング
>
>
> Co-authored-by: 山田太郎 <yamada@example.com>
> Co-authored-by: 佐藤花子 <sato@example.com>"
重要なポイントは以下の通りです。
- コミットの説明文の後に空行を2行挿入
-
Co-authored-by:の行を追加(各共同著者ごとに1行) - 形式:
Co-authored-by: 名前 <メールアドレス>
2.3 GitHub Desktop での実装
GitHub Desktopを使用する場合、GUIから簡単に共同著者を追加できます。
2.4 GitHub Web エディタでの実装
GitHubのWebエディタでファイルを変更した後、以下の手順で共同著者を追加します。
- 「Commit changes...」をクリック
- 「Commit message」フィールドに変更内容を記述
- コミットメッセージの下のテキストボックスに
Co-authored-by:情報を追加 - 「Commit changes」または「Propose changes」をクリック
3. コミットメッセージの変更:履歴を整える技術
開発中、コミットメッセージに不明瞭な表現や誤った情報が含まれることがあります。Gitでは、コミットメッセージを変更することができますが、コミットIDも変更されるため注意が必要です。
3.1 最新のコミットメッセージを変更する
まだプッシュしていないコミットの場合、git commit --amend コマンドで簡単に修正できます。
# リポジトリのディレクトリに移動
$ cd /path/to/repository
# 修正コマンドを実行
$ git commit --amend
このコマンドを実行すると、デフォルトのテキストエディタが開き、現在のコミットメッセージが表示されます。編集して保存すれば、メッセージが更新されます。
修正後、次回のプッシュ時に新しいコミットとメッセージがGitHubに反映されます。
3.2 プッシュ済みのコミットメッセージを変更する
すでにGitHubにプッシュ済みのコミットを変更する場合、force pushが必要です。
# メッセージを修正
$ git commit --amend
# force pushを実行
$ git push --force-with-lease origin feature-branch
警告: force pushはリポジトリの履歴を書き換えます。他の開発者がすでにそのブランチをプルしている場合、彼らのローカルリポジトリとの間で競合が発生します。チーム開発では、共有ブランチへのforce pushは極力避けてください。
3.3 過去のコミットや複数のコミットメッセージを変更する
古いコミットや複数のコミットのメッセージを一度に変更する場合、インタラクティブリベースを使用します。
# 最新の3つのコミットを対象にする場合
$ git rebase -i HEAD~3
実行すると、以下のようなリストが表示されます。
pick e499d89 CNAMEを削除
pick 0c39034 READMEを改善
pick f7fde4a コミットメッセージを変更するが同じコミットをプッシュ
# Rebase 9fdb3bd..f7fde4a onto 9fdb3bd
#
# Commands:
# p, pick = コミットを使用
# r, reword = コミットを使用するが、メッセージを編集
# e, edit = コミットを使用するが、修正のために停止
# s, squash = コミットを使用するが、前のコミットにマージ
# f, fixup = squashと同様だが、このコミットのログメッセージを破棄
# x, exec = シェルを使用してコマンドを実行
変更したいコミットの pick を reword に変更します。
pick e499d89 CNAMEを削除
reword 0c39034 READMEを改善
reword f7fde4a コミットメッセージを変更するが同じコミットをプッシュ
保存して閉じると、各コミットのエディタが順番に開くので、新しいメッセージを入力して保存します。
最後にforce pushを実行します。
$ git push --force origin feature-branch
注意: 機密情報を含むコミットメッセージをforce pushで修正しても、元のコミットがGitHubから完全に削除されるとは限りません。古いコミットはクローンには含まれませんが、コミットIDを介してアクセス可能な場合があります。完全に削除するには、GitHubサポートに連絡する必要があります。
4. 組織を代表したコミット:企業開発の透明性
オープンソースプロジェクトや企業の公式リポジトリでは、個人ではなく組織として開発活動を示したい場合があります。on-behalf-of: トレーラーを使用することで、組織を代表したコミットを作成できます。
4.1 必要な条件
組織を代表したコミットを作成するには、以下の条件を満たす必要があります。
- トレーラーで指定された組織のメンバーであること
- コミットに署名していること
- コミットのメールアドレスと組織のメールアドレスが、組織によって検証されたドメイン内にあること
- コミットメッセージが
on-behalf-of: @org <name@organization.com>トレーラーで終わっていること
4.2 コマンドラインでの実装
# コミットメッセージを入力(説明の後に2行の空行を追加)
$ git commit -m "ユーザビリティテストをリファクタリング
>
>
on-behalf-of: @myorg yamada@myorganization.com"
4.3 GitHub Web エディタでの実装
- 「Commit changes...」をクリック
- 「Commit message」フィールドに変更内容を記述
- コミットメッセージの下のテキストボックスに
on-behalf-of: @org <name@organization.com>を追加 - 「Commit changes」または「Propose changes」をクリック
新しいコミット、メッセージ、およびバッジがGitHub上に表示されます。
5. コミットの比較:変更を可視化する
リポジトリの異なるバージョン間で変更を比較することで、開発の進行状況を把握できます。リポジトリのパスに /compare を追加することで、比較ビューにアクセスできます。
5.1 比較の基本構造
比較ビューには、base(開始点)と compare(終点)の2つのドロップダウンメニューがあります。これらを変更することで、任意のバージョン間の差分を確認できます。
5.2 ブランチ間の比較
最も一般的な使用方法は、プルリクエストを開始する際のブランチ比較です。compare ドロップダウンメニューからブランチ名を選択するだけで、比較を開始できます。
5.3 タグ間の比較
リリースタグ間を比較することで、前回のリリース以降の変更を確認できます。
注意: ブランチとタグが同じ名前の場合、ブランチが優先されます。タグを明示的に比較するには、tags/ をタグ名の前に追加します。
5.4 コミット間の比較
2つの任意のコミットを直接比較するには、URLを編集します。短縮SHAコードを使用できます。
5.5 フォーク間の比較
異なるリポジトリのブランチを比較する場合、ブランチ名の前にユーザー名を付けます。
-
base:suzuki:main -
compare:tanaka-org:main
これにより、suzuki と tanaka-org が所有するリポジトリの main ブランチを比較できます。
大規模な組織では、さらに詳細な指定が可能です。tanaka:awesome-app:main は、tanaka/awesome-app リポジトリの main ブランチを指定します。
5.6 コミット履歴の表記法
Gitでは、特定の記法を使用してコミットの前後関係を表現できます。
^ 記法: 1つ前のコミットを指定。複数重ねることでさらに遡ります。
- 例:
96d29b7^^^^^は96d29b7の5つ前のコミット
~N 記法: N個前のコミットを指定。
- 例:
96d29b7~5は96d29b7の5つ前のコミット
6. コミットビューの違い:履歴の見え方
GitHubでは、コミット履歴を表示する方法によって、表示される情報が異なる場合があります。
6.1 2つの表示方法
- リポジトリのコミットページに直接移動
- ファイルをクリックして「History」を選択し、特定のファイルのコミット履歴を表示
6.2 単一ファイルの履歴での省略
特定のファイルの履歴を表示する場合、Gitはそのファイルに影響を与えなかったコミットを省略します。例えば、サイドブランチで変更を加えてから取り消した場合、そのコミットはファイル履歴に表示されません。
これにより、ファイルの最終状態に寄与したコミットのみを効率的に確認できます。
6.3 完全な履歴の確認
すべての履歴情報を確認したい場合は、リポジトリのコミットページを使用してください。こちらでは、ファイルに直接影響しなかったコミットも含めて表示されます。
7. トラブルシューティング:よくある問題と解決策
7.1 コミットがGitHubには存在するがローカルクローンには存在しない
git show コマンドで特定のコミットを表示しようとしたときに、エラーが発生する場合があります。
$ git show 1095ff3d0153115e75b7bca2c09e5136845b5592
> fatal: bad object 1095ff3d0153115e75b7bca2c09e5136845b5592
しかし、GitHub上では問題なく表示されます。
7.1.1 原因と解決策
原因1: ローカルリポジトリが最新でない
# リモートリポジトリから情報を取得
$ git fetch origin
git fetch コマンドは、リモートリポジトリから安全に情報をコピーし、ローカルクローンを更新します。
原因2: ブランチが削除された
コミットを含むブランチが削除された場合、そのコミットは孤立(どの参照からも到達不可能)します。
この場合、そのコミットを持つ共同作業者がいれば、以下の手順でリカバリできます。
# ローカルブランチ(B)がコミットを含んでいると仮定
$ git branch recover-B B
# コミットを参照する新しいローカルブランチを作成
$ git push upstream B:recover-B
# ローカルのBを新しいupstreamブランチにプッシュ
その後、他のメンバーは以下のコマンドで取得できます。
$ git fetch upstream recover-B
# コミットをローカルリポジトリに取得
原因3: force pushによる上書き
複数人がアクセスできるリポジトリでは、force pushは可能な限り避けてください。force pushは履歴を書き換えるため、他の人の作業基盤となっているコミットを上書きする可能性があります。プルリクエストが壊れたり、他のメンバーのローカルブランチが同期できなくなるリスクがあります。
7.2 コミットが間違ったユーザーにリンクされている
コミットが別のユーザーにリンクされている場合、ローカルのGit設定のメールアドレスがそのユーザーのGitHubアカウントに接続されていることが原因です。
7.2.1 解決手順
- ローカルのGit設定を変更
# グローバル設定を変更
$ git config --global user.email "your-email@example.com"
# 特定のリポジトリのみ変更
$ git config user.email "your-email@example.com"
- GitHubアカウントにメールアドレスを追加
GitHubの設定ページで、新しいメールアドレスをアカウントに追加します。これにより、今後のコミットが正しくリンクされます。
7.3 コミットがどのユーザーにもリンクされていない
コミットがどのユーザーにもリンクされていない場合、以下のいずれかの理由が考えられます。
認識されない著者(メールアドレスあり)
使用したメールアドレスがGitHubアカウントに接続されていません。GitHubのメール設定にそのアドレスを追加してください。
認識されない著者(メールアドレスなし)
汎用的なメールアドレスを使用しており、GitHubアカウントに接続できません。Gitでコミットメールアドレスを設定し、GitHubのメール設定に追加する必要があります。
無効なメール
ローカルのGit設定のメールアドレスが空白、または正しい形式ではありません。同様に、Gitでメールアドレスを設定し、GitHubに追加してください。
8. まとめ
Gitのコミット機能は、適切に活用することで開発プロセスの透明性と効率性を大幅に向上させることができます。
-
複数著者のコミット:
Co-authored-by:で共同作業を正確に記録 -
メッセージの修正:
git commit --amendとインタラクティブリベースで履歴を整理 -
組織代表のコミット:
on-behalf-of:で企業活動を可視化 - 比較機能: ブランチ、タグ、コミット間の差分を効率的に確認
- トラブルシューティング: 一般的な問題に対する具体的な解決策
これらのテクニックを日常の開発ワークフローに組み込むことで、チーム全体のコミュニケーションが改善され、プロジェクトの進行状況がより明確になります。特にforce pushのような破壊的な操作については、その影響範囲を十分に理解した上で慎重に使用することが重要です。
コミット履歴は、プロジェクトの歴史そのものです。適切な管理により、将来の開発者(そして未来の自分)が、なぜその変更が行われたのかを正確に理解できるようになります。