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. 《Redis入门指南》笔记

    第1章 简介 1.1 历史与发展 2008年 意大利创业公司创始人因对mysql性能不满意,于是他决定开发redis. 2009年 redis初版由他一个人开发完成.redis是"remot ...

  2. js计算两个时间相差

    .filter('useTime', function() { return function(val) { // if (/.(.mp4)$/gi.test(url)) { // return JS ...

  3. Linux一些基础命令

    man              查看命令                                                                             -  ...

  4. Python练习题 034:Project Euler 006:和平方与平方和之差

    本题来自 Project Euler 第6题:https://projecteuler.net/problem=6 # Project Euler: Problem 6: Sum square dif ...

  5. SpringBoot整合SpringDataJPA,今天没啥事情就看了一下springboot整合springdataJPA,实在是香啊,SQL语句都不用写了

    SpringBoot整合SpringDataJPA 1.JPA概念 JPA是Java Persistence API的简称,中文名Java持久层API,是JDK 5.0注解或XML描述对象-关系表的映 ...

  6. 无所不能的embedding 3. word2vec->Doc2vec[PV-DM/PV-DBOW]

    这一节我们来聊聊不定长的文本向量,这里我们暂不考虑有监督模型,也就是任务相关的句子表征,只看通用文本向量,根据文本长短有叫sentence2vec, paragraph2vec也有叫doc2vec的. ...

  7. 联赛模拟测试10 C. 射手座之日

    题目描述 分析 方法一(线段树) 线段树维护的是以当前节点为左端点的区间的贡献 而区间的右端点则会从 \(1\) 到 \(n\) 逐渐右移 当我们把右端点从 \(i-1\) 的位置扩展到 \(i\) ...

  8. HashMap 、ConcurrentHashMap知识点全解析

    散列表 在了解hashmap之前,要先知道什么是散列表,因为hashmap就是在散列表结构基础上改造而成的.散列表,也叫哈希表,是根据关键码值(key value)而直接进行访问的数据结构.也就是说, ...

  9. 3-kubernetes监控与日志管理

    监控集群资源利用率 metrics-server是一个集群范围的资源使用情况的数据聚合器,作为一个应用部署在集群中 metrics-server从每个节点上kubelet API收集指标,通过kube ...

  10. 第五周:面向对象部分内容总结(5)---java设计规则

    面向对象设计原则 1.开闭原则 开闭原则理解: 简单说就是一个软件实体支持扩展,不支持修改.就是在不改变源码的基础上,扩展其它的功能. 其实笔者认为,开闭原则无非就是想表达这样一层意思:用抽象构建框架 ...