- 博客(115)
- 收藏
- 关注
原创 Git原理与使用详解(十):Git大师之路——总结与最佳实践
经过前面九章的深入学习,我们已经从Git的完全新手成长为能够驾驭企业级开发场景的Git专家。本章作为整个系列的收官之作,将对前面所学的知识进行系统性的总结,并分享在实际工作中应用Git的最佳实践。希望这个系列能够成为你Git学习道路上的有力助手,祝你在未来的开发工作中取得更大的成功!通过本系列十篇文章的系统学习,我们已经完成了从Git新手到专家的蜕变。:创建、切换、合并、删除的完整生命周期管理。:Git的核心概念、基本操作和工作原理。:掌握合并冲突的预防、识别和解决方法。:分支、标签、HEAD的工作原理。
2026-01-26 16:08:00
270
原创 Git原理与使用详解(九):Git内部原理与高级技巧揭秘
本章将深入Git的内部世界,探索其数据存储模型、关键对象类型和工作原理。我们还将学习一些强大的高级技巧,让你从Git的"熟练使用者"蜕变为"真正的专家"。在下一篇(也是最后一篇)中,我们将进行全面的知识总结,并探讨如何将所学应用到实际工作中,制定个人和团队的Git最佳实践。Git的强大之处在于它的简单性和灵活性的完美结合。通过前八章的学习,我们已经掌握了Git在日常开发中的全面应用。但真正让Git高手与众不同的是他们对Git。Reflog是Git的安全网,记录了所有引用变更的历史。
2026-01-26 16:04:01
328
原创 Git原理与使用详解(八):企业级Git工作流与DevOps实践
然而,在真实的企业环境中,Git的使用远不止于简单的分支管理和代码合并。本章将带你进入企业级Git实践的世界,学习标准的Git分支模型、DevOps理念、以及如何将Git集成到完整的软件开发生命周期中。DevOps是Development(开发)和Operations(运维)的组合词,是一种文化、运动和实践,旨在促进开发团队和运维团队之间的协作与沟通。在下一篇中,我们将进入Git学习的最后阶段,探讨Git的底层原理和高级技巧,帮助你从Git使用者成长为Git专家。标准的分支策略为解决这些问题提供了框架。
2026-01-26 16:00:08
432
原创 Git原理与使用详解(七):团队交响曲——多人协作开发实战
在前面的章节中,我们学习了Git的本地操作和基本的远程仓库管理,这相当于一个音乐家的独奏练习。通过规范的Git工作流、清晰的代码审查和有效的沟通,团队可以高效地协作开发复杂的软件项目。在下一篇中,我们将进入企业级开发的主题,学习标准的Git分支模型和DevOps实践,了解如何将Git集成到完整的软件开发生命周期中。每个新功能都在独立的分支上开发,完成后通过合并请求(Pull Request)集成到主分支。冲突是多人协作中的常见情况,重要的是学会如何正确处理。:强制推送会重写历史,只应在个人功能分支上使用。
2026-01-26 15:56:39
352
原创 Git原理与使用详解(六):连接世界——远程仓库与多人协作入门
远程仓库(如Gitee、GitHub上的仓库)只是多个仓库中的一个,通常被约定为“官方”版本库,用于交换大家的修改。在前面的章节中,我们所有的Git操作都是在本地完成的,这就像玩一个精彩的单机游戏。本章我们将学习如何将本地仓库与远程仓库连接,实现最基本的推送和拉取操作,为后续的多人协作打下基础。每个开发者的本地仓库都是一个完整的镜像,包含完整的版本历史。当你的队友向远程仓库推送了新的提交,你需要将这些更新拉取到本地,以保持同步。作为中央枢纽,让所有开发者都能推送自己的更新,并拉取他人的更新。
2026-01-26 15:53:12
445
原创 Git原理与使用详解(五):平行宇宙——Git分支管理艺术
想象一下这样的场景:你正在为即将发布的新版本V1.0开发一个核心功能,这个功能代码量很大,需要一周时间才能完成。与此同时,测试团队发现了一个线上V1.0版本的高危Bug,需要立即修复并发布V1.1版本。在只有一条时间线的情况下,这个分支就是。是一个特殊的指针,它指向你当前所在的分支(也就是当前激活的"平行宇宙")。:功能开发分支,从develop分支创建,完成后再合并回develop。合并会创建一个新的合并提交,即使是可以Fast-forward的情况。目录下的文件,文件内容就是该分支指向的提交ID。
2026-01-26 15:50:17
465
原创 Git原理与使用详解(四):时光回溯——版本回退与修改撤销
一个强大的版本控制系统,其价值不仅在于记录每一次正确的提交,更在于当错误发生时,能提供一套安全、可靠的“后悔药”机制,让我们能够从容地回溯到任何一个正确的历史版本。它提供了强大的工具来帮助我们进行版本回退和修改撤销,理解并善用这些功能,是每一位开发者必须掌握的生存技能。想象一下,你刚刚提交了几个版本,但发现当前版本的代码引入了严重的问题,希望将代码库恢复到某个历史版本的状态。此时,如果你想彻底丢弃这个修改,可以再使用情况一中的命令。可以理解为 Git 中的“当前激活状态”或“你正在看的地方”的标签。
2026-01-26 15:46:38
474
原创 Git原理与使用详解(三):深入.git与文件管理实战
同时,在实际开发中,我们不仅需要添加新文件,更重要的是对已有文件进行频繁的修改。,是Git版本控制的核心。:存储一次提交的元数据,如作者、提交者、提交时间、提交信息,以及指向其父提交(一个或多个)和顶层Tree对象的指针。在下一篇博客中,我们将探索Git的“时光机”功能:如何进行版本回退、撤销修改,以及删除被Git管理的文件。开头的行(绿色,在终端中通常显示为绿色)表示在新版本中存在,但在旧版本中不存在的行。开头的行(红色,在终端中通常显示为红色)表示在旧版本中存在,但在新版本中被删除的行(本例中没有)。
2026-01-26 15:41:58
562
原创 Git原理与使用详解(二):初探Git仓库与核心工作流程
我们深入剖析了Git的核心——工作区、暂存区、版本库的“三区”概念及其协作流程,这个模型是理解所有后续Git操作的关键。本篇将带领你踏出Git实战的第一步:创建你的第一个Git仓库,并深入理解Git赖以运作的核心机制——工作区、暂存区和版本库的“三区”协作。目录是Git的“心脏”,千万不要手动修改或删除这个目录里的任何文件,否则很可能会破坏整个Git仓库,导致版本历史丢失。你把切好的、准备下锅的菜先放到这个盘子里。的隐藏子目录,这个目录就是Git的版本库,你所有的版本信息、配置、日志等都存放在这里。
2026-01-26 15:37:29
691
原创 Git原理与使用详解(一):版本控制之殇与Git的救赎
我们重点介绍了Git作为分布式版本控制系统的核心优势,并详细讲解了如何在主流操作系统(Linux和Windows)上完成Git的安装配置,为后续的实战操作打下了坚实的基础。:与传统的集中式版本控制系统(如SVN)不同,Git是分布式的。创建、切换、合并分支的操作几乎可以在瞬间完成,鼓励开发者频繁使用分支来进行功能开发、Bug修复等,而不会影响主线的稳定性。:安装完成后,在开始菜单中找到“Git” -> “Git Bash”,点击打开一个类似于Linux终端的命令行窗口。对于初学者,可以换成更易用的编辑器。
2026-01-26 15:28:27
497
原创 红黑树底层实现原理
当uncle节点不存在的时候所需要进行的操作跟uncle存在的时候所进行的操作一摸一样,如果parent节点是grandparent的左孩子节点的时候,我们就需要进行右旋操作,经过右旋之后的操作之后再将grandparent节点的颜色修改成为红色,parent节点的颜色修改成为黑色即可。当parent为grandparent的右节点的时候同样的道理,但是我们需要进行的是左旋的操作,之后再将颜色进行修改,同样是grandparent的颜色修改成为红色,parent的颜色修改成为黑色。
2025-11-28 11:42:03
811
原创 AVL树的底层实现
还记得我们之前学习到的二叉搜索树吗?二叉搜索树是严格按照左孩子的值小于根节点的值,右节点的值大于根节点的值这样一个逻辑所构成的一棵树。我们根据这样的规定可以做到快速的查找到指定的数据。时间复杂度仅为O(lgN)。但是我们同样说过,在极端的情况下我们的二叉搜索树会退化,例如一端超级高一端超级低的情况,这个时候查找的时间复杂度就会退化为O(N)。因此为了解决我们的极端情况,特此产生了AVL树也就是平衡二叉搜索树。所谓的AVL树就跟他正常的名字的含义一样,平衡二叉搜索树。严格遵守平衡规则的二叉搜索树。
2025-11-27 17:25:06
962
原创 C++学习——异常
1. 异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用的信息,这样可以帮助更好的定位程序的bug。2. 返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误,最外层才能拿到错误,在每次返回错误的过程当中我们都需要对错误的类型进行判断,极大的带来了不便。3. 很多的第三方库都包含异常,比如boost、gtest、gmock等等常用的库,那么我们使用它们 也需要使用异常。
2025-11-21 19:20:02
824
原创 搜索二叉树的认识以及底层实现
所谓的搜索二叉树其实就是具有特殊规则要求的二叉树。搜索二叉树要求我们每一个子树都应该满足其左孩子节点当中存储的值都应该小于父节点当中存储的值,其右孩子节点当中存储的值都应该大于我们父节点当中存储的值。搜索二叉树结构如下图所示:只要我们满足这样的规则就说明我们的二叉树是一颗搜索二叉树。
2024-09-17 16:57:35
1271
原创 C++当中的多态(三)
编译器会自动将继承A的虚函数表当中对应的函数地址进行覆盖得到一个完整的派生类虚函数表A,同样的对于读书与B类的虚函数进行重写的时候,也会对相应的函数地址进行覆盖得到一个完整的派生类虚函数表B。同时我们A的虚函数表被D类所继承,如果D类对A类进行虚函数的重写操作,会直接使用新的虚函数地址覆盖我们原有的虚函数的地址。思考一下:我们的虚表可以进行修改吗?使用基类A的指针进行访问C类重写的函数,调用的应该是C类当中的重写之后的虚函数,使用基类B的指针进行访问C类重写的函数,调用的应该也是C类当中重写之后的虚函数。
2024-09-12 21:21:28
1078
原创 C++当中的多态(二)
相信大家在刚开始遇到这三种概念的时候都会产生疑惑。重载,重写,重定义很像诶,那么这三者有什么区别呢?我们需要注意什么吗?函数重定义的概念在我们的继承章节当中提到过。当我们的派生类存在跟我们基类函数名完全相同的函数的时候,就构成了函数的隐藏。对于函数隐藏来说我们并不要求参数类型一致,不管我们参数相不相同,只要函数分别在基类跟派生类当中,只要不满足我们重写的要求的同名函数都可以构成函数的隐藏。之前我们介绍的都是多态的基本的使用方法。
2024-09-12 12:11:01
724
原创 C++当中的多态(一)
所谓的多态在我们的生活当中其实很常见。举一个简单的例子:当我们需要买票的时候有很多种不同的票可以供我们购买,如果你是学生就可以享受半价票的优惠,如果你是VIP用户就可以享受八五折的优惠,如果你是烈士家属就可以享受优先购票的权利.......那么像这种针对于同一个窗口,但是由不同的人,来进行相同的购票操作,最终得到不同的结果的现象就叫做多态。多态实际上就是不同继承关系的类对象,在调用同一个函数,做出了不同行为的现象。比如我们上面编写的代码当中学生类以及VIP类等都继承了购票窗口类。
2024-09-11 22:16:20
1087
原创 C++当中的继承(二)
每一次调用基类的构造函数的时候都会对我们 的静态成员变量进行++操作,这样不论是创建我们的基类对象还是创建我们的派生类对象都会进行统计,我们这个类型的对象个数也就被统计出来了。当我们产生该种继承方式的时候就会出现数据冗余和二义性的问题,因为我们会发现在类B和类C当中都继承了类A,所以我们类A当中的数据自然也就复制了一份到我们的类B和类C当中了,那么派生类D在继承类B和类C的时候又会将类B和类C当中的数据复制一份到我们的类D当中。所谓的虚继承就是专门应对我们菱形继承所带来的问题所引入的概念。
2024-09-10 18:38:43
1090
原创 C++当中的继承
在C++当中继承是一个非常重要的语法。我们可以使用继承快速的进行代码的复用以及对代码进行扩展操作。首先我们来进行学习继承的基本语法。
2024-09-10 18:37:48
976
原创 模板相关知识的补充
我们之前没有产生类似的报错的原因是:我们之前仅仅是使用该模板参数创建了一个对象,对于该对象我们仅仅是调用了其中的成员函数,成员函数的使用方式和语法跟我们成员变量的语法已经内部类的使用语法不会产生冲突,(成员变量的使用语法跟内部类的使用语法产生了冲突)所以就没有出现上述的报错情况。还记得我们上一篇博客当中讲到的:仿函数吗?我们可以对于仿函数进行控制,使得我们得仿函数可以发挥类似于函数的作用。但是如果如果我们不小心传成了指针呢?我们会发现程序运行的结果出现了异常,我们期望的是可以输出12<15的结果。
2024-09-05 17:15:22
1251
原创 priority_queue和reverse_iterator的底层实现
对于priority_queue顾名思义是一个名叫优先级队列的类。但是仅仅通过这个优先级我们并不能判断其具体的用法以及功能。但是如果我们说到优先级队列的本质上应该是一个堆呢?我们的优先级队列实质上是使用堆进行实现的,其功能就是对我们插入的数据进行构建,构建成为一个堆的形式。堆顶的元素永远是数组数据当中最大或者最小的,因此我们可以通过和最后一个数据的交换就可以实现对数组的排序。那么我们就不难想到我们优先级队列应当拥有的函数接口:首先我们需要拥有一个数据的插入接口push,以及一个数据的删除接口pop。
2024-09-05 12:11:27
689
原创 栈和队列的学习以及实现+双端队列的底层原理
但是相信大家肯定会有一个疑惑:我记得我们在使用stack栈的时候不需要传两个参数呀?我们只需要传入一个参数不久可以了吗?我们仔细观察一下stack和queue的模板参数就会发现:在系统库实现的过程当中我们设置了一个默认的模板参数deque。这个默认参数的实现就使得我们不需要手动传入参数就可以正常使用stack。我们同样可以设置一个默认的模板参数。难道这个默认的模板参数只能选择deque吗?我们选择其他的数据容器行不行呢?我们测试一下会发现是完全可以的。
2024-09-01 19:05:57
920
原创 list类底层逻辑实现
list的底层逻辑是一个双向带头链表。那么list的底层其实就跟我们之前实现的带头双向链表相同,都是开辟一个一个单独的节点,最后再通过指针将各个单独的节点链接起来即可。我们来类比之前编写的双向带头链表实现具体的内容。
2024-08-31 20:21:14
1185
原创 list的使用及其相关知识点
作为数据容器之一的list和其他容器的使用上有很多相似的地方,比如都有大致相同的构造函数,大致相同的头插尾插,头删尾删函数。因此对于重复的内容我们就不在赘述,直接介绍关于list和其他数据结构容器不相同的使用方法。
2024-08-28 21:06:06
1445
原创 vector相关功能的底层实现
如果是经常编写C++代码的同学,相信大家肯定对于vector都不陌生。但是对于vector的底层逻辑大家真的熟悉吗?在本次的博客当中我们将会向大家介绍关于vector底层的逻辑,以及在实现底层逻辑需要注意的事项。查阅相关的文档我们会发现,和我们之前编写的string有所不同。vector采用的是三个指针的形式进行表示的vector内存的大小以及容量的。就像上图中所显示的那样,其中的start / finish / end_of_sotrage 才是vector类当中的私有变量。
2024-08-28 09:40:12
871
原创 使用递归形式以及迭代形式实现树的前中后序遍历
相信大家对于二叉树的遍历并不陌生,对于二叉树的递归遍历我们也可以信手拈来。但是如果让我们将二叉树修改成为非递归的形式呢?是不是有点疑惑了?那么本次博客我们就来梳理一下二叉树的非递归遍历。由于递归遍历二叉树的代码以及逻辑都很简单,所以我们直接给出代码的结果,之后直接进行输出结果的比较即可。我们手动构建的树的形式如下图所示。
2024-05-29 12:49:28
1039
原创 程序员代码面试指南(二)
我们可以创建一个栈,向栈当中不断地压入数据,在加入数据之前,我们需要先判断栈是否为空,如果为空就将数组当中指定位置的值修改为INT_MAX,因为该位置可能是边界数据,那么左边就不存在大于该位置的值。假设右侧的孩子节点的数据更大,所以我们child2的父亲节点毫无疑问是parent了,但是对于child1来说,我们会向左侧找到一个大于child1的数据parent,也会向右侧找到一个大于child1的数据child2。这就需要我们证明左右可能产生的节点的情况了,即证明数组的一侧孩子的数量不可能超过1。
2024-05-18 17:18:33
756
原创 力扣刷题:四数相加Ⅱ
在官方题解当中我们可以学到一个解法:我们可以将四个数组分成为两个一组的形式,将一组当中的两个数组进行相加合并,将两个数组当中的元素进行完全匹配相加,合并之后就可以将两组新的数据进行匹配,之后就可以将题目的要求修改为两个数组查找指定的值。所以我们需要重新进行优化,我们可以提前对数组当中的数据进行处理,使用哈希表进行映射,哈希表的键为数组当中数据的值,哈希表的值为数组当中该值出现的次数。我们会发现这种算法的时间复杂度为O(N^2),其主要需要进行的操作就是数组的合并,以及之后的数据查找操作。
2024-05-06 16:17:30
628
原创 插入排序和归并排序算法的实现和优化
插入排序算法是专门对于数组进行排序的一种算法。可以将无序的数组转化成为有序的状态。可以说插入排序算法是我们排序算法当中最简单的算法之一。其主要进行的操作和我们打扑克当中抓拍的思路很相同。我们只需要保证我们最开始的数组为有序状态,拿到一个新的数据的时候就可以将该数据从最右边开始向左进行判断我们新数据想要插入的位置。如果小于我们最右边的数据就进行交换操作。直到第一次数据大于左侧的数据即可。实际过程如下图所示:但是我们可能有的同学会想:要是前面的元素不有序呢?这样不是使用起来很局限吗?
2024-04-16 18:02:51
722
原创 常用算法——双指针算法
所谓的双指针算法看似十分的神秘,但是实质上就是两个标志查找元素的变量。双指针既可以是我们平常最常说的指针(类似int *类型的数据),也可以是数组的下标。因为对于一个数组数据的查找,通过下标我们照样可以找到相应的数据。而我们最经常说到的算法当中的指针并不是平常所说的指针,而是类似于数组下标之类的,方便于查找对应的数据的值。而双指针算法就是通过两个“指针”方便我们查找对应的数据以达到对应要求的算法。
2024-04-14 13:37:02
1249
原创 leetcode刷题系列(一)
为了优化我们的程序,我们在这里向大家介绍一个方法:对于有序的二维数组我们可以将右上角的元素作为标记元素,将我们目标元素和他作比较,如果右上角的元素小于我们的目标元素就可以删除一行的元素,(右上角的元素是本行最大的元素)。如果右上角的元素大于我们的目标元素就可以删除一列的元素,(右上角的元素是本列最小的元素)。但是我们会发现我们数据的总检查的次数为1+2+...+(n-1)+n我们的时间复杂度还是O(N^2),我们所进行的效果很小,算法的时间复杂度还是属于N^2级别的,所以我们还需要思考其他的方法。
2024-04-14 13:35:30
1115
原创 蓝桥杯刷题
之后就是我们的递归的写法,本质上的思路和我们的暴力计算很像,也是将每一种牌看成从 0 - 4 五种情况。如果数字超过13同样直接返回,(需要注意的是我们在传参的时候由于第一次传参的值无法进行四次循环,进行四次循环的是传参的值加一,所以我们需要传入0作为参数,实质上表示牌的点数的数字为 1-13)如果是普通的情况就进行从0-4五次遍历,表示这一种牌总共可能会那几张牌。主要思路就是将每天的跑步数量泛化,也就是将每一天跑步的米数都看成1,等到符合一定的条件的时候将米数再加1,这样可以简化对题目程序的编写。
2023-11-15 12:54:00
595
原创 进程地址空间
所以我们的进程地址空间和页表当中的数据就会和我们进程当中的其他数据一样需要被带走,等到我们的进程再一次需要运行的时候再次被切换到CPU当中。这也是我们一个相同的地址当中可以保存两个不同的数据的原因,相同的只是我们虚拟出来的地址,真正存储数据的物理地址实质上还是不同的。在我们程序的编写过程当中,其实我们所有能够看到的地址都不是实际的物理地址,而是被我们创建出来的虚拟的地址。我们在上面说到过:进程地址空间是属于每个进程所独有的,每个进程在运行的时候都会创建一个属于自己的进程地址空间。
2023-10-29 10:47:03
232
原创 进程相关内容(三)
由于我们操作系统当中的进程有很多种,但是我们的数据资源有限。所以我们的进程在运行的时候需要区分一定的顺序,这样才不会造成进程方面的干扰。所以在我们的操作系统当中引入了进程优先级的概念。
2023-10-18 22:45:35
283
原创 进程相关介绍(二)
当我们的进程运行的时候有很多状态,因为我们的CPU资源是有限的,我们的进程必须有选择性的放入CPU上面才可以运行。因此我们的进程就存在了很多种进程状态,比如运行态,阻塞态,挂起态等等。在本次的博客当中我们就来详细介绍一下关于进程介绍以及进程优先级的相关知识。上述图片就是我们进程当中的许多种状态,由于归类的不同所属状态也不同。我们挑选其中的比较重要的三种状态进行讲解。
2023-10-16 12:28:57
284
原创 进程相关介绍(一)
一个进程实质上就是一个被执行的程序。操作系统会将这个程序使用PCB结构体保管起来,之后通过链表的形式将各个进程的PCB结构体和其相对应的代码数据管理起来。在Linux当中PCB结构体有很多种,最主要的是task_ struct。在task_ struct结构体当中存储着各种进程的的属性。例如:标示符,状态,优先级等等。为了更加清楚的认识进程相关的知识,我们将会依次介绍其中的几个主要的属性以及集中最主要的进程。
2023-10-10 21:46:51
296
原创 操作系统和进程相关的认识
在认识进行相关的知识之前我们需要先认识一下关于操作系统的相关的知识。据我们所知操作系统是位于软件和硬件之间的,可以协调软件和硬件之间的工具,那么我们的操作系统到底是怎么处理硬件与软件之间的关系呢?操作系统又是怎么与硬件链接起来的呢?那么我们就从硬件开始入手,一步步带大家认识一下操作系统的作用原理,以及其中进程的概念。
2023-10-06 16:51:45
220
原创 gdb的使用
在我们编写代码的过程当中我们肯定会遇到程序运行的结果不符合预期的情况,这个时候我们就需要通过调试代码找到错误,并进行修改。在平时的程序编写的时候我们使用的都是VS2019集成开发软件,其中已经封装了图形化界面的调试方案。可以很好的帮助我们进行代码的调试。但是在Linux系统当中,我们要想对代码进行调试就需要使用我们的调试工具,并通过特定的指令进行代码的调试以及运行。在本次的博客当中我们将对比在VS2019环境当中的代码调试步骤以及在Linux当中的代码调试步骤,帮助我们学习gdb代码调试工具。
2023-09-30 19:56:41
451
空空如也
数据结构当中红黑树是最难的部分吗?
2023-04-28
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅