ここでいくつかのことが起こっています。まず、Git のブランチは実際には特定のコミットに固定された単なる「ラベル」であり、ブランチにコミットすると自動的に移動されることを理解しておくと便利です。Git は、新しいコミット ハッシュを使用して新しいコミットを作成し、新しいコミットを指すようにブランチ/ラベルを更新します。(では、これがタグとどう違うのかと尋ねるかもしれません。タグは同じコミットに固定されており、git commit を呼び出しても更新を取得しません。)
新しいブランチを作成すると、Git が新しいラベルを作成し、同じコミットを指すようになるだけです。この新しいブランチがチェックアウトされている間に新しいコミットを作成した場合にのみ、新しいブランチが他のブランチから分岐していることがわかります。
本当の混乱は、ブランチのマージを再び開始したときに始まります。これは主に、Git が「早送りマージ」と呼ぶ奇妙なことによるもので、デフォルトで行われます。2 番目の例を見て、マスターと開発が元の origin/master と origin/develop の場所であると想像してみましょう。
あるブランチを別のブランチにマージするように Git に依頼すると、Git は、それらのブランチの違いをターゲット ブランチに取得するために何をする必要があるかを判断します。master に開発するために加えた変更をマージしたいので、git に次のように伝えます。
$ git checkout master
$ git merge develop
Git はブランチを見て、develop が master よりも数コミット分進んでいることを確認しますが、それ以上に複雑なことは何もありません。そのため、 master ラベルを取得し、develop が指しているコミットに貼り付けるだけで、「早送り」マージを実行します。ミッションは達成され、以前は開発のみだった変更が現在マスターにもあります。
マスターを開発にマージする直前の最初の例のように、各ブランチに追加のコミットが必要な場合は、「もっと複雑な何か」が進行中です。マスターでコミットを行い、次に git チェックアウトを開発し、そこでコミットを行い、マスターを開発にマージするように Git に依頼しました。Git は、ブランチ ラベルを移動するだけで「ごまかす」ことができなくなりました。2 つのブランチからの変更を、その制御下にあるファイルの 1 つの状態に統合する方法を理解する必要があります (現時点では、それが常に可能であると仮定しましょう。これは真実からそれほど離れていません。それができない場合は、マージの競合が発生しますが、これは思ったほど悪くはありません)。
マージ後の新しいコンテンツは、最初のブランチの最後の状態にも、2 番目のブランチの状態にもなりません。そのため、最初の例の上部にあるように、まったく新しいコミットで表す必要があります。Git は、各ブランチからの変更を 1 つの状態にマージして新しい状態を表す「マージ コミット」と呼ばれるものを作成しました。
最後に、Git に常にマージ コミットを作成させることができますが、これは厳密に、技術的に、必要ではありません。コマンドラインでは、フラグ --no-ff を使用してこれを行うことができ、早送りはできません。グラフィカル クライアントには、同じことを行うためのチェックボックスがあります (SourceTree では、現在、「早送りでマージが解決されてもコミットを作成する」というラベルが付けられています)。多くの人 (私を含む) は --no-ff を使用してマージすることを実際に推奨しています。これは、分岐ポインタを移動することが技術的に可能かどうかなどの技術的な問題に関係なく、マージの行為が常に履歴に記録されるためです。