Git Diff を使いこなす

GitBeginner
オンラインで実践に進む

はじめに

Git エクスプローラーの皆さん、ようこそ!今日は、Git の中で最も強力で頻繁に使用される機能の一つである git diff コマンドについて深く掘り下げていきます。ファイルにどのような変更を加えたのか正確に把握したかったり、コードの異なるバージョンを比較したりする必要がある場合、git diff はまさに探し求めていたツールです。

git diff コマンドは、コードの変更を詳細に観察するための顕微鏡のようなものです。作業ディレクトリ、ステージングエリア(インデックス)、コミット間、さらにはブランチ間など、リポジトリのさまざまな状態における正確な差異を確認することができます。

この実験では、以下の方法を学びます:

  1. 作業ディレクトリとステージングエリアの比較
  2. ステージングエリアと最新コミットの比較
  3. 異なるブランチ間の比較
  4. 特定のファイルの比較
  5. 外部 diff ツールを使用した視覚的な比較

この実験を終える頃には、あなたは git diff のエキスパートになり、正確かつ自信を持って変更内容を精査できるようになっているはずです。このスキルは、自分の作業のレビュー、コミットの準備、そして他者との効果的な共同作業において極めて重要です。

それでは、git diff のパワーを探索し始めましょう!

ワークスペースのセットアップ

比較を始める前に、比較対象となるファイルとコミットを含むワークスペースを準備しましょう。新しいディレクトリを作成し、Git リポジトリを初期化して、複数のコミットを含むいくつかのファイルを追加します。

ターミナルを開き、以下のコマンドを入力してください:

cd ~/project
mkdir git-diff-lab
cd git-diff-lab
git init

次に、以下のコマンドをコピー&ペーストして、いくつかのファイルを作成し、一連のコミットを行います:

echo "## Git Diff Lab" > README.md
git add README.md
git commit -m "Initial commit"

echo "function greet(name) {" > greet.js
echo "  return 'Hello, ' + name + '!';" >> greet.js
echo "}" >> greet.js
git add greet.js
git commit -m "Add greet function"

echo "const numbers = [1, 2, 3, 4, 5];" > numbers.js
echo "console.log(numbers);" >> numbers.js
git add numbers.js
git commit -m "Add numbers array"

今行った操作の内容を整理しましょう:

  1. README ファイルを作成し、最初のコミットを行いました。
  2. 挨拶を返す関数を含む JavaScript ファイルを作成し、コミットしました。
  3. 数値の配列を含む別の JavaScript ファイルを作成し、コミットしました。

これで、探索するための履歴を持ったリポジトリが完成しました!

作業ディレクトリとステージングエリアの比較

git diff の最も基本的な使い方は、まだステージング(git add)されていない作業ディレクトリ内の変更を確認することです。これを試してみましょう。

まず、greet.js ファイルにいくつかの変更を加えます:

echo "function farewell(name) {" >> greet.js
echo "  return 'Goodbye, ' + name + '!';" >> greet.js
echo "}" >> greet.js

次に、git diff を使ってこれらの変更を確認します:

git diff

以下のような出力が表示されるはずです:

diff --git a/greet.js b/greet.js
index 95f5574..a3641f6 100644
--- a/greet.js
+++ b/greet.js
@@ -1,3 +1,7 @@
 function greet(name) {
   return 'Hello, ' + name + '!';
 }
+function farewell(name) {
+  return 'Goodbye, ' + name + '!';
+}

この出力の見方を説明します:

  • 最初の行は、どのファイルが比較されているかを示しています。
  • +++--- の行は、比較されているファイルのバージョンを示しています(a/ は元のバージョン、b/ は新しいバージョンです)。
  • @@ の行は、ファイル内のどの場所で変更が発生したかというコンテキスト情報を提供します。
  • + で始まる行は追加された行で、- で始まる行は削除された行を示します。

この diff は、greet.js に 3 つの新しい行が追加されたことを示しています。

q キーを押して diff ビューを終了します。

次に、これらの変更をステージングします:

git add greet.js

もう一度 git diff を実行しても、何も出力されません。これは、git diff がデフォルトでは「ステージングされていない変更」のみを表示するためです。ステージング済みの変更を確認するには、次のステップで説明する git diff --staged を使用する必要があります。

覚えておいてください。引数なしの git diff は、作業ディレクトリとステージングエリアを比較します。これは、変更をステージングする前に内容をレビューするのに最適な方法です。

ステージングエリアと最新コミットの比較

変更をステージングしたので、次はステージングエリアと最新のコミットを比較する方法を学びましょう。これは、次のコミットにどのような変更が含まれるかをレビューする際に役立ちます。

ステージングエリアと最新コミットの差異を確認するには、以下のコマンドを使用します:

git diff --staged

前のステップで見たのと同様の出力が表示され、farewell 関数の追加が確認できるはずです。

このコマンドは、時間をかけて少しずつ変更をステージングし、最終的にコミットする前にすべてを再確認したい場合に特に便利です。

動作を確認するために、もう一つ変更を加えてステージングしてみましょう:

echo "console.log(greet('World'));" >> greet.js
git add greet.js

ここで git diff --staged を実行すると、farewell 関数と新しい console.log の行の両方が表示されます。

git diff --staged(または同義の git diff --cached)は、最新のコミットと比較して、現在ステージングエリアにある変更を表示します。コミット直前の最終チェックとして非常に有効な手段です。

ブランチ間の比較

Git diff は、異なるブランチ間を比較する際にも役立ちます。これは、機能開発用のブランチ(フィーチャーブランチ)で作業していて、メインブランチ(master/main)との違いを確認したい場合に特に重宝します。

新しいブランチを作成して変更を加えてみましょう:

git checkout -b feature-branch
echo "const PI = 3.14159;" >> numbers.js
git add numbers.js
git commit -m "Add PI constant"

では、このブランチを master ブランチと比較してみます:

git diff master feature-branch

numbers.js に定数 PI が追加されたことを示す出力が表示されるはずです。

このコマンドは、master ブランチの先端と feature-branch ブランチの先端の差異を表示します。つまり、「master にはなくて feature-branch にある変更は何か」を教えてくれます。

最初のブランチ名を省略して、現在のブランチと別のブランチを比較することもできます:

git diff master

これは、現在のブランチ(feature-branch)と master を比較します。

ブランチを比較する際の注意点:

  • 最初のブランチ(省略した場合は現在のブランチ)にはあるが、2 番目のブランチにはない変更は、削除(-)として表示されます。
  • 2 番目のブランチにはあるが、最初のブランチにはない変更は、追加(+)として表示されます。

この機能は、ブランチをマージする準備をしているときや、フィーチャーブランチがどのような変更を導入しようとしているかを確認したいときに非常に便利です。

特定のファイルの比較

特定のファイルやファイル群の変更だけを確認したい場合もあります。Git diff を使えば、これを簡単に行うことができます。

複数のファイルに変更を加えてみましょう:

echo "function multiply(a, b) { return a * b; }" >> greet.js
echo "const doubledNumbers = numbers.map(n => n * 2);" >> numbers.js

ここで、greet.js の変更だけを見たい場合は、次のように指定します:

git diff greet.js

これにより、greet.js に加えられた変更のみが表示されます。

ブランチ間で特定のファイルを比較することも可能です:

git diff master feature-branch -- numbers.js

これは、master ブランチと feature-branch ブランチの間で、numbers.js にどのような違いがあるかを表示します。

上記のコマンドにある -- は、ブランチ名とファイルパスを区切るために使用されます。常に必須というわけではありませんが、ファイル名がブランチ名と間違えられる可能性がある場合など、曖昧さを避けるためにこれを使う習慣をつけておくと良いでしょう。

これまで学んだすべての diff コマンドでファイルパスを指定できます。これは、多くのファイルに変更がある大規模なプロジェクトで、特定の箇所だけに集中したい場合に特に役立ちます。

外部 diff ツールの使用

Git 内蔵の diff は強力ですが、変更をより視覚的に把握したい場合もあります。多くの開発者は、そのために外部の diff ツールを使用します。

人気のあるツールの一つに vimdiff があります。Git が vimdiff を使用するように設定してみましょう:

git config --global diff.tool vimdiff
git config --global difftool.prompt false

これで、git diff の代わりに git difftool を使用できるようになります:

git difftool

これにより、変更された各ファイルが vimdiff で開かれます。ファイル間の移動は、次のファイルへは :n、前のファイルへは :prev を使用します。vimdiff を終了するには :qa! を入力します。

他にも Beyond Compare、KDiff3、P4Merge など、多くの diff ツールが利用可能です。ツールの選択は、個人の好みや使用している OS によって決まることが多いです。

視覚的な diff ツールは、特に大きな変更を確認する際には非常に役立ちますが、常に必要というわけではありません。多くの開発者は標準の git diff 出力に習熟し、日常的な作業ではそのスピードとシンプルさを好んで使用しています。

まとめ

おめでとうございます、diff 探偵の皆さん!git diff の世界を深く掘り下げる学習を完了しました。カバーした主要な概念を振り返ってみましょう:

  1. 作業ディレクトリとステージングエリアの比較: 作業ディレクトリ内の未ステージングの変更を確認する方法を学びました。
  2. ステージングエリアと最新コミットの比較: コミット前に、ステージングされた変更をレビューする方法を発見しました。
  3. ブランチ間の比較: 異なるブランチを比較して、それらがどのように分岐しているかを確認する方法を見ました。
  4. 特定のファイルの比較: 関心のある特定のファイルに絞って diff を表示する方法を学びました。
  5. 外部 diff ツールの使用: 変更を異なる視点から見るために、視覚的な diff ツールを使用する方法を探索しました。

git diff コマンドは、Git ツールキットの中でも非常に強力なツールです。コミットの準備、同僚の作業のレビュー、あるいはプロジェクトの履歴の理解など、あらゆる場面で変更を正確に検査することができます。

git diff を使いこなすには練習が必要です。最初は出力が難解に見えるかもしれませんが、時間が経てば diff を素早く効率的に読み取れるようになります。

Git の学習を続ける中で、git diff のさまざまなオプションやユースケースをさらに探索してみてください。これは、他の多くの Git 機能と組み合わせることで、プロジェクトの変更に関する深い洞察を与えてくれる多才なコマンドです。

ハッピー・ディフィング!あなたのコードの変更が常に明確で、意図通りでありますように!