ホームページ  >  記事  >  コンピューターのチュートリアル  >  Git のコミットは差分、スナップショット、または履歴ですか?

Git のコミットは差分、スナップショット、または履歴ですか?

PHPz
PHPz転載
2024-02-19 11:39:421055ブラウズ

Git 提交是差异、快照还是历史记录?

Git コミットがどのように実装されるかを理解するのは簡単ですが、送信に対する他の人の意見を理解するのは困難です。そこで私はマストドン上の他の人にいくつかの質問をしてみました。

Git の提出についてどう思いますか?

私は非常に非科学的な調査を実施し、人々に Git のコミットについてどう思うか尋ねました。それはスナップショットでしょうか、差分でしょうか、それとも以前のすべてのコミットのリストでしょうか? (もちろん、この 3 つすべてであると考えるのが合理的ですが、人々のメインの

が気になります。 ###消す:###

51%の差
  • 42% スナップショット
  • 4% 以前のすべてのコミットの履歴
  • 3%「その他」
  • 差分とスナップショットの 2 つのオプションの比率が非常に近いことに驚きました。また、
「私の意見では、コミットは diff ですが、実際にはスナップショットとして実装されていると思います」や

「私の意見では、コミットはスナップショットですが、実際には diff として実装されていると思います。」送信が実際にどのように実装されるかについては、後ほど詳しく説明します。

先に進む前に: 「違い」または「スナップショット」とは何を意味しますか?

#########違いはなんですか?

私が話している「違い」はおそらく非常に明白です。違いは、git show COMMIT_ID を実行したときに得られるものです。たとえば、rbspy プロジェクトのタイプミスの修正は次のとおりです: リーリー

GitHub でご覧いただけます: https://github.com/rbspy/rbspy/commit/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b

スナップショットとは何ですか?

「スナップショット」とは、「git checkout COMMIT_ID を実行したときに取得されるすべてのファイル」のことです。

Git は通常、送信されたファイルのリストを「ツリー」(「ディレクトリ ツリー」など) として参照します。上記で送信されたすべてのファイルは GitHub で確認できます:

https://github.com/rbspy/rbspy/tree/24ad81d2439f9e63dd91cc1126ca1bb5d3a4da5b (/commit/

ではなく

/tree/

です)

「Git の実装方法」は本当にそれを説明する正しい方法でしょうか?

Git の学習に関して私が最もよく聞くアドバイスは、おそらく「Git が内部的に物事をどのように表現するかを学べば、すべてがより明確になります。」です。私は明らかにこの視点がとても好きです (このブログを時間をかけて読んだことがある方なら、私が が好きであることがお分かりいただけると思います) しかし、Git の学習方法としては、私が期待していたほど成功しませんでした。いつもなら、「なるほど、Git コミットはスナップショットで、親コミットへのポインタがあり、ブランチはコミットへのポインタで、そして…」と興奮気味に説明を始めるところですが、People を試してみました。助けてくれた人は、この説明はあまり役に立たなかった、まだ理解できないと言うでしょう。そこで、他の選択肢を検討してきました。

しかし、最初に内部実装について話しましょう。


Git が内部的にコミットを表す方法 - スナップショット

内部的には、Git はコミットをスナップショット (各ファイルの現在のバージョンの「ツリー」を保存する) として表します。 Git リポジトリにいます。ファイルはどこにありますか?これについては で書きましたが、ここでは内部フォーマットの概要を簡単に説明します。 これは提出表現です: リーリー

そして、このツリー オブジェクトを表示すると、このコミットのリポジトリのルートにあるすべてのファイル/サブディレクトリのリストが表示されます。 リーリー

これは、Git コミットのチェックアウトが常に高速であることを意味します。Git にとって、100 万件前のコミットをチェックアウトするのと同じくらい簡単に、昨日のコミットをチェックアウトできます。コミットは差分としてまったく保存されないため、Git は現在の状態を判断するために 10,000 の差分を再適用する必要はありません。

スナップショットはpackfileを使用して圧縮されます

Git のコミットはスナップショットであると述べましたが、「私の意見では、コミットはスナップショットですが、実装の違いだと思います」という人は
、これも実際に当てはまります。 Git
のコミットは、慣れ親しんだ diff の形式では表現されません (前のコミットとの差分としてディスクに保存されません)。しかし、基本的な直観としては、 10,000## 行 # のファイルが 500 回編集された場合、500 個のファイルを保存する効率は非常に低くなります。

Git には、差分の形式でファイルを保存する方法があります。これは「パックファイル」と呼ばれ、Git はディスク領域を節約するために、データをパックファイルに定期的にガベージ コレクションします。リポジトリを

git clone すると、Git はデータも圧縮します。

ここでは、パックファイルがどのように機能するかを完全に説明するのに十分なスペースがありません (Aditya Mukerjee の「Git パックファイルの解凍」は、パックファイルがどのように機能するかを説明する私のお気に入りの記事です)。ただし、デルタがどのように機能するか、およびデルタが diff とどのように異なるかについての私の理解をここで簡単に要約できます:

    オブジェクトは「元のファイル」および「デルタ」への参照として保存されます
  • デルタは、「バイト 0 ~ 100 を読み取り、次にバイト「hello there」を挿入し、バイト 120 ~ 200 を読み取る」などの一連の命令です。元のファイルから新しいテキストをつなぎ合わせます。したがって、「削除」という概念はなく、コピーして追加するだけです。
  • ミュータンスのレイヤーが少ないと思います: Git が特定のオブジェクトを取得するために通過する必要があるミュータンスのレイヤーが何層あるかを確認する方法はわかりませんが、私の印象では、通常はそれほど多くはありません。たぶん10階未満でしょうか?とはいえ、実際に調べる方法を知りたいです。
  • 元のファイルは前のコミットのものである必要はなく、何でも構いません。もしかしたら、後のコミットからのものかもしれませんか?よくわかりません。
  • 変更を計算するための「正しい」アルゴリズムはありません。Git にはいくつかの近似ヒューリスティックがあるだけです

差分を見ると実際に何か奇妙なことが起こっています

特定のコミットの差分を確認するために

git show SOME_COMMIT を実行すると実際に何が起こるかは、少し直感に反します。私の理解は次のとおりです:

Git はパックファイルを調べ、変更を適用して、このコミットとその親コミットのツリーを再構築します。
  • Git は 2 つのディレクトリ ツリー (現在のコミットのディレクトリ ツリーと親コミットのディレクトリ ツリー) 間の差分比較を実行します。ほとんどすべてのファイルがまったく同じであるため、これは通常高速です。そのため、git はほとんど何もせずに同一ファイルのハッシュを比較するだけで済みます。
  • 最後に Git で違いが表示されます
  • したがって、Git は変更をスナップショットに変換し、差分を計算します。差のようなもので始まり、別の違いのようなもので終わるので、少し奇妙に感じますが、変化の量と差は実際にはまったく異なるため、意味はあります。

    そうは言っても、Git はコミットをスナップショットとして保存し、packfile はディスク領域を節約し、クローン作成を高速化するための実装の詳細にすぎないと思います。実際に Packfile がどのように機能するかを知る必要はありませんでしたが、ディスク容量をあまり消費せずに Git スナップショットがどのようにコミットされるかを理解するのに役立ちます。

    #Git の「間違った」理解: コミットは差分である Git の「エラー」については、次のような理解が一般的だと思います。

    コミットは、前のコミット (および親コミット、作成者、およびメッセージへのポインター) に基づく差分として保存されます。
    • コミットの現在の状態を取得するには、Git は以前のすべてのコミットを最初から再適用する必要があります。
    • この理解はもちろん間違っています (実際には、コミットはスナップショットの形式で保存され、差分はこれらのスナップショットから計算されます)。しかし、これは非常に便利で、私にとっては理にかなっています。マージ コミットについて考えると少し奇妙ですが、これはマージ コミットの最初の親コミットに基づく違いに過ぎないと言えるかもしれません。

    この誤解は時には非常に役立つと思いますが、Git を日常的に使用する上では問題ないようです。私たちが最もよく使うもの (違い) が最も基本的な要素になることがとても気に入っています。私にとっては非常に直感的です。

    私はまた、次のような、Git についての有益だが「間違った」理解についても考えてきました。

      コミット情報は編集できます (実際には編集できません。同一のコミットをコピーして新しい情報を与えるだけです。古いコミットはまだ存在します)
    • コミットは別のベースに移動できます (同様に、コピーされます)
    Git にはさまざまな「間違った」理解があると思いますが、それらは完全に理にかなっていて、主に Git ユーザー インターフェイスでサポートされており、ほとんどの場合問題は発生しません。しかし、変更を元に戻したい場合や何か問題が発生した場合は、混乱する可能性があります。

    コミットを差分として扱うことのいくつかの利点

    Git ではコミットがスナップショットであるとわかっていても、おそらくほとんどの場合、コミットを差分として扱います。理由は次のとおりです。

      ほとんどの場合、私は加えている変更に集中します。コード行を変更するだけの場合、明らかに、コードベース全体の現在の状態ではなく、そのコード行について主に考えています
    • GitHub で Git コミットをクリックするか、
    • git show を使用すると、違いがわかります。これは私が見慣れているものです
    • 私はリベースをよく使いますが、重要なのは差分を再適用することです

    コミットをスナップショットとして扱うことのいくつかの利点

    しかし、私は時々コミットをスナップショットと考えることもあります。理由は次のとおりです。

      Git は、ファイルの移動によって混乱することがよくあります。ファイルを移動して編集すると、Git はそれが移動されたことを認識せず、代わりに
    • として表示されます。 「old.py が削除され、new.py が追加されました」。これは、Git はスナップショットのみを保存するためで、「Move old.py -> new.py」と表示された場合は、
      old.pyとnew.pyの内容は似ているので現時点では推測の域を出ません。
    • こうすることで、
    • git checkout COMMIT_ID が何をしているのかを理解しやすくなります (10,000 のコミットを再適用するという考えはストレスになります)
    • マージされたコミットは実際には何でも構いません (単なる新しいスナップショットです!) ので、私にとってマージ コミットはスナップショットのように見えます。これは、マージ競合を解決するときになぜ恣意的な変更が行われる可能性があるのか​​、また競合を解決するときになぜ注意が必要なのかを理解するのに役立ちました。

    提出に関するその他の理解

    マストドンの返信の一部では次のようなことも言及されています:

      コミットに関する「追加の」アウトオブバンド情報 (電子メール、GitHub プル リクエスト、同僚との会話など)
    • 「違い」を「前の状態、後の状態」と考えてください。
    • そしてもちろん、多くの人は状況に応じて提出物を異なる見方をします
    • コミットについて話すときに人々が使用する、それほど曖昧ではないかもしれない他の言葉:

    「リビジョン」 (スナップショットのように見えます)
    • 「パッチ」 (差分のように見えます)
    • #########それでおしまい!

    私は、人々が Git に対して持っているさまざまな理解を理解するのに苦労しています。特に厄介なのは、「間違った」理解が非常に役立つことが多いにもかかわらず、人々は「間違った」メンタル モデルを警戒することに熱心で、一部の Git インタプリタが立ち上がり、なぜ間違っているのかを彼らに説明してください。 (これらの Git インタプリタは通常、良い意味を持ちますが、それに関係なくマイナスの影響を与える可能性があります) でも、たくさんのことを学びました!コミットについてどのように話すべきかはまだ完全にはわかりませんが、最終的にはわかるでしょう。

    Git コミットについて私と議論してくれた Marco Rogers 氏、Marie Flanagan 氏、そして Mastodon の皆さんに感謝します。

    以上がGit のコミットは差分、スナップショット、または履歴ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    声明:
    この記事はmryunwei.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。