web-dev-qa-db-ja.com

GitコミットIDとは何ですか?

GitコミットIDは、コミットを一意に識別するためにどのように生成されますか?

例:521747298a3790fde1710f3aa2d03b55020575aa

どのように機能しますか?それらは各プロジェクトでのみ一意ですか?または、世界中のGitリポジトリの場合?

30
Ankur Loriya

GitコミットIDは、コミットに関するすべての重要なものの SHA-1ハッシュ です。それらをすべてリストするつもりはありませんが、ここに重要なものがあります...

  • 内容だけでなく、差分だけではありません。
  • コミット日。
  • コミッターの名前とメールアドレス。
  • ログメッセージ。
  • 前のコミットのID。

そのいずれかを変更すると、コミットIDが変更されます。そして、はい、同じプロパティを持つ同じコミットは、異なるマシン上で同じIDを持ちます。これには3つの目的があります。まず、コミットが改ざんされているかどうかをシステムが判断できることを意味します。アーキテクチャに直接組み込まれています。

第二に、IDを見るだけでコミットを迅速に比較できます。これにより、Gitのネットワークプロトコルは非常に効率的になります。 2つのコミットを比較して、それらが同じかどうかを確認したいですか?差分全体を送信する必要はなく、IDを送信するだけです。

第三に、これは天才です。同じIDを持つ2つのコミットは同じ履歴を持ちます。これが、以前のコミットのIDがハッシュの一部である理由です。コミットの内容が同じで、親が異なる場合、コミットIDは異なる必要があります。つまり、リポジトリを比較するとき(プッシュやプルなど)、Gitが2つのリポジトリ間で共通のコミットを見つけると、チェックを停止できます。これにより、プッシュとプルが非常に効率的になります。例えば...

Origin
A - B - C - D - E [master]

A - B [Origin/master]

git fetch Originのネットワーク会話は次のようになります...

  • localちょっとオリジン、あなたはどんなブランチを持っていますか?
  • Origin私はEにマスターがいます.
  • local私にはEがなく、Bにあなたのマスターがいます。
  • Origin Bあなたが言う?私にはBがあり、それはEの祖先です。 C、D、Eをお送りします。

これが、rebaseでコミットを書き換えた場合、それ以降はすべて変更する必要があるためです。以下に例を示します。

A - B - C - D - E - F - G [master]

ログメッセージを少し変更するために、Dを書き換えたとします。これでDはDでなくなるため、D1を呼び出す新しいコミットにコピーする必要があります。

A - B - C - D - E - F - G [master]
         \
          D1

D1はCを親として持つことができますが(Cは影響を受けず、コミットは子を認識しません)、E、F、Gから切断されます。Eの親をD1に変更すると、EはEになりません。新しいコミットE1にコピーする必要があります。

A - B - C - D - E - F - G [master]
         \
          D1 - E1

FからF1、GからG1のように続きます。

A - B - C - D - E - F - G
         \
          D1 - E1 - F1 - G1 [master]

それらはすべて同じコードを持ち、異なる親(またはD1の場合は異なるコミットメッセージ)だけを持ちます。

42
Schwern

実行することにより、コミットIDの作成に何が入るかを正確に確認できます。

git cat-file commit HEAD

それはあなたに何かを与えるでしょう

tree 07e239f2f3d8adc12566eaf66e0ad670f36202b5
parent 543a4849f7201da7bed297b279b7b1e9a086a255
author Justin Howard <[email protected]> 1426631449 -0700
committer Justin Howard <[email protected]> 1426631471 -0700

My commit message

それはあなたに与えます:

  1. ツリーの内容のチェックサム
  2. 親コミットID(これがマージの場合、さらに親が存在します)
  3. タイムスタンプ付きのコミットの作成者
  4. タイムスタンプ付きのコミットのコミッター
  5. コミットメッセージ

Gitはこれをすべて実行し、sha1ハッシュを実行します。実行することでコミットIDを再現できます

(printf "commit %s\0" $(git cat-file commit HEAD | wc -c); git cat-file commit HEAD) | sha1sum

これは、文字列commitの後にスペースとcat-fileテキストブロブのバイトカウントが続くことから始まります。次に、cat-file blobを追加し、その後にヌルバイトを追加します。これらはすべてsha1sumを介して実行されます。

ご覧のとおり、この情報にはプロジェクトまたはリポジトリを識別するものは何もありません。これが問題を引き起こさない理由は、2つの異なるコミットハッシュが衝突する可能性が天文学的に低いためです。

20
Justin Howard