git对象

git是面向对象的,对象存储在.git/objects文件夹中。此文件夹中,一个对象就是一个文件,文件名就是对象的id

提交commit的时候,每个文件都是一个数据对象,一个树对象会用来维护一次提交的所有数据对象,如果提交的内容包含文件夹,那么这个文件夹也会是一个树对象

一次提交就是一个提交对象,这个对象包括了表示此次提交所有数据对象的树对象,以及对上一个提交对象的指针

# -t 打印对象类型;-p 打印对象内容
$ git cat-file -t 458ed8e
commit # 458ed8e是一个提交对象 $ git cat-file -p 458ed8e
tree 0ce2ac7bb5b76a74a03d1af4b3b87337ecb15e88 # 本次提交的树对象
parent dd5736397cacc07ba8fbf73201a53a0d733063b2 # 上一个提交对象的指针
author luozixi <luozixi@xxx.net> 1592392241 +0800
committer luozixi <luozixi@xxx.net> 1592392241 +0800 fix $ git cat-file -t 0ce2ac7bb5b76a74a03d1af4b3b87337ecb15e88
tree # 查看本次提交的树对象类型 $ git cat-file -t dd5736397cacc07ba8fbf73201a53a0d733063b2
commit # 查看上一个提交对象的类型 $ git cat-file -p 0ce2ac7bb5b76a74a03d1af4b3b87337ecb15e88
100644 blob d45dda6a2a0d66f808c4999bb2b54ff0d931dde4 .editorconfig
040000 tree dc8ccda293623ed2a7f173c0c9714e95044a9125 utils
# 本次提交的树对象中,有一个数据对象(对应文件)和一个树对象(对应文件夹)

git指针

所有的分支和标签都是指向提交对象的指针

所有的本地分支指针都存储在 git/refs/heads 目录下,每一个分支对应一个文件,文件的内容就是本地分支最后一次提交的提交对象

$ cat .git/refs/heads/feature/feature1
458ed8e77466a5f5be0167ab7ab8977060ec21cf

HEAD指针,是一个指向指针的指针

$ cat .git/HEAD
ref: refs/heads/feature/feature1

它指向了feature/feature1的分支指针存储位置,而分支指针又指向分支最后一次提交的提交对象,所以说HEAD是一个指向指针的指针

它的作用是标识当前使用的是那个分支,使用git checkout切换分支的时候,实际上就是修改了HEAD指针的值

checkout和reset的区别:这两个命令都会改变 HEAD 的指向,区别是 checkout 不改变 HEAD 所指向的分支指针的指向,而 reset 会

git日志

.git/logs/HEAD文件记录了HEAD指针的变更记录

.git/logs/refs/heads则记录了所有分支指的变更记录

使用$ git reglog指令实际上就是读取了.git/logs/HEAD这个文件

$ git log指令就不是直接读取文件了,这个指令的输出是由分支所指的提交对象一层层向前找父提交对象绘制而成的

撤销rebase

git中并不存在某次提交时的分支快照

但是通过HEAD的变更记录,我们可以找到rebase之前当前分支所指的提交对象,然后使用reset将当前分支指向那时的提交对象就可以了

$ git reset --hard HEAD@{30}

HEAD@{30}是需要回退的提交对象的简写

执行这个操作之后,可以发现HEAD的日志里多了一行

 HEAD@{0}: reset: moving to HEAD@{30}

查看当前分支的日志,可以发现很有趣的事情:

0000000000000000000000000000000000000000 c77a9670c5cfdb8abd0ea05fdc4bfe71725c8ff4 luozixi 1591684691 +0800	branch: Created from develop
...
dd5736397cacc07ba8fbf73201a53a0d733063b2 458ed8e77466a5f5be0167ab7ab8977060ec21cf luozixi 1592392241 +0800 commit: fix
458ed8e77466a5f5be0167ab7ab8977060ec21cf b271f35c4e9552d23669a05509067a3cd8b7dd03 luozixi 1592536842 +0800 rebase finished: refs/heads/feature/feature1 onto e5168c3c5e2f8219e51ede4ccd40136e2f69777b
b271f35c4e9552d23669a05509067a3cd8b7dd03 458ed8e77466a5f5be0167ab7ab8977060ec21cf luozixi 1592538987 +0800 reset: moving to HEAD@{30}

每一行的第一个位置是移动分支指针前分支指针指向的提交对象的id,第二个位置是当前分支指针指向的提交对象的id

可以看到日志的一开始,父对象的id是全0的,这是所有分支的起点

458ed8e77466a5f5be0167ab7ab8977060ec21cf是此分支最后一次提交,然后就进行了rebase操作

rebase finished: refs/heads/feature/feature1 onto
e5168c3c5e2f8219e51ede4ccd40136e2f69777b

这个e5168c3c5e2f8219e51ede4ccd40136e2f69777b正是rebase目标分支(debelop)所指提交对象的id,即develop最新的提交

最后,我们执行了reset操作,使feature1的分支指针再次指向了458ed8e77466a5f5be0167ab7ab8977060ec21cf,即此分支的最后一次提交

git log里也没有了rebase的相关提交信息

那么表示rebase操作的b271f35c4e9552d23669a05509067a3cd8b7dd03这个提交对象消失了吗?

$ git cat-file -p b271f35c4e9552d23669a05509067a3cd8b7dd03
tree 1ee51eedb07f6ac0144e590668977eb19696a2c8
parent 64a34f53657544530961c8aadcf60091e3912b74
author luozixi <luozixi@xxx.net> 1592392241 +0800
committer luozixi <luozixi@xxx.net> 1592536842 +0800

可以看到,它没有消失,其实rebase之后形成的所有提交对象都没有消失,只不过已经没有分支指针指向它们了,它们变成了不可见的对象,也就是悬空对象(dangling objects)

如果我们还想再找回它们,去log里找到它的id就行

如果需要彻底删除这些悬空对象,见:http://liuhui998.com/2010/11/06/remove_commits_completely/

参考资料

https://juejin.im/post/5a65ac67f265da3e330473f7

撤销rebase与git原理的更多相关文章

  1. Git原理与命令大全

    Git (wiki: en  chs )是一个免费开源的分布式版本控制系统,由linux内核作者linus Torvalds开发,大型开源项目linux kernel.Android.chromium ...

  2. Git原理入门简析

    为了获得更好的阅读体验,建议访问原地址:传送门 前言: 之前听过公司大佬分享过 Git 原理之后就想来自己总结一下,最近一忙起来就拖得久了,本来想塞更多的干货,但是不喜欢拖太久,所以先出一版足够入门的 ...

  3. Git原理入门解析

    前言: 之前听过公司大佬分享过 Git 原理之后就想来自己总结一下,最近一忙起来就拖得久了,本来想塞更多的干货,但是不喜欢拖太久,所以先出一版足够入门的: 一.Git 简介 Git 是当前流行的分布式 ...

  4. git rebase 与git merge 小结

    git merge是用来合并两个分支的. $ git merge b   将b分支合并到当前分支 同样  $ git rebase b ,也是把 b分支合并到当前分支 ---------------- ...

  5. git原理学习记录:从基本指令到背后原理,实现一个简单的git

    一开始我还担心 git 的原理会不会很难懂,但在阅读了官方文档后我发现其实并不难懂,似乎可以动手实现一个简单的 git,于是就有了下面这篇学习记录. 本文的叙述思路参照了官方文档Book的原理介绍部分 ...

  6. Git原理及常用操作命令总结

    git原理介绍及操作 git 原理——

  7. Merge和Rebase在Git中的区别

    git命令Merge和Rebase的区别 git merge 会生成一个新得合并节点,而rebase不会 比如: D---E test / A---B---C---F master 使用merge合并 ...

  8. git rebase和git merge的用法

    http://softlab.sdut.edu.cn/blog/subaochen/2016/01/git-rebase%E5%92%8Cgit-merge%E7%9A%84%E7%94%A8%E6% ...

  9. git rebase vs git merge详解

    https://medium.com/@porteneuve/getting-solid-at-git-rebase-vs-merge-4fa1a48c53aa#.std3ddz0g 请参考另外一篇文 ...

随机推荐

  1. c++11 新特性实战 (一):多线程操作

    c++11多线程操作 线程 thread int main() { thread t1(Test1); t1.join(); thread t2(Test2); t2.join(); thread t ...

  2. 程序员的开源月刊:HelloGitHub(第 54 期)

    兴趣是最好的老师,HelloGitHub 就是帮你找到兴趣! 简介 分享 GitHub 上有趣.入门级的开源项目. 这是一个面向编程新手.热爱编程.对开源社区感兴趣 人群的月刊,月刊的内容包括:各种编 ...

  3. SpringMVC学习(二)

    Ajax 简介 AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML). AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分 ...

  4. Ubuntu部署和体验Nexus3

    关于Nexus 如下图,在局域网部署了Nexus之后,可以缓存中央仓库的jar,开发者开发的二方库发布到Nexus上,局域网内的其他人也可以从Nexus下载这些二方库使用: 环境信息 本次实战是在Li ...

  5. CF724G 【Xor-matic Number of the Graph】

    题目就不翻译了吧,应该写的很清楚了... 首先 \(,\) 不懂线性基的可以戳这里.知道了线性基\(,\) 但是从来没有写过线性基和图论相结合的\(,\) 可以戳这里. 好\(,\) 点完了这些前置技 ...

  6. Centos 6.9 安装 php5.6

    1.检查当前安装的PHP包 yum list installed | grep php 如果有安装的PHP包,先删除他们, 如: yum remove php.x86_64 php-cli.x86_6 ...

  7. 使用css实现轮播图

    使用css3实现图片轮播 前言:实现图片轮播的方式有很多种 ,例如js ,css 等等. 本文主要讲述使用纯css3实现轮播图 工具介绍: 使用的编辑器: Hbuilder 进入正题 html代码: ...

  8. id+is+深浅co'p'y

    day06 一.id.is 关键字:id #唯一的,如果id相同,说明2个变量指向同一个地址,就是变量一==变量二 注意:id相同值一定相同,值相同但是id不一定相同(不同代码块的值相同,他们就像太阳 ...

  9. js 为什么0.1+0.2不等于0.3

    当程序员在使用浮点数进行计算逻辑处理时,不注意,就可能出现问题, 记住,永远不要直接比较俩个浮点的大小 这个属于数字运算中的精度缺失的问题 在0.1 + 0.2这个式子中,0.1和0.2都是近似表示的 ...

  10. CSP-S2020AFO记

    2020-10.11 考初赛辣. 选择题考了一堆时间复杂度,一个不会(卒) 我寻思这01背包哪里能用贪心? 啊,这,这,这手写快排竟如此简单,手写取Max,手写队列,两个字符串颠来倒去,竟活到爆! 震 ...