#Git原理の簡単な理解

13286 ワード

総説:Gitは根本的にコンテンツアドレス(content-addressable)ファイルシステムであり、その上にVCSユーザーインタフェースを提供している.
-
操作によって一歩一歩理解する
1.ファイルディレクトリ構造を表示するためのtreeツールをインストールし、Gitの学習理解に役立ちます.
brew install tree

インストール後、任意のディレクトリの下にtreeコマンドを入力すると、ディレクトリがツリー構造で表示され、階層関係が一目瞭然になります.
2.クリーンなフォルダを新規作成し、ls -aコマンドを実行してすべてのファイル(非表示ファイルを含む)を表示します.2つのファイルが表示されます.
.  ..

現在のファイルの上位ディレクトリに戻りたい場合、通常はcd ..コマンドが使用されますが、ここには..という隠しファイルがあるので、..は実は上位ディレクトリの識別ファイルであると理解できます.
3.現在のディレクトリでgit initコマンドを実行し、ls -aでファイルの状況を確認します.
.    ..   .git

隠しファイル.gitが1つ多く出てきて、すべてのGitが格納して操作した内容がこのディレクトリの下にあります.ライブラリをバックアップまたはコピーする場合は、基本的にこのディレクトリを他の場所にコピーすればいいです.
4.cdは.gitファイルに入り、treeコマンドで現在のディレクトリ構造を表示します.いくつかのファイルの大まかな役割について簡単な注釈をしました.次に重点的に展開するファイルには、*番号のタグを付けました.
$ tree
.
├── HEAD                //*           ,        
├── config              //         
├── description         //   GitWeb     ,    
├── hooks               //           
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── info
│   └── exclude
├── objects             //*         
│   ├── info
│   └── pack
└── refs                //*        (  )         ,        
    ├── heads
    └── tags

8 directories, 14 files

5.git addの操作を理解する:開発プロセスをシミュレートし、あなたのプロジェクトディレクトリの下で新しいファイルを作成します.ここではREADME.mdを例に挙げます.作成後、ファイルに任意の内容を書き込み、git add .操作を実行します.このとき、.gitディレクトリに入り、treeコマンドを実行します.
$ tree
.
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── objects
│   ├── d0
│   │   └── d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 16 files
objectsディレクトリの下に多くのものが出ていることがわかります.これは私たちのさっきのgit add .操作によって生成されました.では、これらの書類は何を表していますか.実はこのファイルはGitがコンテンツごとに生成したファイルで、そのコンテンツとヘッダ情報のSHA-1チェックサムを取得し、そのチェックサムの最初の2文字を名前とするサブディレクトリを作成し、残り38文字をファイル名として(サブディレクトリの下に保存する).簡単に言えばgitはアルゴリズムによって私たちが提出した内容を計算して一連の数字を得て、それから数字の上位2桁を1つのディレクトリ名として、残りの文字列をファイル名とします.ファイルの内容を確認します.cat-fileコマンドを使用できます.このコマンドはGitオブジェクトのスイス軍刀を表示します.転送-pパラメータは、このコマンドにデータの内容のタイプを出力させることができます.完全なファイル名はディレクトリ名+ファイル名であることに注意してください.
$ git cat-file -p d0d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1
#GitTest

私たちが追加した内容はこのファイルに保存されています.
6.git commitを理解する:操作したばかりの上で、git commit -mの操作を実行し、同様に.gitのディレクトリ構造を観察し、私が提出した説明は「.
$ tree
.
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects
│   ├── 5f
│   │   └── 3a2c5612b3687a8963fe76e46305b0c7ba5724
│   ├── cf
│   │   └── 0359c6428293e0b717f02292ef191ccc590592
│   ├── d0
│   │   └── d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

14 directories, 22 files
objectsディレクトリには2つのファイルが追加されています.
$ git cat-file -p 5f3a2c5612b3687a8963fe76e46305b0c7ba5724
tree cf0359c6428293e0b717f02292ef191ccc590592
author liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503989030 +0800
committer liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503989030 +0800

first commit

この書類の内容は、私たちのgit commit -mの説明情報です.彼はtree cf0359c6428293e0b717f02292ef191ccc590592を持っていることに注意してください.これは今回提出したプロジェクトのルートディレクトリを指しています.どういう意味か見てみましょう.
$ git cat-file -p cf0359c6428293e0b717f02292ef191ccc590592
100644 blob d0d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1    GitTestREADME.md

私たちがcommitを行う場合、プロジェクトディレクトリのファイルの存在状況は1つのファイルGitTestREADME.mdしかないので、指定されたバージョンのコードロールバックを行うと、この値に基づいて当時のルートディレクトリのファイルの存在状態を戻します.残りのファイルは何ですか.
$ git cat-file -p cf0359c6428293e0b717f02292ef191ccc590592
100644 blob d0d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1    GitTestREADME.md

これが、commit記述ファイルで発見されたルートディレクトリを指すファイルです.
7.新しいファイルを追加し続け、git add.git commit -mの操作をもう一度実行します.1つのコマンドが指示されたら、.gitファイルの変化状況を観察します.ここでは最終的な結果状態をリストします.プロセスは省略します.
$ tree
.
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       └── heads
│           └── master
├── objects
│   ├── 58
│   │   └── 7a55b8f052d0a74bd592ffe7c8c5ff8ccc06c5
│   ├── 5f
│   │   └── 3a2c5612b3687a8963fe76e46305b0c7ba5724
│   ├── 92
│   │   └── a36d18afcce6bdda094c8360551051695fc842
│   ├── c9
│   │   └── c50f0b74a03f5be47d97770a2d11e23983d425
│   ├── cf
│   │   └── 0359c6428293e0b717f02292ef191ccc590592
│   ├── d0
│   │   └── d37ed92ba0227dc7c3b9a5cb2a8bfa6a04a6f1
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

17 directories, 25 files

3つ以上のファイルが出てきて、ファイルの内容を手に入れると、以前の最初のファイルに保存されていたものと同じものが見えます.1つはgit addが提出した内容で、1つはgit commit -mの内容で、1つは現在のルートディレクトリです.注意しなければならないのは、このgit commit -mの内容が保存されているディレクトリで、それは最初のcommitといくつかの違いがあります.
$ git cat-file -p 92a36d18afcce6bdda094c8360551051695fc842
tree 587a55b8f052d0a74bd592ffe7c8c5ff8ccc06c5
parent 5f3a2c5612b3687a8963fe76e46305b0c7ba5724
author liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503991626 +0800
committer liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503991626 +0800

second commit
parent 5f3a2c5612b3687a8963fe76e46305b0c7ba5724が1つ増えて、字面からどういう意味か理解することができて、その前のcommitを指して、前のノードと理解することができて、証明することができます:
$ git cat-file -p 5f3a2c5612b3687a8963fe76e46305b0c7ba5724
tree cf0359c6428293e0b717f02292ef191ccc590592
author liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503989030 +0800
committer liuyiyi <liuyiyi@lyydeMacBook-Pro.local> 1503989030 +0800

first commit

最初のcommitは親ノードがないのでparentはありませんが、その後のcommitは親ノードがあるのでparentという行があります.
8.振り返ってHEAD、refsの2つのファイルについて話します.HEADは現在のブランチを指していることはよく知られていますが、それはどのように指しているのか、彼の内容を見てみるとわかります.HEADは本質的に1つのファイルです!以上のものはすべてファイルです!!
vim HEAD


ref: refs/heads/master

HEADの内容はファイルパスなので、HEADが現在のブランチを指しているのではなく、ファイルのパスを指しています.このファイルパスに基づいてファイルの内容を見てみましょう.
vim refs/heads/master

92a36d18afcce6bdda094c8360551051695fc842

このパスの下のファイルの内容は、2回目のcommitのファイル名なので、正確には、このファイルは現在のブランチの現在のcommitを指していますが、HEADファイルの内容はこのファイルです.ファイルがロールバック操作を行うと、refs/heads/masterのファイルの値が変更され、ロールバックしたcommitになります.
9.新しいブランチdevelopを作成し、.gitファイルディレクトリの変化を観察する.
└── refs
    ├── heads
    │   ├── develop
    │   └── master
    └── tags

refs/headersの下にdevelopというファイルが1つ増えていることがわかります.developファイルの内容を取得し、masterの2回目のcommitコンテンツのファイルを指します.
vim refs/heads/develop

92a36d18afcce6bdda094c8360551051695fc842

したがって、現在のブランチに基づいて新しいブランチを作成するのは、本質的には1つのファイルだけであり、このファイルの内容は、分割が作成されたときに最新のcommitを指すだけです.ブランチを作成するコストは非常に小さいです.
10.この時点でブランチがdevelopに切り替わると、HEADの変化が観察され、HEADコンテンツがどのように変化し、ファイルコンテンツがrefs/heads/developとなる経路、すなわち現在のブランチdevelopを指すかが推測される.