上一篇我们把提交讲成了一串用parent指针串起来的快照链但那只是一条线实际开发中我们不可能大家都在一条线上改代码所以这就引出了分支。分支就是一个指针理解分支最重要的一句话是分支什么都没多存它就是一个指向某个提交的可变指针。在.git/refs/heads/下面一个分支就是一个普普通通的文本文件里面存着 40 个字符的哈希cat.git/refs/heads/main5cccce7a1f3b2c8d9e0f1a2b3c4d5e6f7a8b9c0d就这么简单。所以 Git 建一个分支本质上只是写了一个 41 字节的文件瞬间完成这也是它比 SVN 建分支快几个数量级的根本原因SVN 的分支是真的去复制一份目录出来。A --- B --- C ↑ main main 这个分支指向 CHEAD 是什么HEAD 是我们现在在哪儿的标记唯一需要注意的是它通常不直接指向提交而是指向一个分支cat.git/HEADref: refs/heads/main这叫符号引用意思是 HEAD 指向main这个分支然后main再指向提交 C所以 HEAD 其实是个两层的指向。搞清这一层之后一个新提交产生的过程就很好理解了Git 做的事情是把 HEAD 指向的那个分支往前移一格HEAD 本身纹丝不动它还是指着main。所以切换分支本质上只是改了这个 HEAD 文件的内容不是去搬动什么代码。游离 HEAD如果 HEAD 不指向分支而是直接指向某个提交这种状态就叫游离 HEADdetached HEADgitcheckout HEAD~1HEAD detached at 3520544 nothing to commit, working tree clean这时候我们就是在看一个历史提交HEAD指向3520544这个具体提交而不指向任何分支。可以拿来做实验但如果在这个状态下提交了这些提交不属于任何分支等我们切走之后就没有任何引用指向它们了很容易找不回来除非用reflog这个到第 4 篇讲gitcheckout-qHEAD~1echoxx.txtgitadd.gitcommit-m游离状态下的提交gitcheckout mainWarning: you are leaving 1 commit behind, not connected to any of your branches: 52393a9 游离状态下的提交Git 会好心地提醒我们你丢下了一个提交。想保留的话在切走之前先建个分支就行了git checkout -b new-branch。分支的增删改查查看分支gitbranch# 本地分支当前分支前面有 *gitbranch-v# 带上每个分支的最后一个提交gitbranch-vv# 再带上上游分支第 3 篇会用到gitbranch-a# 包括远程分支gitbranch--merged# 哪些分支已经合并到当前分支了创建和切换gitbranch feature# 只创建不切换gitcheckout feature# 切换gitcheckout-bfeature# 创建并切换最常用gitswitch-cfeature# 同上新命令这里需要注意的是git checkout -b feature是从当前 HEAD 的位置分出去的如果想从别的地方分就在后面跟上起点gitcheckout-bhotfix main# 从 main 分出一个 hotfixgitcheckout-bhotfix a1b2c3d# 从某个提交分删除分支gitbranch-dfeature# 删除如果还没合并会拒绝防止误删gitbranch-Dfeature# 强制删除不管有没有合并-d拒绝删除一个还没合并的分支这个设计是个保护机制。比如一个做到一半的feature分支直接删掉那些提交就真找不回来了其实reflog还能救见第 4 篇。确定不要了再用-D。checkout 和 switchgit checkout是个身兼数职的命令它既能切分支也能恢复文件gitcheckout main# 切分支gitcheckout -- a.txt# 把 a.txt 恢复成暂存区的样子恢复文件gitcheckout HEAD~1# 游离到某个提交同一个命令名承担了语义完全不同的操作其中git checkout -- a.txt这种还是会丢改动的危险操作很容易手滑敲错。所以 Git 2.23 把这两个职责拆成了两个专用命令老写法新写法干什么git checkout branchgit switch branch切分支git checkout -b branchgit switch -c branch建并切分支git checkout -- filegit restore file恢复文件丢弃工作区改动git checkout commitgit switch --detach commit游离到某个提交checkout现在还能用但新写的东西建议用switch和restore语义清楚也不容易误操作。合并现在假设有两个分支各自往前走了要把feature合进maingitswitch maingitmerge feature合并的结果有两种取决于两个分支的位置关系。快进合并如果main从分出去之后一次提交都没有那它的 HEAD 只是停在一个老位置上而feature是在它前面一路走下来的合并前 A --- B(main) --- C --- D(feature) 合并后 A --- B --- C --- D ↑ main, feature这种情况下 Git 不需要真的合并什么只要把main指针挪到D就行了这就叫快进fast-forward没有产生新的提交历史是一条直线。合并提交如果两个分支都往前走了那就分叉了没法靠移动指针解决C --- D (feature) / A --- B \ E --- F (main)这时候git merge feature会创建一个合并提交merge commit它有两个父提交gitmerge --no-ff feature-m合并 featuregitlog--oneline--graph看这个图|/是分叉点A两条线分别是feature的提交C和main的提交D最后|\汇合到合并提交5cccce7。--no-ff的意思是就算能快进也强制生成一个合并提交。为什么要这样因为快进之后历史里看不出这里曾经有个 feature 分支以后想整个回退这个功能就很麻烦得一个个提交去翻。有了合并提交回退功能只要 revert 这一个提交就行。merge 和 rebase 的区别这是分支里最需要搞清的一对也是面试和实际工作中都绕不开的。merge保留真实的分叉上面看到的那个图就是 merge 的结果。分叉在开发过程中是真实存在过的所以 merge 也如实地把它留在了历史里。好处是历史如实反映了当时发生了什么能看出来这些提交是并行开发的。坏处是分支一多图上全是分叉和合并git log会变得很难看。rebase把提交搬过去同样是把feature合进mainrebase 的做法完全不一样gitswitch featuregitrebase maingitswitch maingitmerge --ff-only feature* f3af094 C: feature 的提交 * 3520544 D: main 的提交 * 113a797 A: 初始提交完全没有分叉是一条直线。rebase 做的事情是把feature上的提交一个个拿下来先让feature指到main的最新提交再把刚才拿下来的提交在main最新提交的基础上重新应用一遍。效果看起来就像我本来就是在main最新的基础上开发的。代价是提交被改写了注意上面那个C提交的哈希merge 版本里是d41640drebase 之后变成了f3af094。改动内容完全一样但 commit 的哈希变了。原因就在第 1 篇讲的对象模型里commit 对象存着parent指针父提交变了对象内容就变了哈希自然跟着变。所以 rebase 本质上是产生了一个全新的提交原来那个在历史里消失了。这就是那条黄金法则的由来不要 rebase 已经推送到公共分支的提交。因为别人手里拿着的还是旧的那个提交旧的 SHA我们这边变成了新的两边一比对就是两条不同的历史别人拉取的时候要么报冲突要么被迫跟着改团队里会乱成一团。判断标准很简单这个分支除了我还有别人在用吗。只有自己在用的分支本地分支、自己的 PR 分支可以随便 rebase公共分支main、develop永远不要动。那到底该用哪个场景用哪个把功能分支合进 mainmerge --no-ff保留功能的边界功能分支开发期间同步 main 的最新代码rebase main让自己这边跟上避免以后攒出一次大冲突本地整理乱糟糟的提交rebase -i第 5 篇讲公共分支之间merge绝不要 rebase实践中一个比较常用的组合是开发期间用自己的分支rebase main保持同步这时候分支只有自己用安全功能开发完了合进main的时候用merge --no-ff留下一个合并提交作为这个功能的边界。冲突怎么处理冲突发生在同一个文件的同一段内容两个分支各改了一份的时候。Git 不知道该听谁的就交给我们来决定gitmerge featureAuto-merging a.txt CONFLICT (content): Merge conflict in a.txt Automatic merge failed; fix conflicts and then commit the result.打开a.txt会看到这样的标记 HEAD main 这边改成这样 feature 这边改成这样 feature三段的分工是 HEAD到之间当前分支合并时我们所在的分支也就是 HEAD的内容到 feature之间被合并分支的内容处理方式就是手工把整个冲突块编辑成我们想要的样子然后把那三行标记删掉。比如最终想两边都保留就改成main 这边改成这样 feature 这边改成这样改完之后gitadda.txt# 告诉 Git 这个文件的冲突我解决了gitcommit# 完成合并merge 会自动生成好提交说明git status会一路提示还有哪些文件没解决、下一步该干什么跟着走就行。想反悔怎么办合并和 rebase 中途都可以中止回到操作之前的状态gitmerge--abort# 放弃这次合并回到 merge 之前gitrebase--abort# 放弃这次 rebasegitcherry-pick--abortrebase 过程中还有另外两个参数gitrebase--continue# 解决完冲突继续应用下一个提交gitrebase--skip# 跳过当前这个提交继续下一个需要注意的是 rebase 的冲突处理和 merge 不太一样merge 只解决一次冲突提交完就结束了而rebase 是逐个提交重放理论上每一个提交都可能要解一次冲突所以 rebase 一个提交很多的分支会比较烦。这也是大分支同步主干时定期小步 rebase 比攒到最后一次性 rebase 舒服得多的原因。
企业数字化 ERP 产品动态
相关推荐
跟着鹏哥学习C语言-------写第一篇博客 一 介绍 我是一名大一新生,一直以来对计算机技术都很感兴趣。之前零散接触过一点编程,但总觉得不够,所以决定从现在开始认真走这条路。二 目标关于学习编程的目标,目前给自己定得很明确:第一步就是学会C语… · 2026/9/27 22:57:49
c语言预处理 第十七章 联合体和枚举 第十八章 动态内存管理 第十九章 文件操作 第二十章编译和链接 文章目录前言一、预处理是什么?二、使用1.预处理符号2.#define定义常量3.#define定义宏4.宏替换的规则5.宏函数的对比6.#和##总结前言
随着嵌入式开发和系统编程的不断发展&… · 2026/9/27 22:57:49
数据结构入门必学:时间复杂度、空间复杂度详细解析(附实例代码) 前言在学习算法的时候,我们经常会遇到一个问题:为什么两个程序实现相同功能,一个运行非常快,一个却非常慢?例如:斐波那契数列:long long Fib(int N)
{if(N < 3)return 1;return Fib(N-1)Fib(… · 2026/9/27 22:57:43
基于ROS与Gazebo的AGV工业运输系统仿真实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:30:07
硅碳相变:大模型API选型技术剖析,模型多为何项目更慢 硅碳相变:大模型API选型技术剖析,模型多为何项目更慢
如果你是一位后端工程师或AI应用开发者,大概率在某个深夜对着十几家AI API聚合平台的文档页反复切换过标签。每家都宣称自己接入了几百个模型,价格表长得像一份汇率牌价。真正… · 2026/9/27 23:30:07
Java面试被问Spring循环依赖,这样答加分 三级缓存不是重点,AOP代理才是二级缓存就能解决普通对象的循环依赖:A实例化后放入二级缓存,B创建时能从二级缓存拿到A的早期引用。那为什么还要第三级?因为如果A需要被AOP代理,早期引用必须是代理对象,而不… · 2026/9/27 23:29:54
ab173 JSON懒人工具:零配置、离线、高安全的格式化校验神器 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:29:54
Windows 10下CH340驱动安装与文件替换实战指南 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/27 23:29:54
wordpress做微商城设计对比评测:备案不卡壳的5条黄金法则 wordpress做微商城设计对比评测:备案不卡壳的5条黄金法则 很多老板一上来就问我:为什么我的wordpress做微商城,代码写得很漂亮,后台也配置好了,但就是没法正常访问?答案往往不在代码,而在 备案流程一头雾水 。… · 2026/9/27 23:29:54
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01
MATLAB雷达信号脉冲压缩仿真:LFM线性调频、匹配滤波与距离分辨率实现 简介:这套Matlab仿真工具完整呈现雷达信号脉冲压缩过程,从线性调频(LFM)信号生成、目标回波仿真到匹配滤波压缩处理均有可运行代码支撑,面向电子信息工程、计算机、数学等专业学生,适用于课程设计、期末大作… · 2026/9/27 0:00:01
汕头网站建设制作厂家避坑指南:5大注意事项救急 汕头网站建设制作厂家避坑指南:5大注意事项救急 改个需求建站公司拖一周,这种憋屈事我见得太多了。 很多汕头老板找本地建站团队,签合同前看着方案挺美,一上线就变脸。 今天不聊虚的,直接拆解找 汕头网站建设制作厂家 时的5个核心 注意事项… · 2026/9/27 0:00:01
多模态虚假新闻检测实战:BERT+ResNet双塔与对比学习 简介:基于PyTorch的多模态虚假新闻检测项目完整代码包,面向自然语言处理与计算机视觉交叉方向的开发者、科研人员及毕业设计选题者,解决社交媒体中文本与图像联合识别虚假新闻的问题。系统以BERT预训练模型提取文本语义特征,以Res… · 2026/9/27 0:00:01