前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Git内部存储原理

Git内部存储原理

作者头像
赵化冰
发布于 2022-08-01 04:33:52
发布于 2022-08-01 04:33:52
73400
代码可运行
举报
运行总次数:0
代码可运行

Git是程序员工作中使用频率非常高的工具,要提高日常的工作效率,就需要熟练掌握Git的使用方法。相对于传统的版本控制系统而言,Git更为强大和灵活,其各种命令和命令参数也非常多,如果不了解Git的内部原理,要把Git使用得顺手的话非常困难。本文将用一个具体的例子来帮助理解Git的内部存储原理,加深对Git的理解,从掌握各种Git命令,以在使用Git进行工作时得心应手。

Git 目录结构

Git的本质是一个文件系统,其工作目录中的所有文件的历史版本以及提交记录(Commit)都是以文件对象的方式保存在.git目录中的。

首先创建一个work目录,并采用git init命令初始化git仓库。该命令会在工作目录下生成一个.git目录,该目录将用于保存工作区中所有的文件历史的历史版本,提交记录,branch,tag等信息。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ mkdir work
$ cd work
$ git init

其目录结构如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
├── branches             不这么重要,暂不用管                    
├── config               git配置信息,包括用户名,email,remote repository的地址,本地branch和remote
|                        branch的follow关系
├── description          该git库的描述信息,如果使用了GitWeb的话,该描述信息将会被显示在该repo的页面上
├── HEAD                 工作目录当前状态对应的commit,一般来说是当前branch的head,HEAD也可以通过git checkout 命令被直接设置到一个特定的commit上,这种情况被称之为 detached HEAD      
├── hooks                钩子程序,可以被用于在执行git命令时自动执行一些特定操作,例如加入changeid
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info                不这么重要,暂不用管
│   └── exclude
├── objects             保存git对象的目录,包括三类对象commit,tag, tree和blob
│   ├── info
│   └── pack
└── refs                保存branch和tag对应的commit
    ├── heads           branch对应的commit
    └── tags            tag对应的commit

Git Object存储方式

目前objects目录中还没有任何内容,我们创建一个文件并提交。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ echo "my project" > README
$ echo "hello world" > src/file1.txt
$ git add .
$ git commit -sm "init commit"
[master (root-commit) b767d71] init commit
 2 files changed, 2 insertions(+)
 create mode 100644 README
 create mode 100644 src/file1.txt

从打印输出可以看到,上面的命令创建了一个commit对象,该commit包含两个文件。 查看.git/objects目录,可以看到该目录下增加了5个子目录 06,3b, 82, b7, ca,每个子目录下有一个以一长串字母数字命令的文件。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.git/objects
├── 06
│   └── 5bcad11008c5e958ff743f2445551e05561f59
├── 3b
│   └── 18e512dba79e4c8300dd08aeb37f8e728b8dad
├── 82
│   └── 424451ac502bd69712561a524e2d97fd932c69
├── b7
│   └── 67d7115ef57666c9d279c7acc955f86f298a8d
├── ca
│   └── 964f37599d41e285d1a71d11495ddc486b6c3b
├── info
└── pack

说明:Git Object目录中存储了三种对象:Commit, tree和blob。Git为对象生成一个文件,并根据文件信息生成一个 SHA-1 哈希值作为文件内容的校验和,创建以该校验和前两个字符为名称的子目录,并以 (校验和) 剩下 38 个字符为文件命名 ,将该文件保存至子目录下。

查看Git Object存储内容

通过 git cat-file命令可以查看Git Object中存储的内容及对象类型,命令参数为Git Object的SHA-1哈希值,即目录名+文件名。在没有歧义的情况下,不用输入整个Hash,输入前几位即可。

当前分支的对象引用保存在HEAD文件中,可以查看该文件得到当前HEAD对应的branch,并通过branch查到对应的commit对象。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat .git/HEAD
ref: refs/heads/master
cat .git/refs/heads/master
b767d7115ef57666c9d279c7acc955f86f298a8d

使用 -t 参数查看文件类型:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -t b767d7
commit

使用 -p 参数可以查看文件内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p b767d7
tree ca964f37599d41e285d1a71d11495ddc486b6c3b
author Huabing Zhao <zhaohuabing@gmail.com> 1548055516 +0800
committer Huabing Zhao <zhaohuabing@gmail.com> 1548055516 +0800

init commit

Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

可以看出这是一个commit对象,commit对象中保存了commit的作者,commit的描述信息,签名信息以及该commit中包含哪些tree对象和blob对象。

b767d7这个commit中保存了一个tree对象,可以把该tree对象看成这次提交相关的所有文件的根目录。让我们来看看该tree对象中的内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p ca964f
100644 blob 065bcad11008c5e958ff743f2445551e05561f59    README
040000 tree 82424451ac502bd69712561a524e2d97fd932c69    src

可以看到该tree对象中包含了一个blob对象,即README文件;和一个tree对象,即src目录。 分别查看该blob对象和tree对象,其内容如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p 065bca
my project
$ git cat-file -p 824244
100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad    file1.txt

查看file1.txt的内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p 3b18e51
hello world

从上面的实验我们可以得知,git中存储了三种类型的对象,commit,tree和blob。分别对应git commit,此commit中的目录和文件。这些对象之间的关系如下图所示。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
HEAD---> refs/heads/master--> b767d7(commit)
                                    +
                                    |
                                    v
                                ca964f(tree)
                                    +
                                    |
                          +---------+----------+
                          |                    |
                          v                    v
                     065bca(blob)         824244(tree)
                          README              src
                                               +
                                               |
                                               v
                                          3b18e5(blob)
                                             file1.txt                                     

Git branch和tag

从refs/heads/master的内容可以看到,branch是一个指向commit的指针,master branch实际是指向了b767d7这个commit。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git checkout -b work
Switched to a new branch 'work'
$ tree .git/refs/
.git/refs/
├── heads
│   ├── master
│   └── work
└── tags
$ cat .git/refs/heads/work .git/refs/heads/master
b767d7115ef57666c9d279c7acc955f86f298a8d
b767d7115ef57666c9d279c7acc955f86f298a8d

上面的命令创建了一个work branch。从其内容可以看到,该branch并没有创建任何新的版本文件,和master一样指向了b767d7这个commit。

从上面的实验可以看出,一个branch其实只是一个commit对象的应用,Git并不会为每个branch存储一份拷贝,因此在git中创建branch几乎没有任何代价。

在work branch上进行一些修改,然后提交。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ echo "new line" >> src/file1.txt
$ echo "do nothing" >> Makefile
$ git commit -sm "some change"
[work 4f73993] some change
 2 files changed, 2 insertions(+)
 create mode 100644 Makefile

查看当前的HEAD和branch内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat .git/HEAD
ref: refs/heads/work
huabing@huabing-xubuntu:~/work$ cat .git/refs/heads/work .git/refs/heads/master
4f73993cf81931bc15375f0a23d82c40b3ae6789
b767d7115ef57666c9d279c7acc955f86f298a8d

可以看到HEAD指向了work branch,而work branch则指向了4f73993这个commit,master branch指向的commit未变化,还是b767d7。

查看4f73993这个commit对象的内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p 4f73993
tree 082b6d87eeddb15526b7c920e21f09f950f78b54
parent b767d7115ef57666c9d279c7acc955f86f298a8d
author Huabing Zhao <zhaohuabing@gmail.com> 1548069325 +0800
committer Huabing Zhao <zhaohuabing@gmail.com> 1548069325 +0800

some change

Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

可以看到commit有一个parent字段,指向了前一个commi b767d7。该commit也包含了一个tree对象,让我们看看其中的内容。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$  git cat-file -p  082b6d
100644 blob 8cc95f278445722c59d08bbd798fbaf60da8ca14    Makefile
100644 blob 065bcad11008c5e958ff743f2445551e05561f59    README
040000 tree 9aeacd1fa832ca167b0f72fb1d0c744a9ee1902f    src

$ git cat-file -p 9aeacd
100644 blob 79ee69e841a5fd382faef2be2f2eb6e836cc980a    file1.txt

可以看到该tree对象中包含了该版本的所有文件和目录,由于README没有变化,还是指向的065bca这个blob对象。Makefile是一个新建的blob对象,src和file1.txt则指向了新版本的对象。

增加了这次commit后,git中各个对象的关系如下图所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
                                          (parent)
HEAD--> refs/heads/work--> 4f7399(commit) +-------> b767d7(commit)<---refs/heads/master
                              +                             +
                              |                             |
                              v                             v
                         082b6d(tree)                   ca964f(tree)
                              +                             +
                              |                             |
               +-----------------------------+     +--------+-----------+
               |              |              |     |                    |
               v              v              v     v                    v
           9aeacd(tree)    8cc95f(blob)    065bca(blob)            824244(tree)
         src (version 2)    Makefile         README               src (version 1)
               +                                                        +
               |                                                        |
               v                                                        v
          79ee69(blob)                                             3b18e5(blob)
        file1.txt (version 2)                                    file1.txt (version 1)

从上图可以看到,Git会为每次commit时修改的目录/文件生成一个新的版本的tree/blob对象,如果文件没有修改,则会指向老版本的tree/blob对象。而branch则只是指向某一个commit的一个指针。即Git中整个工作目录的version是以commit对象的形式存在的,可以认为一个commit就是一个version,而不同version可以指向相同或者不同的tree和blob对象,对应到不同版本的子目录和文件。如果某一个子目录/文件在版本间没有变化,则不会为该子目录/文件生成新的tree/blob对象,不同version的commit对象会指向同一个tree/object对象。

Tag和branch类似,也是指向某个commit的指针。不同的是tag创建后其指向的commit不能变化,而branch创建后,其指针会在提交新的commit后向前移动。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git tag v1.0
$ cat .git/refs/tags/v1.0 .git/refs/heads/work
4f73993cf81931bc15375f0a23d82c40b3ae6789
4f73993cf81931bc15375f0a23d82c40b3ae6789

可以看到新创建的v1.0 tag和work branch都是指向了4f7399这个commit。

Git Stash实现原理

Git stash的功能说明:经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态,而你想转到其他分支上进行一些工作。问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。解决这个问题的办法就是git stash命令。

“‘储藏”“可以获取你工作目录的中间状态——也就是你修改过的被追踪的文件和暂存的变更——并将它保存到一个未完结变更的堆栈中,随时可以重新应用。

Git是如何实现Stash的呢?理解了Commit, Tree, Blog这三种Git存储对象,我们就可以很容易理解Git Stash的实现原理。因为和bransh及tag类似,Git Stash其实也是通过Commit来实现的。

通过实验来测试一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ echo "another line" >> src/file1.txt
$ git stash

通过上面的命令,我们在file1.txt中增加了一行,然后通过git stash命令将这些改动“暂存”在了一个“堆栈”中,让我们来看看.git目录发生了什么变化。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── index
├── info
│   └── exclude
├── logs
│   ├── HEAD
│   └── refs
│       ├── heads
│       │   ├── master
│       │   └── work
│       └── stash
├── objects
│   ├── 06
│   │   └── 5bcad11008c5e958ff743f2445551e05561f59
│   ├── 08
│   │   └── 2b6d87eeddb15526b7c920e21f09f950f78b54
│   ├── 11
│   │   └── a6d1031e4fa2d4da0b6303dd74ed8e85c54057
│   ├── 33
│   │   └── f98923002cd224dabf32222c808611badd6d48
│   ├── 3b
│   │   └── 18e512dba79e4c8300dd08aeb37f8e728b8dad
│   ├── 4f
│   │   └── 73993cf81931bc15375f0a23d82c40b3ae6789
│   ├── 6a
│   │   ├── 1474c4da0653af0245970997b6fab0a0a7c1df
│   │   └── d88760c3be94d8cb582bf2d06b99083d034428
│   ├── 75
│   │   └── e170cc1d928ae5a28547b4a3f2f3394a675b9a
│   ├── 79
│   │   └── ee69e841a5fd382faef2be2f2eb6e836cc980a
│   ├── 82
│   │   └── 424451ac502bd69712561a524e2d97fd932c69
│   ├── 8c
│   │   └── c95f278445722c59d08bbd798fbaf60da8ca14
│   ├── 90
│   │   └── c43dbb1e71c271510994d6b147c425cbffa673
│   ├── 9a
│   │   └── eacd1fa832ca167b0f72fb1d0c744a9ee1902f
│   ├── b7
│   │   └── 67d7115ef57666c9d279c7acc955f86f298a8d
│   ├── ca
│   │   └── 964f37599d41e285d1a71d11495ddc486b6c3b
│   ├── e8
│   │   └── 83e779eb08e2d9bca1fc1ee722fc80addac312
│   ├── info
│   └── pack
├── ORIG_HEAD
└── refs
    ├── heads
    │   ├── master
    │   └── work
    ├── stash
    └── tags
        └── v1.0

可以看到objects目录中增加了一些对象文件,refs中增加了一个stash文件。通过命令查看该文件内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ cat .git/refs/stash
11a6d1031e4fa2d4da0b6303dd74ed8e85c54057
$ git cat-file -p 11a6
tree 90c43dbb1e71c271510994d6b147c425cbffa673
parent 4f73993cf81931bc15375f0a23d82c40b3ae6789
parent 6a1474c4da0653af0245970997b6fab0a0a7c1df
author Huabing Zhao <zhaohuabing@gmail.com> 1548326421 +0800
committer Huabing Zhao <zhaohuabing@gmail.com> 1548326421 +0800

WIP on work: 4f73993 some change
$ git cat-file -p 90c4
100644 blob 8cc95f278445722c59d08bbd798fbaf60da8ca14    Makefile
100644 blob 065bcad11008c5e958ff743f2445551e05561f59    README
040000 tree 33f98923002cd224dabf32222c808611badd6d48    src
$ git cat-file -p 33f9
100644 blob 75e170cc1d928ae5a28547b4a3f2f3394a675b9a    file1.txt
$ git cat-file -p 75e1
hello world
new line
another line

从命令行输出可以看到,git stash实际上创建了一个新的commit对象11a6d1, 该commit对象的父节点为4f7399。commit对象中包含了修改后的file1.txt blob对象75e170。通过git log可以查看:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git log --oneline --graph stash@{0}
*   f566001 WIP on work: 4f73993 some change
|\
| * 0796ced index on work: 4f73993 some change
|/
* 4f73993 some change
* b767d71 init commit

备注:git stash生成的commit对象有两个parent,一个是前面一次git commit命令生成的commit,另一个对应于保存到stage中的commit。

从该试验可以得知,git stash也是以commit,tree和object对象实现的。Git stash保存到“堆栈"中的修改其实一个commit对象。

Git reset 实现原理

在进行一些改动以后并通过git commit 将改动的代码提交到本地的repo后,如果你测试发现刚才的改动不合理,希望回退刚才的改动,应该如何处理?

我们先提交一个错误的改动:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ echo "I did something wrong" >> src/file1.txt
$ git add .
$ git commit -sm "This commit should not be there"
[work ccbc363] This commit should not be there
 1 file changed, 1 insertion(+)

你可以通过git revert回退刚才的改动,或者修改代码后再次提交,但这样的话你的提交log会显得非常凌乱;如果不想把中间过程的commit push到远程仓库,可以通过git reset 回退刚才的改动。

先查看目前的log

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git log
commit ccbc3638142191bd68454d47a0f67fd12519806b
Author: Huabing Zhao <zhaohuabing@gmail.com>
Date:   Fri Jan 25 12:35:31 2019 +0800

    This commit should not be there

    Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

commit 4f73993cf81931bc15375f0a23d82c40b3ae6789
Author: Huabing Zhao <zhaohuabing@gmail.com>
Date:   Mon Jan 21 19:15:25 2019 +0800

    some change

    Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

commit b767d7115ef57666c9d279c7acc955f86f298a8d
Author: Huabing Zhao <zhaohuabing@gmail.com>
Date:   Mon Jan 21 15:25:16 2019 +0800

    init commit

    Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

通过 git reset回退到上一个commit。注意这里HEAD是一个指向当前branch最后一个commit指针,因此HEAD~1表示之前的一个commit。git reset命令也可以直接使用commit号作为命令参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git reset HEAD~1
Unstaged changes after reset:
M       src/file1.txt

$ git log
commit 4f73993cf81931bc15375f0a23d82c40b3ae6789
Author: Huabing Zhao <zhaohuabing@gmail.com>
Date:   Mon Jan 21 19:15:25 2019 +0800

    some change

    Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

commit b767d7115ef57666c9d279c7acc955f86f298a8d
Author: Huabing Zhao <zhaohuabing@gmail.com>
Date:   Mon Jan 21 15:25:16 2019 +0800

    init commit

    Signed-off-by: Huabing Zhao <zhaohuabing@gmail.com>

可以看到刚才的commit被回退了,但修改的文件还存在,处于Unstaged状态,你可以对这些文件进行改动后再次提交。

如果你不想保留修改的文件,可以使用–hard参数直接回退到指定的commit,该参数会将HEAD指向该commit,并且工作区中的文件也会和该comit保持一致,该commit后的修改会被直接丢弃。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git reset HEAD --hard
HEAD is now at 4f73993 some change
$ git status
On branch work
nothing to commit, working directory clean

Git object存储方式

Git object是通过下面的方式处理并存储在git内部的文件系统中的:

  1. 首先创建一个header,header的值为 “对象类型 内容长度\0”
  2. 将header和文件内容连接起来,计算得到其SHA-1 hash值
  3. 将连接得到的内容采用zlib压缩
  4. 将压缩后的内容写入到以 “hash值前两位命令的目录/hash值后38位命令的文件” 中

可以通过Ruby手工创建一个 Git object 来验证上面的步骤。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ irb
irb(main):001:0> content = "what is up, doc?"                     //文件内容
=> "what is up, doc?"
irb(main):002:0> header = "blob #{content.length}\0"              //创建header
=> "blob 16\u0000"
irb(main):003:0> store = header + content                         //拼接header和文件内容
=> "blob 16\u0000what is up, doc?"
irb(main):004:0> require 'digest/sha1'
=> true
irb(main):005:0> sha1 = Digest::SHA1.hexdigest(store)
=> "bd9dbf5aae1a3862dd1526723246b20206e5fc37"                     //计算得到hash值
irb(main):006:0>  require 'zlib'
=> true
irb(main):007:0> zlib_content = Zlib::Deflate.deflate(store)      //压缩header+文件内容 
=> "x\x9CK\xCA\xC9OR04c(\xCFH,Q\xC8,V(-\xD0QH\xC9O\xB6\a\x00_\x1C\a\x9D"
irb(main):008:0>  path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38]
=> ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37"       //通过hash值计算文件存储路径
irb(main):009:0> require 'fileutils'
=> true
irb(main):010:0>  FileUtils.mkdir_p(File.dirname(path))           //写文件
=> [".git/objects/bd"]
irb(main):011:0> File.open(path, 'w') { |f| f.write zlib_content }
=> 32
irb(main):012:0>

文件以及写入到Git的内部存储中,我们尝试通过git cat-file 验证并读取该文件内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ git cat-file -p bd9dbf5aae1a3862dd1526723246b20206e5fc37
what is up, doc?

可以看到,可以通过git cat-file文件读取该文件内容,因此该文件是一个合法的git object,和通过git 命令写入的文件格式相同。

总结

Git围绕三种Object来实现了版本控制以及Branch,Tag等机制。

  • Commit: Commit可以看作Git中一个Version的所有目录和文件的Snapshot,可以通过git checkout 查看任意一个commit中的内容。
  • Tree: 目录对象,内部包含目录和文件
  • Blob: 文件对象,对应一个文件

理解了Git object的存储机制,就可以理解Git的各个命令的实现原理,更好地使用Git来实现源代码管理。

参考


本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
我们随手做的 git stash,究竟干了什么?
git stash 是程序员的至宝。老板 biangbiang 甩来一个 case,说这个要下班之前 hot fix,咋办,stash,切到 release 对应的分支,缝缝补补;产品 kuangkuang 砸来一个需求更新,说这个简单,小哥哥帮帮我先做了,咋办,stash 切一个新的 feature 分支,撸袖子干。如果没有 git stash,人生至少要灰暗一半。
tyrchen
2019/12/02
4470
洞悉技术的本质-Git内部原理探索
洞悉技术的本质,可以让我们在层出不穷的框架面前仍能泰然处之。用了那么久的 Git,不懂点内部原理,那可不行!懂点原理可以让我们遇到问题的时候能够更好更快的理清解决问题的思路。
Cloud-Cloudys
2020/07/06
8030
从一个实战的角度来理解 Git 原理~
我之前写了一篇文章 《深入理解 Git 》https://zhuanlan.zhihu.com/p/71577255。
DevOps时代
2020/11/03
5760
从一个实战的角度来理解 Git 原理~
Git基本概念及操作(3)
如果使用传统的如CC开发的话,刚开始进行GIT开发可能不是太适应。这个主要是有些概念不一样。比喻在CC中,我们一般是围绕一个主分支进行开发,对一个文件来说,在主分支上会生成不同的版本。同样,我们在每一个版本下面创立新的次分支,在次分支上也会生出很多版本。最后合到主分支,产生下一个版本。那么在GIT中是如何实现这些关联呢?GIT中同样有分支、版本概念。但是没有Configspec概念。tag概念同LABEL概念类似。当然这些概念都同GIT中是如何管理文件版本相关的。首先我们来看GIT是如何将文件对象化管理的,前面我们说GIT同其它版本管理系统不一样是GIT每个版本都不是保存变更,而是全保存。那么如果全保存的话,显然会带来相当大的硬盘开销,其弊端非常明显,那么GIT是怎么消除这个弊端的呢?GIT利用了HASH算法,我们知道在目前已知道的算法中,HASH(SHA-1)算法产生的唯一性还是非常强的。也就是说虽然在工作区域是一个普通文件,但是在仓库中保存的是一个HASH值,由这个HASH值来表示文件,自然空间节省很多。GIT中将这个HASH值称之为对象。这些对象通常是由提交版本、子目录、文件的HASH值组成。对每一个对象通常按类型、大小和内容进行管理。其中最主要的是类型分为三种:
py3study
2020/01/09
8630
git底层原理,从常见操作解释git的底层原理,再也不怯
每个开发者拥有自己仓库的写权限和其他所有人仓库的读权限。这种情形下通常会有个代表“官方”项目的权威的仓库。
公众号 IT老哥
2021/01/12
2.7K0
三分钟上手!一文看懂 Git 的底层工作原理
Git 的本质是一个文件系统(很重要,记住这句话,理解这句话),工作目录中的所有文件的历史版本以及提交记录(commit)都是以文件对象的方式保存在 .git 目录中的。
飞天小牛肉
2023/08/26
6530
三分钟上手!一文看懂 Git 的底层工作原理
用了5年的Git,你竟然还不晓得它的实现原理!
作者 | 杨夕 来源 | https://zhuanlan.zhihu.com/p/53750883 越了解事物的本质就越接近真相。我发现学习Git内部是如何工作的以及Git的内部数据结构这部分内容,对于理解Git的用途和强大至关重要。若你理解了Git的思想和基本工作原理,用起来就会知其所以然,游刃有余。这是Git系列的第一篇,主要会介绍Git的特点以及内部数据结构设计,和完成一次完整提交流程的时候数据是如何变化的。 Git有什么特点? fast,scalable,distributed revision
程序猿DD
2023/04/04
2820
用了5年的Git,你竟然还不晓得它的实现原理!
10.2 Git 内部原理 - Git 对象
Git 是一个内容寻址文件系统。 看起来很酷, 但这是什么意思呢? 这意味着,Git 的核心部分是一个简单的键值对数据库(key-value data store)。 你可以向该数据库插入任意类型的内容,它会返回一个键值,通过该键值可以在任意时刻再次检索(retrieve)该内容。 可以通过底层命令 hash-object 来演示上述效果——该命令可将任意数据保存于 .git 目录,并返回相应的键值。 首先,我们需要初始化一个新的 Git 版本库,并确认 objects 目录为空:
shaonbean
2019/05/26
7610
聊聊Git原理
说起Git,相信大家都很熟悉了,毕竟作为程序猿,每天的业余时间除了吃饭睡觉就是逛一下全世界最大的开(tong)源(xing)代(jiao)码(you)网站GitHub了。在那里Git是每个人所要具备的最基本的技能。今天我们不聊Git的基本应用,来聊一聊Git的原理。<!-- more -->
Jackeyzhe
2020/03/11
3910
这才是真正的Git——Git内部原理揭秘!
本文作者:lzaneli,腾讯 TEG 前端开发工程师 本文以一个具体例子结合动图介绍了Git的内部原理,包括Git是什么储存我们的代码和变更历史的、更改一个文件时,Git内部是怎么变化的、Git这样实现的有什么好处等等。 通过例子解释清楚上面这张动图,让大家了解Git的内部原理。如果你已经能够看懂这张图了,下面的内容可能对你来说会比较基础。 视频链接: https://www.bilibili.com/video/av77252063 PPT 链接: https://www.lzane.com/
腾讯技术工程官方号
2019/12/18
1.5K0
这才是真正的Git——Git内部原理揭秘!
Git内部原理介绍
git 是一个内容寻址的文件系统,其核心部分是一个简单的键值对数据库(key-value data store),可以向该数据库插入任意类型的内容,它会返回一个40位长的哈希键值。并在此基础上提供了一个版本控制系统的用户界面。
腾讯工蜂
2018/12/07
17.1K1
Git的存储原理
Git 出现前,主流版本控制系统(SVN...)一般为基于增量(delta-based)的系统,如下图:
小江的学习日记
2024/07/27
730
Git基本操作(超详细)
.git ⽬录是Git来跟踪管理仓库的,不要⼿动修改这个⽬录⾥⾯的⽂件,不然改乱了,就把Git仓库给破坏了
南桥
2024/02/20
1.1K0
Git基本操作(超详细)
这才是真正的Git——Git内部原理
linux 之父 Linus Torvalds 大家应该都知道,而 git 也是由 Linus 开发的。从 1991 年发布了第一版的 linux 内核,Linux 内核开源项目有着众多的参与者,但绝大多数的 Linux 内核维护工作都花在了提交补丁和保存归档的繁琐事务上(1991-2002年间)。到 2002 年,整个项目组开始启用一个专有的分布式版本控制系统 BitKeeper 来管理和维护代码,之前市面上也有其他的版本管理系统,比如 CSV、SVN,但是 Linus 觉得它们很蠢,直到有了 BitKeeper 才开始使用版本管理系统。
前端森林
2021/06/25
3K0
这才是真正的Git——Git内部原理
Git 原理入门
即使天天使用它,很多人也未必了解它的原理。Git 为什么可以管理版本?git add、git commit这些基本命令,到底在做什么,你说得清楚吗?
ruanyf
2018/10/11
7120
Git 原理入门
10.3 Git 内部原理 - Git 引用
我们可以借助类似于 git log 1a410e 这样的命令来浏览完整的提交历史,但为了能遍历那段历史从而找到所有相关对象,你仍须记住 1a410e 是最后一个提交。 我们需要一个文件来保存 SHA-1 值,并给文件起一个简单的名字,然后用这个名字指针来替代原始的 SHA-1 值。
shaonbean
2019/05/26
8640
一篇搞懂Git 和 SVN 的区别【原理篇】
Git和SVN都是版本管理系统,但是他们 命令区别后面会简单进行一个对比,我们先从原理的角度分析
火狼1
2022/03/22
2.7K0
一篇搞懂Git 和 SVN 的区别【原理篇】
Git原理入门简析
Git 是当前流行的分布式版本控制管理工具,最初由 Linux Torvalds (Linux 之父) 创造,于 2005 年发布。
我没有三颗心脏
2019/08/19
4500
10.7 Git 内部原理 - 维护与数据恢复
有的时候,你需要对仓库进行清理 - 使它的结构变得更紧凑,或是对导入的仓库进行清理,或是恢复丢失的内容。 这个小节将会介绍这些情况中的一部分。
shaonbean
2019/05/26
8410
Git Pro深入浅出(三)
前面已经阐述了Git基本的运作机制和使用方式,介绍了许多Git提供的工具来帮助你简单且有效地使用它。本部分将演示如何借助Git的一些重要的配置方法和钩子机制,来满足自定义的需求。
奋飛
2019/08/15
8850
相关推荐
我们随手做的 git stash,究竟干了什么?
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文