当前位置: 首页 > news >正文

网站备案服务内容一个人网站开发

网站备案服务内容,一个人网站开发,北京清控人居建设集团网站,重庆网络推广培训Git 是目前最流行的版本控制系统#xff0c;从本地开发到生产部署#xff0c;我们每天都在使用 Git 进行我们的版本控制#xff0c;除了日常使用的命令之外#xff0c;如果想要对 Git 有更深一步的了解#xff0c;那么研究下 Git 的底层存储原理将会对理解 Git 及其使用非…Git 是目前最流行的版本控制系统从本地开发到生产部署我们每天都在使用 Git 进行我们的版本控制除了日常使用的命令之外如果想要对 Git 有更深一步的了解那么研究下 Git 的底层存储原理将会对理解 Git 及其使用非常有帮助就算你不是一个 Git 开发者也推荐你了解下 Git 的底层原理你会对 Git 的强大有一个全新的认识并且将会在日常的 Git 使用过程中更加得心应手。 这篇文章面向的读者主要是对 Git 有一定的了解的群体并不会介绍具体 Git 的作用及其使用也不会介绍与其它版本控制系统如 Subversion 之间的差异主要是介绍下 Git 的本质以及他的存储实现的相关原理旨在帮助 Git 使用者更加清晰的了解在使用 Git 进行版本控制的时候其内部实现。 Git 本质是什么 Git 本质上是一个内容寻址的 Key-Value 数据库我们可以向 Git 仓库内插入任意类型的内容Git 会返回给我们一个唯一的键值可以通过这个键取出当时我们插入的值我们可以通过底层命令git hash-object命令来尝试 ➜  Zoker git:(master) ✗ cat testfile Hello Git ➜  Zoker git:(master) ✗ git hash-object testfile -w 9f4d96d5b00d98959ea9960f069585ce42b1349a 可以看到我们目录下有一个名为testfile的文件内容是Hello Git! 我们使用git hash-object命令将这个文件的内容写入到 Git 仓库-w 选项告诉 Git 把这个内容写到 Git 的.git/objects对象数据库目录并且 Git 返回了一个 SHA 值这个 SHA 值就是后续我们要取出这个文件的键值 ➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a Hello Git 我们使用了git cat-file命令取回刚刚存入到 Git 仓库的内容虽然不像 Redis 的命令 get set 那么直观但是它确实是一个 KV 数据库不是吗 我们刚刚尝试插入的这种数据是基础的blob类型的对象Git 还有其它如 tree、commit 等对象类型这些不同的对象类型之间有特定的关联关系它们将不同的对象有逻辑的关联起来才能够帮我们进行不同版本的控制和检出。稍后会展开讲解这几种不同的对象类型我们先来了解下 Git 的目录结构看看在 Git 中数据是如何存放的。 Git 目录结构 通过上一节的介绍我们知道了 Git 本质就是一个 KV 数据库而且还提到了内容都是写到 .git/objects对象目录那么这个目录放在哪里Git 又是如何存储这些数据的呢本节我们重点介绍一下 Git 的存储目录结构了解下 Git 是如何存放不同类型的数据的。 更详细的介绍参见https://github.com/git/git/blob/master/Documentation/gitrepository-layout.txt 通过 git init 我们可以在当前目录初始化一个空的 Git 仓库Git 会自动生成 .git 目录这个 .git 目录就是后续所有的 Git 元数据的存储中心我们来看一下它的目录结构 ➜  Zoker git init Initialized empty Git repository in /Users/zoker/tmp/Zoker/.git/ ➜  Zoker git:(master) ✗ tree .git .git ├── HEAD              // 是一个符号引用指明当前工作目录的版本引用信息我们平时执行 checkout 命令时就会改变 HEAD 的内容 ├── config             // 配置当前存储库的一些信息如Proxy、用户信息、引用等此处的配置项相对于全局配置权重更高 ├── description      // 仓库描述信息 ├── hooks             // 钩子目录执行 Git 相关命令后的回调脚本默认会有一些模板 │   ├── update.sample │   ├── pre-receive.sample │   └── ... ├── info                // 存储一些额外的仓库信息如 refs、exclude、attributes 等 │   └── exclude ├── objects           // 元数据存储中心 │   ├── info │   └── pack └── refs               // 存放引用信息也就是分支、标签     ├── heads     └── tags 默认初始化生成的 Git 仓库就只有这些文件除此之外还存在一些其它类型的文件和目录如packed-refs modules logs等这些文件都有特定的用途都是在特定的操作或者配置后才会出现这里我们只关注核心存储的实现这些额外文件或目录的作用及使用场景再可自行翻阅文档这里仅介绍核心的一些文件。 hooks 目录 hooks 目录主要存储的是 Git 钩子Git 钩子可以在很多事件发生后或者发生前触发能够提供给我们非常灵活的使用方式默认情况下全部都是带.sample后缀的需要移除这个后缀并赋予可执行权限方可生效下面列举下常用的一些钩子及其常见的用途 客户端钩子 pre-commit提交前触发比如检查提交信息是否规范测试是否运行完毕代码格式是否符合要求 post-commit相反这个是整个提交完成后触发可以用来发通知 服务端钩子 pre-receive服务端接收推送请求首先被调用的脚本可以检测这些被推送的引用是否符合要求 update与 pre-receive 相似但是 pre-receive 只会运行一次而 update 将会为每一个推送的分支分别运行一次 post-receive整个推送过程完成后触发可以用来发送通知、触发构建系统等 objects 目录 如上一节我们提到的Git 将所有接收到的内容生成对象文件存储在这个目录下我们通过 git hash-object 生成了一个对象并写入了 Git 仓库这个对象的键值是 9f4d96d5b00d98959ea9960f069585ce42b1349a这个时候我们来查看下 objects 目录的结构 ➜  Zoker git:(master) ✗ git hash-object testfile -w 9f4d96d5b00d98959ea9960f069585ce42b1349a ➜  Zoker git:(master) ✗ tree .git/objects .git/objects ├── 9f │   └── 4d96d5b00d98959ea9960f069585ce42b1349a ├── info └── pack 可以看到 objects 目录已经有了新的内容多了一个 9f 的文件夹以及其中的文件这个文件就是插入到 Git 仓库的内容的对象文件Git 取其键值的前两个字母作为文件夹将后面的字母作为对象文件的文件名进行存储这里也就是objects/[0-9a-f][0-9a-f]所存储的对象我们一般称为 loose objects 或者 unpacked objects也就是松散对象。 除了对象的存储文件夹细心的同学应该已经注意到了 objects/pack 文件夹的存在这里对应的是打包后的文件为了节省空间和提升效率当存储库中有过多的松散对象文件或者手动执行 git gc 命令时亦或是推送拉取的传输过程中Git 都会将这些松散的对象文件打包成pack文件来提升效率这里存放的就是这些打包后的文件 ➜  objects git:(master) git gc ... Compressing objects: 100% (75/75), done. ... ➜  objects git:(master) tree . ├─ pack     ├── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.idx     └── pack-fe24a22b0313342a6732cff4759bedb25c2ea55d.pack └── ... 可以看到 objects 目录已经没有了松散对象取而代之的是 pack 目录的两个文件一个是打包后的文件另一个是对这个打包的内容进行索引的 idx 文件方便查询某个对象是否在这个对应的 pack 包内。 需要注意的是如果在刚刚我们手动创建的一个 blob 对象的仓库进行 GC将不会产生任何效果因为这个时候整个 Git 仓库并没有任何一个引用指向这个对象我们说这个对象是游离的下面我们来介绍下存储引用的目录。 refs 目录 refs 目录存储我们的引用references引用可以看做是对一个版本号的别名它存储的实际就是某一个 Commit 的 SHA 值上面我们用来测试的仓库并没有任何一个提交所以只有一个空的目录结构。 └── refs     ├── heads     └── tags 我们随便找一个包含提交的仓库查看他的默认分支 master。 ➜  .git git:(master) cat refs/heads/master 87e917616712189ecac8c4890fe7d2dc2d554ac6 可以看到这个master的引用只是存储了一个 Commit 的 SHA 值好处当然就是我们不需要记着那长长的一串 SHA 值我们只需要用master这个别名就可以获取到这个版本。同样的 tags 目录下存储的就是我们的标签与分支不同的是标签的所记录的引用值一般是不会变化的而分支可以我们的版本变化而变化。除此之外还可能会看到 refs/remotes refs/fetch 等目录这些里面存储的是特定命名空间的引用。 还有一种情况就是上面我们讲到的 GC 机制如果一个仓库执行了 GC那么不仅objects目录下的松散对象会被打包refs下面的引用同样也会被打包只不过它存放在裸仓库的根目录下 .git/packed-refs ➜  .git git:(master) cat packed-refs # pack-refs with: peeled fully-peeled sorted 87e917616712189ecac8c4890fe7d2dc2d554ac6 refs/heads/master 当我们需要访问分支 master 的时候Git 会首先去 refs/heads 里面进行查找如果找不到就会前往 .git/packed-refs 进行查找将所有的引用打包到一个文件无疑提升了不少效率。需要注意的是如果我们在这个时候往 master 分支上更新了一些提交这个时候 Git 并不会直接修改 .git/packed-refs文件它会直接在refs/heads/下重新创建一个master引用包含最新的提交的 SHA 值根据刚刚我们介绍的 Git 的机制Git 会首先在 refs/heads/ 查找找不到才会去 .git/packed-refs 查找。 那么引用里面存储的 Commit 的这串 SHA 值到底是指向什么内容呢我们可以使用之前查看 blob 对象内容的 cat-file 命令进行查看 ➜  .git git:(master) git cat-file -p 87e917616712189ecac8c4890fe7d2dc2d554ac6 tree aab1a9217aa6896ef46d3e1a90bc64e8178e1662 // 指向的 tree 对象 parent 7d000309cb780fa27898b4d103afcfa95a8c04db // 父提交 author Zoker kaixuanguiqugmail.com 1607958804 0800 // 作者信息 committer Zoker kaixuanguiqugmail.com 1607958804 0800 // 提交者信息 test ssh // 提交信息 它是一个 commit 类型的对象主要的属性是它指向的 tree 对象它的父提交如果它是第一个提交那么这里是 0000000...以及作者和提交信息。 那么 commit 对象是什么它所指向的 tree 对象又是什么与之前我们手工创建的 blob 对象有什么差别接下来我们来谈谈 Git 存储对象。 Git 存储对象 在 Git 的世界里一共有四种类型的存储对象文件blob、树tree、提交commit、标签tag这里我们主要探讨头三种类型因为这三种是最基础的 Git 元数据而标签对象只是一个包含了额外属性信息的 Tag 而已也就是附注标签annotated tag这里不再过多的介绍。 轻量标签lightweight与附注标签annotated介绍https://git-scm.com/book/zh/v2/Git-基础-打标签 Blob 对象 在介绍 Git 本质的时候为了演示 Git 是一个基于内容寻址的 KV 数据库我们向 Git 仓库插入了一个文件的内容 ➜  Zoker git:(master) ✗ cat testfile Hello Git ➜  Zoker git:(master) ✗ git hash-object testfile -w 9f4d96d5b00d98959ea9960f069585ce42b1349a 这个 Key 为 9f4d96d5b00d98959ea9960f069585ce42b1349a 的 Git 对象实际上就是一个 Blob 对象他存储了这个 testfile 文件的值我们可以使用 cat-file 命令来进行查看 ➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a Hello Git 每一次我们修改文件Git 都会完整的保存一份这个文件的快照而非记录差异所以如果我们修改了testfile文件的内容再次存入到 Git 仓库中的时候Git 会基于当前最新的内容来生成它的 Key需要注意的是当内容不变的时候它的 Key 值是固定的毕竟我们前面也说了Git 是一个基于内容寻址的 KV 数据库。 另外这里的 Blob 对象存储的是文本内容它还可以是二进制内容但是这里并不建议使用 Git 管理二进制文件的版本。我们 Gitee 平台在日常运营过程中遇到最多的问题就是用户仓库过大这种情况一般都是用户提交了大的二进制文件导致的因为每次文件的变更记录的是快照所以这个二进制文件如果变更频繁它占用的空间是倍增的。而且对于文本内容的 BlobGit 在 GC 的过程中会只保存两次提交之间的文件差异是可以达到节省空间的效果的但是对于二进制内容的 Blob 是无法像文本内容的 Blob 那样处理的所以尽量不要把频繁变动的二进制内容存储到 Git 仓库可以使用 LFS 的方式进行存储。如果已经存在了大量的二进制文件可以使用filter-branch进行瘦身新加入的同事在首次 Clone 仓库的时候肯定会感激你的。 LFS 的使用https://gitee.com/help/articles/4235大仓库的瘦身https://gitee.com/help/articles/4232filter-branchhttps://github.com/git/git/blob/master/Documentation/git-filter-branch.txt 到了这里是不是觉得哪里不对劲没错这个 Blob 对象只存储了这个文件的内容却没有记录文件名那我们该怎么知道这个内容是属于哪个文件的啊答案是 Git 的另外一个重要的对象Tree 对象。 Tree 对象 在 Git 中Tree 对象主要的作用是将多个 Blob 或者 子 Tree 对象组织到一起所有的内容都是通过 Tree 和 Blob 类型的对象进行存储的。一个 Tree 对象包含了一个或者多个 Tree Entry树对象记录每个树对象记录都包含了一个指向 Blob 或者子 Tree SHA 值的指针还有它们对应的文件名等信息其实就可以理解为索引文件系统中的 inode 和 block 的关系图示一个 Tree 对象的话如下图 这个 Tree 对象对应的目录结构就是下面这样的 . ├── LICENSE ├── readme.md └── src     ├── libssl.so     └── logo.png 通过这种方式我们可以像组织 Linux 下目录的方式一样来结构化的存储我们仓库的内容把 Tree 看作目录结构把 Blob 看作具体的文件内容。 那么该如何创建一个 Tree 对象呢在 Git 中是根据暂存区的状态来创建对应的 Tree 对象的这里的暂存区其实就是我们日常在使用 Git 的过程中所理解的暂存区Staged一般我们使用 git add 命令将某些文件添加到暂存区待提交。在没有任何提交的空仓库里这个暂存区的状态就是你通过 git add 所添加的那些文件如 ➜  Zoker git:(master) ✗ git status On branch master No commits yet Changes to be committed:   (use git rm --cached file... to unstage)     new file:   LICENSE     new file:   readme.md Untracked files:   (use git add file... to include in what will be committed)     src/ 这里当前的暂存区状态就是在根目录有两个文件暂存区的状态是保存在 .git/index 文件的我们使用 file 命令来看看它是什么 ➜  Zoker git:(master) ✗ file .git/index .git/index: Git index, version 2, 2 entries 可以发现在 index 文件中有两个 entry也就是根目录的两个文件 LICENSE 和 readme.md。对于已经有提交的仓库如果暂存区没有任何内容那么这个 index 表示的就是当前版本的目录树状态如果修改或者增删了文件并且加入了暂存区那么 index 就会发生改变将相关文件的指针指向该文件新的 Blob 对象的 SHA 值。 所以如果想要创建一个 Tree 对象我们需要往暂存区放点东西除了使用 git add我们还可以使用底层命令 update-index 来创建一个暂存区。接下来我们根据上面已经创建好的 testfile 文件来创建一个树对象首先就是将文件 testfile 加入到暂存区 ➜  Zoker git:(master) ✗ git update-index --add testfile // 与 git add testfile 一样 ➜  Zoker git:(master) ✗ git status On branch master No commits yet Changes to be committed:   (use git rm --cached file... to unstage)     new file:   testfile 这个过程 Git 主要是先把testfile的内容以 Blob 的形式插入到 Git 仓库然后将返回的这个 Blob 的 SHA 值记录到index中告诉暂存区目前这个文件的内容是哪个。 ➜  Zoker git:(master) ✗ tree .git/objects .git/objects ├── 9f │   └── 4d96d5b00d98959ea9960f069585ce42b1349a ├── info └── pack 3 directories, 1 file ➜  Zoker git:(master) ✗ git cat-file -p 9f4d96d5b00d98959ea9960f069585ce42b1349a Hello Git Git 在执行update-index命令的时候把指定文件的内容存储为 Blob 对象并且记录在index文件状态内。由于在之前我们已经通过 git hash-object 命令将这个文件的内容插入过了并且我们可以发现因为内容不变所以生成的这个 Blob 对象的 SHA 值也是一致的如果像我们这样已经做过插入的动作下面的命令是等效的 git update-index --add --cacheinfo 9f4d96d5b00d98959ea9960f069585ce42b1349a testfile 这个命令其实就是把之前已经生成的 Blob 对象放到暂存区并且指定它的文件名字是 testfile。由于我们的暂存区已经有一个文件 testfile所以我接下来我们可以使用 git write-tree 命令来基于当前暂存区的状态来创建一个 Tree 对象了 ➜  Zoker git:(master) ✗ git write-tree aa406ee8804971cf8edfd8c89ff431b0462e250c ➜  Zoker git:(master) ✗ tree .git/objects .git/objects ├── 9f │   └── 4d96d5b00d98959ea9960f069585ce42b1349a ├── aa │   └── 406ee8804971cf8edfd8c89ff431b0462e250c ├── info └── pack 执行完命令后Git 会基于当前暂存区的状态生成一个 SHA 值为aa406ee8804971cf8edfd8c89ff431b0462e250c的 Tree 对象并把这个 Tree 对象像 Blob 对象一样存储在.git/objects目录下。 ➜  Zoker git:(master) ✗ git cat-file -p aa406ee8804971cf8edfd8c89ff431b0462e250c 100644 blob 9f4d96d5b00d98959ea9960f069585ce42b1349a    testfile 使用 cat-file 命令查看这个 Tree 对象可以看到这个对象下只有一个文件名为testfile。 我们继续创建第二个 Tree 对象我们需要第二个 Tree 对象下有修改后的testfile文件有新增的 testfile2文件并且需要把第一个 Tree 对象作为 第二个 Tree 对象的duplicate目录。首先我们先把修改后的testfile和新增的testfile2文件加入到暂存区 ➜  Zoker git:(master) ✗ git update-index testfile ➜  Zoker git:(master) ✗ git update-index --add testfile2 ➜  Zoker git:(master) ✗ git status On branch master No commits yet Changes to be committed:   (use git rm --cached file... to unstage)     new file:   testfile     new file:   testfile2 紧接着我们需要把第一个 Tree 对象挂到 duplicate 目录下我们可以使用 read-tree 命令来实现 ➜  Zoker git:(master) ✗ git read-tree --prefixduplicate aa406ee8804971cf8edfd8c89ff431b0462e250c  ➜  Zoker git:(master) ✗ git status On branch master No commits yet Changes to be committed:   (use git rm --cached file... to unstage)     new file:   duplicate/testfile     new file:   testfile     new file:   testfile2 然后我们执行 write-tree 并通过 cat-file 查看第二个 Tree 对象 ➜  Zoker git:(master) ✗ git write-tree 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1 ➜  Zoker git:(master) ✗ git cat-file -p 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1 040000 tree aa406ee8804971cf8edfd8c89ff431b0462e250c    duplicate 100644 blob 106287c47fd25ad9a0874670a0d5c6eacf1bfe4e    testfile 100644 blob 098ffe6f84559f4899edf119c25d276dc70607cf    testfile2 成功完成了我们不仅修改了 testfile 的文件内容还新增了一个 testfile2 文件并且还把第一个 Tree 对象当作第二个 Tree 对象的 duplicate 目录了这个时候 Tree 对象看起来应该是这样的 至此我们知道了如何手动创建一个 Tree 对象但是后面如果我需要这两个不同的 Tree 的快照该怎么办总不能都记住这三个 Tree 对象的 SHA 值吧没错记起来费老大劲了关键是还不知道是谁在什么时间为了什么而创建的这个快照而 Commit 对象提交对象就能够帮我们解决这个问题。 Commit 对象 Commit 对象主要是为了记录快照的一些附加信息并且维护快照之间的线性关系。我们可以通过git commit-tree命令来创建一个提交这个命令看字面意思就知道它是用来将 Tree 对象提交为一个 Commit 对象的命令 ➜  Zoker git:(master) ✗ git commit-tree -h usage: git commit-tree [(-p parent)...] [-S[keyid]] [(-m message)...] [(-F file)...] tree     -p parent           id of a parent commit object     -m message          commit message     -F file             read commit log message from file     -S, --gpg-sign[key-id]                           GPG sign commit 关键的两个参数是 -p 和 -m-p 是指定这个提交的父提交如果是初始的第一个提交那这里可以忽略-m 则是指定本次提交的信息主要是用来描述提交的原因。我们来把第一个 Tree 对象作为我们的初始提交 ➜  Zoker git:(master) ✗ git commit-tree -m init commit aa406ee8804971cf8edfd8c89ff431b0462e250c 17ae181bd6c3e703df7851c0f7ea01d9e33a675b 使用cat-file来查看这个提交 tree aa406ee8804971cf8edfd8c89ff431b0462e250c author Zoker kaixuanguiqugmail.com 1613225370 0800 committer Zoker kaixuanguiqugmail.com 1613225370 0800 init commit Commit 所存储的内容是一个 Tree 对象并且记录了提交者、提交时间以及提交信息。我们基于这个 Commit 将第二个 Tree 对象作为引用 ➜  Zoker git:(master) ✗ git commit-tree -p 17ae181bd -m add dir 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1 de96a74725dd72c10693c4896cb74e8967859e58 ➜  Zoker git:(master) ✗ git cat-file -p de96a74725dd72c10693c4896cb74e8967859e58 tree 64d62cef754e6cc995ed8d34f0d0e233e1dfd5d1 parent 17ae181bd6c3e703df7851c0f7ea01d9e33a675b author Zoker kaixuanguiqugmail.com 1613225850 0800 committer Zoker kaixuanguiqugmail.com 1613225850 0800 add dir 我们可以使用 git log 来查看这两个提交这里添加 --stat 参数查看文件变更记录 commit de96a74725dd72c10693c4896cb74e8967859e58 Author: Zoker kaixuanguiqugmail.com Date:   Sun Feb 13 22:17:30 2021 0800     add dir  duplicate/testfile | 1   testfile           | 2 -  testfile2          | 1   3 files changed, 3 insertions(), 1 deletion(-) commit 17ae181bd6c3e703df7851c0f7ea01d9e33a675b Author: Zoker kaixuanguiqugmail.com Date:   Sun Feb 13 22:09:30 2021 0800     init commit  testfile | 1   1 file changed, 1 insertion() 这个时候整个对象的结构如下图 练习使用底层命令创建一个提交 仅使用我们上面提到的hash-object write-tree read-tree commit-tree等底层命令来创建一个提交思考哪些过程是与git add git commit等价的。 对象存储方式 我们通过前面的介绍知道了 Git 是将数据以不同的对象类型归纳并且根据内容计算出一个 SHA 值用来作为寻址那么到底是如何计算的呢以 Blob 对象为例Git 主要是做了如下几步 识别对象的类型构造头部信息以类型 内容字节数 空字节作为头部信息如 blob 151\u0000 将头部信息与内容拼接并且计算 SHA-1 校验和 通过 zlib 压缩内容 通过 SHA 值将其内容放到对应的 objects 目录 整个过程就做了这些事情Tree 对象和 Commit 对象也差不多只是头部类型有所差异而已这里不再赘述《Pro Git 2》在 Git 内部原理章节中有介绍如何使用 Ruby 来实现同等的逻辑感兴趣的可以自行翻阅。 Git-内部原理https://git-scm.com/book/zh/v2/Git-内部原理-Git-对象 Git 引用 我们在上面通过 git log --stat 17ae181b 能够查看第一个版本的相关信息并且可以通过这串 SHA 值拿到这个快照的内容但是还是挺麻烦的因为我们要记住一串毫无意义的字符串这个时候 Git 的引用就派上用场了在 Git 目录结构章节我们已经介绍了refs目录我们知道在引用中存储的就是 Commit 对象的键值也就是这个对象的 SHA 值既然如此我们就给我们当前的版本起一个有意义的名字一般我们会拿master作为默认分支引用 ➜  Zoker git:(master) ✗ echo 17ae181bd6c3e703df7851c0f7ea01d9e33a675b  .git/refs/heads/master ➜  Zoker git:(master) ✗ tree .git/refs .git/refs ├── heads │   └── master └── tags 这个时候master 里面存储了我们的第一个 Commit 的 SHA 值我们可以使用 master 来代替 17ae181b 这串毫无意义的字符串了。 ➜  Zoker git:(master) ✗ git cat-file -p master tree aa406ee8804971cf8edfd8c89ff431b0462e250c author Zoker kaixuanguiqugmail.com 1613916447 0800 committer Zoker kaixuanguiqugmail.com 1613916447 0800 init commit 但是这个并不是我们最新的版本我们最新的版本是第二个提交 de96a74725dd72c10693c4896cb74e8967859e58同样的我们可以把refs/heads/master的内容更改为这个提交的 SHA 值但是这里我们使用一个底层命令来完成。 ➜  Zoker git:(master) ✗ git update-ref refs/heads/master de96a74725dd72c10693c4896cb74e8967859e58 ➜  Zoker git:(master) ✗ cat .git/refs/heads/master de96a74725dd72c10693c4896cb74e8967859e58 这个时候分支 master 就指向了我们最新的版本。
http://wiki.neutronadmin.com/news/18728/

相关文章:

  • 投票网站设计网站建设app开发 微信小程序 网站开发 自动脚本
  • 线上运营怎么做台州百度搜索优化
  • 网站建设项目中标通知wordpress播放器源码
  • 响应式网站设计企业seo快速整站上排名教程
  • 建德网站建设德品牌网西乡移动网站建设
  • 300个吉祥公司取名大全搜索引擎优化seo网站
  • 做网站收费标网站ip访问做图表
  • 做短租有哪些网站给你一个网站你怎么做
  • 北京网站设计网站设计公司价格云南省建设厅网站怎么进不去
  • 购物网站支付功能怎么做深圳网站建设raygf
  • 杭州微信建站沈阳网站优化推广方案
  • 麻章网站建设公司wordpress wp-json
  • 智库建设网站婚纱影楼网站免费源码
  • 建设英文网站的公司建设企业网站综合考虑
  • 佛山市公司网站建设哪家好免费做请帖的网站
  • pc建站网站外发加工网有哪些
  • 电子商务网站数据库怎么做网易企业邮箱登录入口手机网页版
  • php 网站 教程怎么做阿里巴巴外贸网站
  • 网站怎么做排名呢怎么建设
  • 本地网站建设信息大全购物网站功能模块设计
  • 深圳一百讯网站建设网站是公司域名是个人可以
  • dede网站地图html文件网站做流量的论坛贴吧
  • 长沙做一个网站多少钱wordpress信息搜集
  • 化妆品网站建设思路wordpress前端框架
  • 泰州网站建设多少钱qq空间秒赞秒评网站推广
  • 个人做网站下载网上图可以吗400平别墅装修费用
  • 论坛seo网站长沙网站推广平台
  • 域名注册的网站有哪些建设厅官方网站北京
  • 影视 网站建设 新媒体寒亭区建设局网站
  • 信阳建设网站哪家好文案转行做网站编辑