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. 过万 star 高星项目的秘密——GitHub 热点速览 Vol.39

    作者:HelloGitHub-小鱼干 虽然国外十一并不过国庆,但是本周的 GitHub 也稍显疲软,GitHub 周榜的获 star 超过 1k 的项目寥寥无几,本周新开源的项目更是屈指可数.用 C ...

  2. django 的跨域配置

    1.跨域原理 #1. 首先浏览器安全策略限制js ajax跨域访问服务器 #2. 如果服务器返回的头部信息中有当前域: // 允许 http://localhost:8080 这个网站打开的页面中的j ...

  3. python下正则表达式的随笔记录

    使用了下正则的表达式: 目的:取出字符串中{}中的内容 最后使用的正则表达式为 {(.*?)} 先看   .*?  : 首先  .  是用来匹配字符串,但是只能匹配一次. 所以加上  *  ,可以让 ...

  4. CF149D Coloring Brackets

    CF149D Coloring Brackets Link 题面: 给出一个配对的括号序列(如"\((())()\)"."\(()\)"等, "\() ...

  5. 【题解】NOIP2018 旅行

    题目戳我 \(\text{Solution:}\) 首先题目描述有一点不准确:回头是必须要走完一条路无路可走的时候才能返回. 对于树的情况:显然贪心做就完事了. 对于基环树的情况:对于一个\(n\)条 ...

  6. 一、Vuforia_AR

    一.AR概念: 增强现实(Augmented Reality,简称AR),是一种将虚拟信息与真实世界巧妙融合的技术,广泛运用了多媒体.三维建模.实时跟踪及注册.智能交互.传感等多种技术手段,将计算机生 ...

  7. 对ACE和ATL积分

    下载source code - 39.66 KB 介绍 这篇文章展示了一种结合ACE和ATL的方法.它不打算作为功能演示,而是作为一个小型的"入门"解决方案,展示实现此目标的可行方 ...

  8. 转C++了

    积极响应"某王"的号召,联赛之后转C辣!(好吧,其实是它拿着一把西瓜刀顶在我背后逼我转的)

  9. 用vscode写python,from引用本地文件的时候老是有红色波浪线,很不爽

    前言 出于一些原因,国际关系等等,最近想把开发工具切换到一些免费开源的工具上面,先尝试了在vscode上搭建python环境,总体还是很简单的, 网上教程很多,vscode本身的插件也很丰富,可惜了国 ...

  10. Vue.js 学习笔记之四:Vue 组件基础

    到目前为止,这个系列的笔记所展示的都是一些极为简单的单页面 Web 应用程序,并且页面上通常只有几个简单的交互元素.但在实际生产环境中,Web 应用程序的用户界面往往是由多个复杂的页面共同组成的.这时 ...