g4e基础篇#6 了解Git历史记录
章节目录
1. 基础篇:
- 为什么要使用版本控制系统
- Git 分布式版本控制系统的优势
- Git 安装和设置
- 了解Git存储库(Repo)
- 起步 1 – 创建分支和保存代码
- 起步 2 – 了解Git历史记录
- 起步 3 – 拉取请求 Pull Request 工作机制
Git的版本历史记录采用了与传统集中式版本管理系统完全不同的方式进行组织,在刚开始使用Git的时候我们往往会不知所措,比如看到这样的历史记录。

看到这个七拐八拐的图形,你可能完全不知道它代表了什么。其实这正是Git的特别之处,Git之所以能够实现之前我们所说那些灵活快速的操作,都是因为它采用这种类似链路的版本记录方式。在这一篇中,我们就一起了解一下这个图形是如何生成的。
这里,我们要模拟一个常见的开发场景:
- 你正在开发一个网站的某个新功能,按照Git的推荐方式,你创建了feature1分支来承载这个新功能的代码变更。
- 当你已经在这个功能上完成几次代码提交的时候,你的项目经理告诉你这个网站现在出现了一个严重的线上问题,需要紧急修复。
- 为了能够快速修复这个线上问题,你不能等待下一个版本发布,必须在现有线上版本上进行修复。这时你暂停了feature1分支的开发工作,切换回到master分支,从新拉取一个名为hotfix的分支并在这个分支上开始了线上问题的修复。
- 当你完成了修复并测试通过后,你将hotfix分支合并到master以便立即从新发布线上版本。
- 完成以上工作后,你切换回到feature1分支继续进行新功能的开发直到新的功能也经过测试可以发布。
- 最后你将feature1分支也合并回到master分支,发布到线上环境。
为了演示这个过程,首先我使用 Visual Studio 创建了一个新的Web网站项目,完成了4次提交并推送到了TFS的Git仓库。
初始状态
初始的历史记录显示如下:

用简单的示意图表示,是这样的:

如果使用命令行查看历史记录可以键入如下命令
>>> git log --oneline --graph
以上的–oneline参数让git只输出第一行的注释信息,简化历史记录更加可读;–graph参数用来在命令行中输出图形链路,现在我们还看不到效果,后面就会有变化。
输出的结果如下

注:如果你在使用以上命令的过程中遇到乱码,请参考:常见问题#4
这表示当前的master分支指向版本库最新的一次提交(C4),同时之前的所有提交都是顺序完成的,形成了一个单一主线的链路。在TFS的版本记录视图上你所看到的图形一列表示的是同一个意思。
创建feature1分支并提交2次变更
现在,按照我们在上一篇中介绍的方法,创建feature1分支,并在这上面完成2次新的提交。
此时再次使用上面的命令列出历史记录,你会看到如下结果:

这个时候你就会有点纳闷了,为什么明明做了分支,历史记录仍然是单一的直线呢?不是应该分叉了吗?看一下示意图你就明白了。

Git确实记录了你的分支信息,只不过它非常聪明的只是修改了feature1所指向的提交而已;这时你的master分支仍然指向C4提交,而feature1分支则指向C6提交了。
以上git log所输出的信息中也非常明确的标明了这一点,看一下历史记录的第1行和第3行括号里面内容就明白了。
创建hotfix分支并提交另外2次变更
现在那个讨厌的项目经理给你下达了新的任务,要修复线上问题。因为线上所部署的正是master分支上的最新版本,所以你需要切换到master分支(也就是C4提交所代表的版本)进行修改。
这时你可以使用以下命令完成hotfix分支的创建
>>> git checkout master
>>> git checkout -b hotfix
完成这个操作后,我们在hotfix分支上输出历史记录。

你会看到现在hotfix和master分支同时指向了一个提交记录(C4),示意图如下:

现在我们在hotfix分支上添加2个新的变更,并输出历史记录

现在hotfix所指向的提交变成了 C8,如果再看我们的示意图就可以看到分叉的效果了

但是为什么git 输出的历史记录中仍然是一条直线呢?这是因为对于master, hotfix和feature1任何一个分支而言,他们的改动对于自己都是单向的唯一链路。
合并hotfix分支到master
现在你已经完成了问题修复,可以将代码合并到master并发布到线上环境了,让我们将hotfix分支的代码合并到master主干上。你需要执行下面命令
>>> git checkout master
>>> git merge hotfix
这2条命令的意思是回到master分支并将hotfix分支的改动合并进来,因为hotfix就是基于master分支进行的,所以合并会直接完成不会有任何的冲突出现。

这里出现了一个词Fast-forward,因为hotfix分支是直接在master分支上完成的,所以git其实仅仅修改了master分支的指向到hotfix的当前指向(也就是C8),输出一下log你就看得很清楚了。

对比刚才在hotfix上的log输出,你会看到这里唯一的变化就是本地master分支的指向移动到了最后一条提交上。你也许会注意到这里还有一个origin/master的指向仍然在之前的提交之上,这时因为我们的Git库已经提交到了TFS的中心存储库,而这个origin/master所代表的是这个中心存储库上的master分支所处的位置,因为我们在以上过程中没有给中心存储库推送过代码,所以这个中心存储库的master分支仍然指向的是最初的位置。
到这里你会明白,Git的分支其实就是一个指针而已,通过这个指针对提交的指向,Git可以非常灵活的切换版本。
到了这里,我们的示意图就变成了这个样子了

合并feature1分支到master分支
现在你已经修复了线上问题,可以回到feature1上继续工作了。假设我们提交C9以后feature1的开发工作也已经完成可以合并了。与刚才合并hotfix的方法一样,我们只需要返回master分支并执行合并命令
>>> git checkout master
>>> git merge feature1
执行的效果如下:

现在如果我们再次在master上输出历史记录,你将看到如下效果

你会注意到git创建了一个新的提交 b5bcb0b 并将这个提交的注释设置为 Merge branch ‘feature1’,它的意思是我为你创建了一个新的提交,在这个提交里面保存了feature1合并进来的代码变更。
注意:在执行merge动作的时候出现了3个Auto-merging的信息,这表明Git自动为你完成了3个文件的合并,在实际使用中这样做可能是会出现问题的,因为Git实际上只是根据文件代码行的信息判断是否可以完成自动合并,这种合并并不是永远安全可靠的。这一点我们在进阶篇中会特别介绍。
现在,我们的示意图就变成了这个样子

最后,我们可以同步代码到TFS中心存储库,并查看服务器上的历史记录。你会看到与我们的示意图非常类似的图形显示。
小结
了解Git处理历史记录的方式对于我们用好Git非常重要,特别是在企业级开发中处理复杂的多版本并行开发的过程中。以上我们提到的几个可能令你困惑的地方,比如hotfix分支合并的时候Git仅仅移动指针的行为,以及最后合并feature1分支时Git创建用于合并的提交的方式都是我们在日常开发中常见的情况。理解了Git的特殊处理方式有助于你在遇到类似情况的时候作出正确的判断,并对后面介绍的很多复杂场景更容易理解。
示例代码:
以上示例代码已经推送到 https://github.com/lean-soft/git-history-demo
参考:
相关文章:
- DevOps文档中心的技术实践演进
- 微软研发云全家桶VSTS登陆中国
- Markdown/reST 文档发布流水线
- 几款好用的Git GUI客户端工具
- 使用 SSH 连接 TFS/VSTS 的GIT仓库
- GitHub + VSTS 开源代码双向同步
请关注微信公众号 【devopshub】,获取更多关于DevOps研发运维一体化的信息

g4e基础篇#6 了解Git历史记录的更多相关文章
- g4e基础篇#4 了解Git存储库(Repo)
章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git 分布式版本控制系统的优势 Git 安装和设置 了解Git存储库(Repo) 起步 1 – 创建分支和保存代码 起步 2 – 了解Git ...
- g4e基础篇#2 Git分布式版本控制系统的优势
g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...
- g4e基础篇#3 Git安装与配置
g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...
- g4e基础篇#1 什么是版本控制系统
g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...
- g4e基础篇#1 为什么要使用版本控制系统
g4e 是 Git for Enterprise Developer的简写,这个系列文章会统一使用g4e作为标识,便于大家查看和搜索. 章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git ...
- g4e基础篇#5 创建分支和保存代码
章节目录 前言 1. 基础篇: 为什么要使用版本控制系统 Git 分布式版本控制系统的优势 Git 安装和设置 了解Git存储库(Repo) 起步 1 – 创建分支和保存代码 起步 2 – 了解Git ...
- Git使用基础篇
Git使用基础篇 前言 Git是一个分布式的版本控制工具,本篇文章从介绍Git开始,重点在于介绍Git的基本命令和使用技巧,让你尝试使用Git的同时,体验到原来一个版 本控制工具可以对开发产生如此之多 ...
- Git使用基础篇(zz)
Git使用基础篇 您的评价: 收藏该经验 Git是一个分布式的版本控制工具,本篇文章从介绍Git开始,重点在于介绍Git的基本命令和使用技巧,让你尝试使用Git的同时,体 ...
- Git操作(基础篇)
Git操作(基础篇) Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.Git的读音为/gɪt/.Git是一个开源的分布式版本控制系统,用以有效.高速的处理从很小到非常 ...
随机推荐
- 固定底部导航菜单-续集(BottomMenu-移动端V3.0)
固定底部导航菜单-续集(BottomMenu-移动端V3.0) 适应在客户端,点击弹出二级菜单.因为手机不支持hover.所以使用click点击实现弹出菜单,并且一级菜单聚焦变色,变化背景图片 核心c ...
- 【转】WEB测试要点总结
一.输入框 1.字符型输入框: (1)字符型输入框:英文全角.英文半角.数字.空或者空格.特殊字符"~!@# ¥%--&*?[]{}"特别要注意单引号和&符号.禁止 ...
- 【Dijkstra堆优化】洛谷P2243电路维修
题目背景 Elf 是来自Gliese 星球的少女,由于偶然的原因漂流到了地球上.在她无依无靠的时候,善良的运输队员Mark 和James 收留了她.Elf 很感谢Mark和James,可是一直也没能给 ...
- 转自 BotVS 量化平台社区 --- 如何从绩效报告中分辨出“好模型 or 坏模型”
## NO:01 在投资行业一直有一个说法,靠交易盈利是所有赚钱方式中最难的一种,以至于有人戏谑称交易为投资领域的搬砖工作. 为了提升交易效率.挖掘潜在投资机会,量化交易伴随着信息技术的发展大行其道, ...
- Mark下js最大精确整数范围,业务中出现的疑难bug
今天在跟后端联调中,偶然发现几个数据的id居然一样,我就询问了下后端这是什么情况,然而后端告诉我说并没有相同的id,于是开始一起排查问题. 排查中发现,从后端拿来的数据在浏览器控制台NetWork ...
- springboot开启access_log日志输出
由于在调试时需要查看access_log日志,但是springboot默认并没有开启,因此查看了一下文档,在springboot的配置文件中添加如下设置,即可将日志输出当磁盘文件中以供查看. #日志开 ...
- 谈谈关键字new
1.在情人节那天,无意间看到空间有人说,没有对象就new一个,然后就可以........ 程序中我们常用到X a=new X(), new在这里是创建一个对象,也可以叫做创建一个实例,我们先谈谈后半部 ...
- H5+Ajax+WebApi实现文件下载(进度条,多文件)
前言 踩过的坑 1.WebAPI跨域 2.Jquery ajax低版本不支持XHR 2功能 3.Jquery ajax不支持Deferred的process事件 4.IE下文件名乱码问题 功能实现 & ...
- 谈谈Grunt,NPM,Gulp
随着前端工程化的趋势,产生了越来越多的构建工具,而其中比较优秀的就是grunt,npm,gulp,今天我来说说这三者间的区别以及他们的优缺点. 相信一般前端开发者选择构建工具的时候,更多的是看个人习惯 ...
- hdu_1754I Hate It(线段树)
hdu_1754I Hate It(线段树) 标签: 线段树 题目链接 题意: 中文题意...不多说了,线段树基础题 直接上代码: #include<cstdio> #include< ...