文章目录
- 第一章 DevOps概述与文化理念
-
-
- 1.1 什么是DevOps
-
- 1.1.1 传统软件开发的痛点
- 1.1.2 DevOps的定义
- 1.2 DevOps的历史
- 1.3 CALMS框架
-
- 1.3.1 Culture(文化)
- 1.3.2 Automation(自动化)
- 1.3.3 Lean(精益)
- 1.3.4 Measurement(测量)
- 1.3.5 Sharing(共享)
- 1.4 DevOps vs SRE vs 平台工程
-
- 1.4.1 SRE
- 1.4.2 平台工程
- 1.5 DevOps工程师的角色和技能要求
- 1.6 DevOps工具全景图
-
- 1.6.1 CI侧(从计划到发布)
- 1.6.2 CD侧(从发布到反馈)
- 1.7 如何使用本教程和学习本文
- 第二章 版本控制系统Git
-
- 2.1 版本控制概述
-
- 2.1.1 为什么需要版本控制
- 2.1.2 版本控制系统的发展
- 2.2 Git安装和初始配置
-
- 2.2.1 安装Git
- 2.2.2 初始配置
- 2.3 Git基础概念和工作流程
-
- 2.3.1 三个区域
- 2.3.2 文件的四种状态
- 2.4 创建Git仓库
-
- 2.4.1 git init – 初始化新仓库
- 2.4.2 git clone – 克隆现有仓库
- 2.5 基础Git命令
-
- 2.5.1 git status – 查看状态
- 2.5.2 创建第一个文件
- 2.5.3 git add – 添加到暂存区
- 2.5.4 git commit – 提交
- 2.5.5 git log – 查看提交历史
- 2.5.6 .gitignore – 忽略不需要版本控制的文件
- 2.6 查看修改差异
- 2.7 撤销操作
-
- 2.7.1 修改最后一次提交
- 2.7.2 取消暂存的文件
- 2.7.3 撤销工作目录的修改
- 2.8 分支(Branch)
-
- 2.8.1 什么是分支
- 2.8.2 创建和切换分支
- 2.8.3 合并分支(Merge)
- 2.8.4 处理合并冲突
- 2.8.5 删除分支
- 2.8.6 分支工作流最佳实践
- 2.9 远程仓库(Remote Repository)
-
- 2.9.1 什么是远程仓库
- 2.9.2 添加远程仓库
- 2.9.3 git push – 推送到远程
- 2.9.4 git fetch 和 git pull – 从远程获取更新
- 2.9.5 SSH vs HTTPS
- 2.10 Pull Request(PR)/ Merge Request(MR)
- 2.11 其他有用的Git命令和技巧
-
- 2.11.1 git stash – 暂存工作进度
- 2.11.2 git tag – 打标签
- 2.11.3 git rebase – 变基
- 2.11.4 撤销已经推送到远程的提交
- 2.12 Git学习资源
- 2.13 Git命令速查表
- 第三章 Python编程语言入门
-
- 3.1 Python简介
- 3.2 Python安装和环境配置
-
- 3.2.1 安装Python
- 3.2.2 选择编辑器
- 3.2.3 第一个Python程序
- 3.3 Python基础语法
-
- 3.3.1 变量和数据类型
- 3.3.2 字符串操作
- 3.3.3 输入输出
- 3.3.4 运算符
- 3.4 控制流
-
- 3.4.1 if条件语句
- 3.4.2 for循环
- 3.4.3 while循环
- 3.5 数据结构
-
- 3.5.1 列表(List)
- 3.5.2 元组(Tuple)
- 3.5.3 字典(Dict)
- 3.5.4 集合(Set)
- 3.6 函数
-
- 3.6.1 定义函数
- 3.6.2 返回值
- 3.6.3 参数类型
- 3.6.4 作用域
- 3.7 模块和包
-
- 3.7.1 导入模块
- 3.7.2 安装第三方包
- 3.8 文件操作
-
- 3.8.1 读写文本文件
- 3.8.2 处理JSON
- 3.8.3 处理YAML
- 3.9 异常处理
- 3.10 实战:一个实用的DevOps脚本
- 3.11 Python学习资源
- 3.12 章节练习
- 第四章 Linux操作系统与Shell脚本
-
- 4.1 Linux简介
- 4.2 获取Linux环境
-
- 4.2.1 方式1:Windows WSL2(推荐Windows用户)
- 4.2.2 方式2:虚拟机
- 4.2.3 方式3:云服务器
- 4.2.4 方式4:macOS用户
- 4.3 文件系统基础
-
- 4.3.1 目录结构
- 4.3.2 路径
- 4.4 基础命令
-
- 4.4.1 导航和查看目录
- 4.4.2 查看文件内容
- 4.4.3 创建、移动、复制、删除
- 4.4.4 查找文件和内容
- 4.5 文件权限
-
- 4.5.1 理解权限
- 4.5.2 修改权限
- 4.5.3 用户和组相关命令
- 4.6 进程管理
- 4.7 磁盘和内存
- 4.8 打包压缩
- 4.9 网络相关命令
- 4.10 输入输出重定向和管道
-
- 4.10.1 重定向
- 4.10.2 管道(Pipe)
- 4.11 文本处理三剑客
- 4.12 包管理器
- 4.13 系统服务管理(systemd)
- 4.14 Shell脚本编程
-
- 4.14.1 第一个Shell脚本
- 4.14.2 变量
- 4.14.3 条件判断
- 4.14.4 循环
- 4.14.5 函数
- 4.14.6 实战:备份脚本
- 4.14.7 Shell脚本最佳实践
- 4.15 Vim编辑器基础
- 4.16 Linux学习资源
- 4.17 命令速查表
- 第五章 计算机网络与安全基础
-
- 5.1 网络基础概念
-
- 5.1.1 什么是网络协议
- 5.1.2 TCP/IP协议
- 5.2 DNS:域名系统
-
- 5.2.1 DNS解析过程
- 5.2.2 /etc/hosts文件
- 5.3 HTTP和HTTPS
-
- 5.3.1 HTTP基础
- 5.3.2 HTTPS和TLS/SSL
- 5.4 SSH:安全外壳协议
-
- 5.4.1 SSH基础
- 5.4.2 SSH密钥认证
- 5.4.3 SSH配置文件
- 5.4.4 SCP和SFTP
- 5.5 防火墙
- 5.6 网络安全基础
-
- 5.6.1 安全基本原则
- 5.6.2 常见安全威胁
- 5.6.3 安全实践
- 5.7 网络排查工具和方法
-
- 5.7.1 网络排查流程
- 5.7.2 常用网络工具
- 5.8 网络学习资源
-
第一章 DevOps概述与文化理念
1.1 什么是DevOps
DevOps是Development(开发)和Operations(运维)两个词的组合,但它的含义远不止于开发和运维的简单结合。
要理解DevOps是什么,我们首先需要理解DevOps出现之前软件行业面临的问题。
1.1.1 传统软件开发的痛点
在DevOps出现之前,软件开发和运维通常是两个完全独立的部门,它们之间隔着一堵\”墙\”:
- 开发部门负责编写代码、添加新功能。他们希望软件能够快速迭代,频繁发布新功能
- 运维部门负责保证系统稳定运行。他们希望系统尽量少变动,因为变更意味着风险
这种矛盾导致了一系列问题:
这些问题在软件规模较小、发布频率较低的时候还可以接受,但随着互联网的发展,用户对软件更新速度的要求越来越高,传统模式已经难以为继。
1.1.2 DevOps的定义
DevOps是一套结合了软件开发(Dev)和IT运维(Ops)的实践、文化和工具的集合,旨在缩短系统开发生命周期,同时能够高频率、高质量地交付软件。
DevOps强调:
- 文化(Culture):打破开发和运维之间的壁垒,建立协作、信任的团队文化
- 自动化(Automation):尽可能自动化构建、测试、部署、监控等重复性工作
- 测量(Measurement):通过数据衡量一切,持续改进流程
- 共享(Sharing):知识、经验、工具的共享和透明度
根据本文推荐的经典著作《The DevOps Handbook》中的定义,DevOps旨在创造一种文化和环境,使得构建、测试、发布软件能够更加地快捷、频繁和可靠。
1.2 DevOps的历史
DevOps这个词最早出现在2009年。当时在比利时举办了一次名为\”DevOpsDays\”的会议,由Patrick Debois等人发起。这次会议标志着DevOps运动的正式开始。
但DevOps的思想根源可以追溯到更早:
- 精益制造(Lean Manufacturing):起源于丰田生产方式,强调消除浪费、持续改进
- 敏捷开发(Agile Development):2001年敏捷宣言发布,强调个体和互动、可工作的软件、客户合作、响应变化
- 持续集成(Continuous Integration):由Martin Fowler等人推广,强调开发人员频繁集成代码到主干
- 持续交付(Continuous Delivery):由Jez Humble和David Farley在《Continuous Delivery》一书中系统化,强调软件随时可以可靠地发布
DevOps在这些思想的基础上,进一步将运维也纳入到整个自动化和持续改进的体系中。
本文推荐的书籍《Accelerate: The Science of Lean Software and DevOps》通过多年的科学研究和数据收集,证明了采用DevOps实践的组织能够同时实现更高的交付频率、更短的交付周期、更低的变更失败率和更快的故障恢复时间。这些发现有力地证明了DevOps不是空中楼阁,而是经过科学验证的有效实践。
1.3 CALMS框架
理解DevOps的一个常用框架是CALMS,这是五个英文单词的首字母缩写:
1.3.1 Culture(文化)
文化是DevOps的基础。没有文化的转变,工具和流程都无法发挥作用。
DevOps文化包括:
- 协作而非对立:开发、测试、运维、安全等所有角色共同为产品的成功负责,而不是各自为政
- 共担责任:出现问题时,不是追究\”这是谁的错\”,而是一起反思\”我们的流程哪里有问题,如何改进\”
- 信任与尊重:相信每个人都在为团队尽最大努力,尊重不同角色的专业意见
- 持续学习:鼓励 experimentation(实验),允许犯错,从失败中学习
- 拥抱变化:不惧怕变化,而是通过自动化和良好的实践让变更变得安全
本文推荐的《Effective DevOps》一书专门用大量篇幅讨论如何建立这样的团队文化,如何打破信息孤岛,如何修复团队之间的误解。
1.3.2 Automation(自动化)
自动化是DevOps的核心手段。DevOps工程师的很大一部分工作就是将重复性的手动工作自动化。
需要自动化的领域包括:
- 基础设施 provisioning(供给):通过代码自动创建服务器、网络、数据库等资源,而不是手动在云平台点击
- 配置管理:自动配置服务器的软件环境、安全设置等
- 构建与测试:代码提交后自动构建、运行单元测试、集成测试
- 部署:自动将软件部署到测试环境、生产环境
- 监控与告警:自动监控系统状态,出现问题自动告警甚至自动修复
- 安全扫描:自动进行代码安全扫描、漏洞检测
需要注意的是,自动化不是目的,而是手段。不要为了自动化而自动化。在自动化之前,首先要理解手动流程,确保手动流程是正确的,然后再自动化。否则,自动化只会更快地产生错误。
1.3.3 Lean(精益)
精益思想来自制造业,核心是消除浪费、持续改进。
在DevOps中,精益意味着:
- 识别价值流中的浪费:哪些步骤是不产生价值的?哪些等待时间可以消除?
- 小批量交付:一次交付少量变更,这样问题更容易定位,风险更小
- 限制在制品(WIP, Work In Progress):同时开始太多任务会导致上下文切换成本高,完成率低
- 持续改进:定期回顾流程,寻找可以改进的地方,小步快跑地优化
本文推荐的《The Phoenix Project》是一本用小说形式讲解DevOps和精益思想的经典著作,书中将IT工作比作工厂生产,形象地解释了如何识别和消除工作流程中的瓶颈和浪费。这本书非常适合入门阅读,即使没有技术背景也能读懂。
1.3.4 Measurement(测量)
没有测量就没有改进。DevOps强调用数据说话,而不是凭感觉。
需要测量的关键指标包括《Accelerate》一书中提出的四个关键指标(Four Key Metrics):
高绩效组织能够同时做到:部署频率高(一天多次)、交付周期短(小于1小时)、变更失败率低(小于15%)、平均恢复时间短(小于1小时)。这打破了传统观念中\”变更越多越不稳定\”的误解——良好的DevOps实践可以让你在快速交付的同时保持高稳定性。
除了这四个核心指标,还应该测量:
- 基础设施资源使用率
- 应用性能指标(响应时间、吞吐量、错误率)
- 用户体验指标
- 团队满意度等
1.3.5 Sharing(共享)
共享意味着透明度和知识流通:
- 工具共享:团队使用统一的工具链,避免每个小组各自为政
- 知识共享:通过文档、分享会、结对编程等方式分享知识
- 责任共享:on-call轮值,让开发人员也体验运维工作,运维人员也参与开发
- 最佳实践共享:好的实践在团队内推广,不重复造轮子
1.4 DevOps vs SRE vs 平台工程
你可能还听说过SRE(Site Reliability Engineering,站点可靠性工程)和平台工程(Platform Engineering)这些概念,它们和DevOps是什么关系呢?
1.4.1 SRE
SRE是Google发明的一套实践,在本文推荐的《Site Reliability Engineering》一书中有详细介绍。SRE可以看作是DevOps在Google的具体实现方式,它有一些非常具体的实践:
- 错误预算(Error Budget):服务允许一定的不可用时间(比如99.9%可用性意味着每月有43分钟的允许停机时间),开发和运维共同在这个预算内平衡新功能发布和稳定性
- SLO/SLI/SLA:用服务水平目标(SLO)、服务水平指标(SLI)、服务水平协议(SLA)来量化可靠性
- 减少琐事(Toil):SRE团队将至少50%的时间用于工程工作,而不是重复性的手动操作
- On-call轮值:SRE工程师轮流值班处理生产问题
SRE更偏向运维侧的工程化实践,而DevOps是覆盖整个软件交付生命周期的更广泛的理念。两者并不矛盾,很多实践是相通的。
1.4.2 平台工程
平台工程是近年来兴起的一个概念,它关注于为开发团队构建一个\”内部开发者平台(IDP, Internal Developer Platform)\”,提供一套自助服务的工具和能力,让开发团队可以自主地部署和运维应用,而不需要每次都找运维团队。
本文推荐的《Team Topologies》一书中提出的\”平台团队(Platform Team)\”概念就是平台工程的组织基础。平台团队的职责是构建和维护这个内部平台,为其他团队提供服务,就像内部的云服务商一样。
平台工程可以看作是DevOps发展到一定阶段的产物,当组织规模扩大到一定程度,纯靠文化和协作不足以支撑大规模团队的DevOps实践,就需要专门的平台团队来提供标准化的工具和自助服务。
1.5 DevOps工程师的角色和技能要求
很多人会问:DevOps工程师到底是做什么的?需要掌握哪些技能?
首先需要说明的是,DevOps不是一个单一的职位头衔,不同公司对DevOps工程师的定义可能差别很大。有的公司DevOps工程师主要写自动化脚本,有的主要做Kubernetes管理,有的主要负责CI/CD流水线搭建,有的实际上就是SRE。
但根据本文设计的12步学习路径,一个全面的DevOps工程师应该掌握以下技能领域(这也是本系列教程的内容):
此外还有DevSecOps作为补充,将安全融入DevOps流程。
这看起来是一个很长的清单,不要被吓到。本教程会带你一步步学习。你不需要在一开始就掌握所有这些,本文的目的就是给你一个清晰的学习路径。
1.6 DevOps工具全景图
本文中展示了DevOps工具链的无限循环图,这非常形象地展示了DevOps的工作流。整个流程可以分为两大循环:CI(持续集成)侧和CD(持续交付)侧。
1.6.1 CI侧(从计划到发布)
1.6.2 CD侧(从发布到反馈)
监控收集到的问题和反馈又回到Plan阶段,形成一个持续改进的无限循环。这就是为什么本文中用无限符号(infinity)来表示CI/CD流程。
本文还提供了一个非常有趣的\”DevOps汉堡(DevOps as a Burger, DaaB)\”隐喻,将DevOps技术栈比作一个汉堡:
- 顶部面包:编程能力(Python、Go、JavaScript等)
- 培根:操作系统(Linux、Unix、Windows)
- 生菜:网络与安全(DNS、HTTP、HTTPS、SSL/TLS、SSH)
- 番茄片:服务器相关(Web服务器、缓存、数据库)
- 洋葱圈:基础设施即代码(配置管理、容器、编排、资源供给)
- 芝士片:CI/CD流水线
- 牛肉饼:监控、日志、服务网格(这是核心,就像汉堡的肉饼)
- 底部面包:云平台(AWS、Azure、GCP等)
这个隐喻很形象,缺了任何一层,这个\”汉堡\”就不完整了。
1.7 如何使用本教程和学习本文
在开始技术学习之前,最后给你一些学习建议:
不要追逐热点:今天这个工具火就学这个,明天那个新工具出来又学那个。先把基础打牢,核心概念理解了,学新工具是很快的。比如理解了容器的原理,学Docker和学其他容器运行时都是相通的。
理解为什么,而不只是怎么用:不要只会复制粘贴命令。理解为什么需要这个工具,它解决了什么问题,相比其他方案有什么优缺点。这才是不会过时的能力。
建立自己的知识体系:学过的东西要整理成笔记、思维导图或者自己的实验环境。推荐使用Markdown记笔记,用Git管理你的笔记。
动手做项目:光学不练假把式。可以从搭建自己的博客开始,然后尝试用Docker部署,再用Kubernetes,再搭建CI/CD流水线。自己从头到尾做一个完整的项目,比看十套教程都有用。
加入社区:关注DevOps相关的博客、Newsletter(比如本文作者Milan的Newsletter有50,000+订阅者),参加本地或线上的技术社区,和同行交流。
阅读经典书籍:本文推荐了8本经典书籍,这些书经过了时间的检验,值得反复阅读。不要只看网上零散的博客文章,系统阅读经典书籍能帮你建立完整的知识框架。
本文推荐的8本经典书籍是:
建议你在学习本教程的过程中,配合阅读这些书籍(尤其是《The Phoenix Project》可以先读,建立兴趣和整体概念)。
好了,关于DevOps的理念和文化就介绍到这里。从下一章开始,我们将进入正式的技术学习,从最基础的Git版本控制开始。
第二章 版本控制系统Git
所有你的资源——无论是应用代码还是基础设施即代码文件——都将保存在Git仓库中。Git是DevOps工程师每天都要使用的最基础工具,没有之一。请务必熟练掌握本章内容。
2.1 版本控制概述
2.1.1 为什么需要版本控制
想象一下你在写一篇很长的论文,你可能会这样保存文件:
- 论文v1.doc
- 论文v2_修改了第三章.doc
- 论文v3_老师意见修改版.doc
- 论文v4_最终版.doc
- 论文v4_最终版_真的最终.doc
- 论文v4_最终版_打死也不改了.doc
这种方式有很多问题:
- 文件命名混乱,很难知道哪个版本改了什么
- 多人协作时,每个人都改自己的副本,最后合并非常困难
- 想找回之前删除的内容很麻烦
- 不知道哪行是谁改的,为什么改
版本控制系统(VCS, Version Control System)就是为了解决这些问题而诞生的。它能:
- 记录文件的所有修改历史
- 随时回到任意历史版本
- 支持多人并行开发,自动或手动合并修改
- 记录每一次修改是谁做的、为什么做(提交信息)
- 支持分支(Branch),可以同时开发多个功能而互不干扰
2.1.2 版本控制系统的发展
版本控制系统经历了几代发展:
本地版本控制系统:比如早期的RCS,在本地记录文件的变更。缺点是无法支持多人协作。
集中化版本控制系统(CVCS):比如SVN、CVS,有一个单一的中央服务器保存所有版本,开发者从中央服务器取出文件。缺点是中央服务器是单点故障,如果服务器宕机,所有人都无法工作;如果中央数据库损坏,可能丢失所有历史。
分布式版本控制系统(DVCS):比如Git、Mercurial,客户端并不只提取最新版本的文件快照,而是把代码仓库完整地镜像下来。这样任何一处服务器故障,都可以用任何一个客户端镜像出来的仓库恢复。每个克隆都是完整的备份。Git就是目前最流行的分布式版本控制系统。
Git是由Linux之父Linus Torvalds在2005年创建的,当时Linux内核开发需要一个新的版本控制系统,Linus一怒之下自己写了一个,这就是Git。Git现在是世界上最流行的版本控制系统,GitHub、GitLab等代码托管平台都是基于Git的。
2.2 Git安装和初始配置
2.2.1 安装Git
根据你的操作系统安装Git:
Windows:
macOS:
Linux (Ubuntu/Debian):
$ sudo apt update
$ sudo apt install git
安装完成后,验证安装:
$ git –version
git version 2.40.0 # 你的版本可能不同,只要能显示版本号就说明安装成功
2.2.2 初始配置
安装完Git后,第一件事是设置你的用户名和邮箱,因为每次Git提交都会使用这些信息:
# 设置用户名(建议用你的真实姓名或GitHub用户名)
$ git config –global user.name \”Your Name\”
# 设置邮箱(建议用你注册GitHub/GitLab的邮箱)
$ git config –global user.email \”your.email@example.com\”
–global 参数表示这是全局配置,对你这台机器上的所有Git仓库都生效。如果想针对特定仓库使用不同的用户名或邮箱,可以在那个仓库目录下不加 –global 参数执行同样的命令。
你可以随时查看配置:
# 查看所有配置
$ git config –list
# 查看某一项配置
$ git config user.name
其他一些有用的配置(可选但推荐):
# 设置默认编辑器为VS Code(如果安装了VS Code)
$ git config –global core.editor \”code –wait\”
# 设置默认分支名为main(Git默认是master,现在行业趋势是用main)
$ git config –global init.defaultBranch main
# 让Git在输出时显示颜色
$ git config –global color.ui auto
# 配置换行符处理(Windows用户推荐)
# Windows换行符是CRLF,Linux/macOS是LF,让Git自动处理
$ git config –global core.autocrlf true # Windows上用这个
# $ git config –global core.autocrlf input # macOS/Linux上用这个
配置完成后,我们就可以开始使用Git了。
2.3 Git基础概念和工作流程
在开始命令之前,理解Git的几个核心概念非常重要。
2.3.1 三个区域
Git有三个主要的区域,理解这三个区域是理解Git工作流的关键:
文件在这三个区域之间流转,形成Git的基本工作流。
2.3.2 文件的四种状态
对应三个区域,Git中的文件有四种主要状态:
基本工作流程是:
2.4 创建Git仓库
有两种方式获取一个Git仓库:
2.4.1 git init – 初始化新仓库
让我们先创建第一个Git仓库来练手。打开终端,执行:
# 创建一个练习目录
$ mkdir devops-git-practice
$ cd devops-git-practice
# 初始化Git仓库
$ git init
Initialized empty Git repository in /Users/yourname/devops-git-practice/.git/
这时你会看到目录下多了一个 .git 文件夹(注意前面有个点,表示是隐藏文件夹),这就是Git仓库的核心,所有版本信息都存在这里。不要手动修改这个文件夹里的内容。
现在看一下仓库状态:
$ git status
On branch main
No commits yet
nothing to commit (create/copy files and use \”git add\” to track)
现在我们开始创建一些文件。
2.4.2 git clone – 克隆现有仓库
当你要参与一个已有项目时,你需要克隆(clone)这个仓库:
# 克隆本文仓库到本地(我们可以克隆这个项目来学习)
$ cd .. # 回到上级目录
$ git clone https://github.com/milanm/DevOps-Roadmap.git
这会在当前目录下创建一个 DevOps-Roadmap 文件夹,里面包含了项目的所有文件和完整的Git历史。
如果你想克隆到指定目录:
$ git clone https://github.com/milanm/DevOps-Roadmap.git my-devops-roadmap
对于我们的练习,还是用刚才自己init的仓库。回到练习目录:
$ cd devops-git-practice
2.5 基础Git命令
2.5.1 git status – 查看状态
git status 是你最常用的命令之一,它会告诉你当前仓库的状态:在哪个分支、有没有未提交的修改、哪些文件在暂存区等等。
$ git status
建议你每次执行其他Git命令前后都可以用 git status 看一下,养成习惯。
2.5.2 创建第一个文件
现在让我们创建第一个文件:
# 创建一个README.md文件
$ echo \”# My First Git Project\” > README.md
# 查看状态
$ git status
On branch main
No commits yet
Untracked files:
(use \”git add <file>…\” to include in what will be committed)
README.md
nothing added to commit but untracked files present (use \”git add\” to track)
可以看到README.md是Untracked状态,Git提示我们可以用 git add 来跟踪它。
2.5.3 git add – 添加到暂存区
使用 git add 将文件加入暂存区:
# 添加单个文件
$ git add README.md
# 或者添加所有修改和新文件(注意后面有个点)
# $ git add .
# 再看状态
$ git status
On branch main
No commits yet
Changes to be committed:
(use \”git rm –cached <file>…\” to unstage)
new file: README.md
现在文件变成了\”Changes to be committed\”状态,也就是已暂存,等待提交。
如果添加之后又修改了文件怎么办?让我们试一下:
# 在README.md中追加一行
$ echo \”This is my first Git repository.\” >> README.md
# 看状态
$ git status
On branch main
No commits yet
Changes to be committed:
(use \”git rm –cached <file>…\” to unstage)
new file: README.md
Changes not staged for commit:
(use \”git add <file>…\” to update what will be committed)
(use \”git restore <file>…\” to discard changes in working directory)
modified: README.md
你会发现README.md同时出现在两个地方!因为我们add之后又修改了文件,暂存区里还是之前add的版本,工作目录里是最新版本。如果这时候提交,提交的是暂存区的版本,不是最新的版本。所以如果要提交最新的修改,需要再次add:
$ git add README.md
2.5.4 git commit – 提交
提交就是把暂存区的内容永久保存到Git仓库中。每次提交都需要写一条提交信息(commit message),说明这次提交做了什么。
$ git commit -m \”Initial commit: add README\”
[main (root-commit) f5a1b3c] Initial commit: add README
1 file changed, 2 insertions(+)
create mode 100644 README.md
-m 参数后面跟提交信息。提交信息应该简洁明了,描述清楚这次提交做了什么。好的提交信息示例:
- “add user login feature”
- “fix #123: fix null pointer exception when user is null”
- “update README with installation instructions”
不好的提交信息示例:
- “update”(更新了什么?)
- “fix bug”(修了什么bug?)
- “asdfasdf”(这是什么?)
- “最新版本”(Git本身就记录版本,不需要在提交信息里写)
提交之后再看状态:
$ git status
On branch main
nothing to commit, working tree clean
工作目录是干净的,所有修改都已提交。
如果不加 -m 参数,Git会打开默认编辑器让你写提交信息,可以写更详细的多行提交信息。
2.5.5 git log – 查看提交历史
使用 git log 查看所有提交历史:
$ git log
commit f5a1b3c8d7e6f5a4b3c2d1e0f1a2b3c4d5e6f7a8 (HEAD –> main)
Author: Your Name <your.email@example.com>
Date: Mon Aug 8 10:00:00 2026 +0800
Initial commit: add README
每次提交都有一个唯一的40位哈希值(比如上面的f5a1b3c…),这是提交的ID,可以用来引用特定的提交。HEAD -> main 表示我们当前在main分支,指向这个最新的提交。
更友好的log显示方式:
# 单行显示每个提交
$ git log –oneline
f5a1b3c (HEAD –> main) Initial commit: add README
# 显示分支图形
$ git log –oneline –graph
随着提交增多,–oneline 非常有用。
让我们再做几次提交来熟悉流程:
# 创建一个新文件
$ echo \”print(\’Hello, DevOps!\’)\” > hello.py
$ git add hello.py
$ git commit -m \”Add hello.py script\”
# 修改README
$ echo \”Learning Git is fun!\” >> README.md
$ git add README.md
$ git commit -m \”Add learning note to README\”
再看log:
$ git log –oneline
a1b2c3d (HEAD –> main) Add learning note to README
b2c3d4e Add hello.py script
f5a1b3c Initial commit: add README
注意提交是按时间倒序排列的,最新的在最上面。
2.5.6 .gitignore – 忽略不需要版本控制的文件
不是所有文件都需要纳入版本控制,比如:
- 编译生成的文件(.class、.o、.pyc等)
- 日志文件(*.log)
- 依赖目录(node_modules/、venv/等)
- 系统生成的隐藏文件(.DS_Store、Thumbs.db等)
- 包含敏感信息的配置文件(密码、API key等)
- IDE配置文件
我们可以创建一个 .gitignore 文件告诉Git哪些文件忽略。
创建 .gitignore 文件:
$ cat > .gitignore << \’EOF\’
# Python编译文件
__pycache__/
*.pyc
*.pyo
*.pyd
# 虚拟环境
venv/
env/
.env
# IDE文件
.vscode/
.idea/
*.swp
*.swo
*~
# 系统文件
.DS_Store
Thumbs.db
# 日志文件
*.log
EOF
提交.gitignore:
$ git add .gitignore
$ git commit -m \”Add .gitignore file\”
现在让我们测试一下:
# 创建一个应该被忽略的文件
$ mkdir __pycache__
$ echo \”this should be ignored\” > __pycache__/test.pyc
# 创建一个日志文件
$ echo \”log content\” > app.log
# 查看状态
$ git status
On branch main
nothing to commit, working tree clean
Git忽略了这些文件,不会提示你提交它们。这正是我们想要的。
GitHub提供了各种语言和项目的.gitignore模板:https://github.com/github/gitignore,你可以根据自己的项目类型参考。
2.6 查看修改差异
当你修改了文件,想知道具体改了什么,可以用 git diff。
让我们做一些修改:
$ echo \”# DevOps Learning Journey\” > README.md
$ echo \”I\’m learning Git, Linux, Docker, Kubernetes…\” >> README.md
查看工作目录和暂存区的差异(也就是还没add的修改):
$ git diff
diff –git a/README.md b/README.md
index 1234567..89abcde 100644
— a/README.md
+++ b/README.md
@@ -1,3 +1,2 @@
–# My First Git Project
-This is my first Git repository.
-Learning Git is fun!
+# DevOps Learning Journey
+I\’m learning Git, Linux, Docker, Kubernetes...
– 开头的是被删除的行,+ 开头的是新增的行。
现在add之后再看:
$ git add README.md
$ git diff # 没有输出,因为工作目录和暂存区一致了
如果想看暂存区和最后一次提交的差异(也就是add了但还没commit的内容):
$ git diff –staged
2.7 撤销操作
人总会犯错,Git提供了多种撤销操作的方式。
重要提示:有些撤销操作是不可逆的,可能会丢失工作。执行撤销操作前一定要确认,或者先做个备份。
2.7.1 修改最后一次提交
如果你刚提交完发现提交信息写错了,或者有个文件忘了add,可以用 –amend:
# 修改提交信息
$ git commit –amend -m \”更好的提交信息\”
# 如果你是漏了文件:先add漏掉的文件,再–amend
# $ git add forgotten_file
# $ git commit –amend
注意:–amend 会生成一个新的提交来替换最后一次提交。如果最后一次提交已经推送到远程仓库了,要谨慎使用amend,因为这会改变历史,可能给协作者带来麻烦。
2.7.2 取消暂存的文件
如果你add了一个文件,但不想提交它了,可以把它从暂存区撤回到工作目录:
# 先把文件加入暂存区
$ echo \”temp\” > temp.txt
$ git add temp.txt
$ git status
Changes to be committed:
new file: temp.txt
# 取消暂存
$ git restore –staged temp.txt
$ git status
Untracked files:
temp.txt
老版本Git用的是 git reset HEAD <file>,效果是一样的。git restore 是Git 2.23引入的更直观的命令。
2.7.3 撤销工作目录的修改
如果你修改了文件,但还没add,想回到上次提交时的状态:
# 先修改文件
$ echo \”bad change\” >> README.md
# 看一下diff
$ git diff
...
# 撤销修改(注意:这会丢弃你的修改,无法找回!)
$ git restore README.md
# 文件恢复到了add之前的状态
老版本Git用 git checkout — <file> 来做这件事。
再次提醒:git restore 会丢弃你未提交的修改,执行前一定要确认!如果你不确定,可以先 git stash 暂存修改(后面会讲)。
2.8 分支(Branch)
分支是Git的杀手级功能,也是Git相比其他版本控制系统最强大的地方之一。理解分支是掌握Git的关键。
2.8.1 什么是分支
分支可以让你从主开发线分离出来,在不影响主线的情况下继续开发。比如:
- 你想开发一个新功能,但不想影响稳定的主分支
- 你想修复一个bug,可以建一个bugfix分支
- 多人协作时,每个人在自己的分支开发,完成后合并
Git的分支非常轻量,创建分支几乎是瞬间完成的,切换分支也很快。这和很多其他版本控制系统不同,在那些系统中分支可能是昂贵的操作。
2.8.2 创建和切换分支
查看当前有哪些分支:
$ git branch
* main
* 表示当前所在的分支。
创建一个新分支:
$ git branch feature/python-script
这创建了一个叫 feature/python-script 的分支,但你还在main分支上。切换到新分支:
$ git switch feature/python-script
# 老版本Git用: git checkout feature/python-script
创建并切换到新分支的快捷方式:
$ git switch -c feature/another-feature
# 老版本Git用: git checkout -b feature/another-feature
现在看一下分支:
$ git branch
* feature/python-script
main
在新分支上做些修改:
$ echo \”name = input(\’What is your name? \’)\” > hello.py
$ echo \”print(f\’Hello, {name}! Welcome to DevOps!\’)\” >> hello.py
$ git add hello.py
$ git commit -m \”Make hello.py interactive\”
看一下log:
$ git log –oneline
c3d4e5f (HEAD –> feature/python-script) Make hello.py interactive
d4e5f6a Add .gitignore file
a1b2c3d Add learning note to README
b2c3d4e Add hello.py script
f5a1b3c Initial commit: add README
现在切回main分支看看:
$ git switch main
$ cat hello.py
print(\’Hello, DevOps!\’)
你会发现hello.py回到了之前的版本!因为main分支看不到feature分支上的提交。这就是分支的隔离作用。
2.8.3 合并分支(Merge)
当feature分支上的功能开发完成后,需要把它合并回main分支。
首先切回要合并入的目标分支(main):
$ git switch main
然后执行merge:
$ git merge feature/python-script
Updating d4e5f6a..c3d4e5f
Fast-forward
hello.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(–)
这次合并是\”Fast-forward\”(快进),因为main分支没有新的提交,Git只需要把main指针向前移动。现在看hello.py:
$ cat hello.py
name = input(\’What is your name? \’)
print(f\’Hello, {name}! Welcome to DevOps!\’)
修改已经合并进来了。
2.8.4 处理合并冲突
如果两个分支都修改了同一个文件的同一部分,Git无法自动决定该用哪个版本,就会产生合并冲突。让我们制造一个冲突来学习如何解决。
创建一个新分支并修改文件:
$ git switch -c feature/conflict-demo
$ echo \”This is from conflict-demo branch\” >> README.md
$ git add README.md
$ git commit -m \”Add line from conflict-demo\”
切回main,在同一位置也做不同的修改:
$ git switch main
$ echo \”This is from main branch\” >> README.md
$ git add README.md
$ git commit -m \”Add line from main\”
现在尝试合并:
$ git merge feature/conflict-demo
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
冲突了!看一下状态:
$ git status
On branch main
You have unmerged paths.
(fix conflicts and run \”git commit\”)
(use \”git merge –abort\” to abort the merge)
Unmerged paths:
(use \”git add <file>…\” to mark resolution)
both modified: README.md
打开README.md看看:
# DevOps Learning Journey
I\’m learning Git, Linux, Docker, Kubernetes…
<<<<<<< HEAD
This is from main branch
=======
This is from conflict-demo branch
>>>>>>> feature/conflict-demo
Git用特殊标记标出了冲突区域:
- <<<<<<< HEAD 到 ======= 之间是当前分支(HEAD,这里是main)的内容
- ======= 到 >>>>>>> feature/conflict-demo 之间是要合并进来的分支的内容
你需要手动编辑文件来解决冲突,决定最终保留什么内容。比如我们两行都保留:
# DevOps Learning Journey
I\’m learning Git, Linux, Docker, Kubernetes…
This is from main branch
This is from conflict-demo branch
删除那些<<<<<<<、=======、>>>>>>>标记。然后标记冲突已解决并提交:
$ git add README.md
$ git commit -m \”Merge feature/conflict-demo, resolve conflicts\”
冲突解决完成。
如果在合并过程中想放弃合并,可以执行:
$ git merge –abort
2.8.5 删除分支
合并完成后,分支已经完成了使命,可以删除它:
$ git branch -d feature/python-script
$ git branch -d feature/conflict-demo
-d 参数在分支没有合并时会拒绝删除。如果确定要丢弃未合并的分支,用大写 -D 强制删除。
2.8.6 分支工作流最佳实践
使用分支的常见工作流:
一个常见的分支命名规范:
- feature/功能描述:新功能
- bugfix/问题描述:常规bug修复
- hotfix/问题描述:紧急线上修复
- release/版本号:发布准备分支
2.9 远程仓库(Remote Repository)
到目前为止我们都是在本地操作,Git的真正威力在于多人协作,这就需要远程仓库。
2.9.1 什么是远程仓库
远程仓库是托管在互联网或其他网络上的项目仓库,可以有多个,有的只读有的可写。和别人协作时,需要管理远程仓库,推送(push)和拉取(pull)数据。
最流行的Git托管平台:
- GitHub:https://github.com/ 全球最大的代码托管平台,很多开源项目都在上面
- GitLab:https://about.gitlab.com/ 可以自建,也有托管服务
- Bitbucket:https://bitbucket.org/ Atlassian出品,和Jira集成好
本文推荐学习GitHub或GitLab。我们以GitHub为例。
首先你需要注册一个GitHub账号:https://github.com/join
2.9.2 添加远程仓库
在GitHub上创建一个新仓库(登录后点右上角\”+\” -> “New repository”),仓库名比如 devops-git-practice,选择Public,不要勾选\”Initialize this repository\”(因为我们本地已经有了)。
创建后,GitHub会显示如何把本地仓库推上去。复制仓库地址,类似:https://github.com/你的用户名/devops-git-practice.git
在本地仓库中添加远程仓库:
# 添加远程仓库,通常命名为origin(这是约定俗成的默认名称)
$ git remote add origin https://github.com/你的用户名/devops-git-practice.git
# 查看远程仓库
$ git remote -v
origin https://github.com/你的用户名/devops-git-practice.git (fetch)
origin https://github.com/你的用户名/devops-git-practice.git (push)
2.9.3 git push – 推送到远程
把本地main分支推送到远程:
# -u参数设置上游分支,之后直接git push就可以了
$ git push -u origin main
Enumerating objects: ..., done.
...
To https://github.com/你的用户名/devops-git-practice.git
* [new branch] main –> main
branch \’main\’ set up to track \’origin/main\’.
现在刷新你的GitHub仓库页面,就能看到你推送的代码了!
之后有新的提交,直接 git push 就可以推送到远程。
2.9.4 git fetch 和 git pull – 从远程获取更新
如果别人推了新的提交到远程仓库,你需要获取这些更新。
git fetch 只是下载远程的数据,但不自动合并到你的工作分支:
$ git fetch origin
git pull 会自动抓取并合并远程分支到当前分支:
$ git pull origin main
git pull 实际上相当于 git fetch + git merge。
对于新手来说,建议先 git fetch 看看有什么更新,再手动merge,这样更清楚发生了什么。等熟练之后再用 git pull。
2.9.5 SSH vs HTTPS
Git远程仓库可以通过HTTPS或SSH两种协议访问:
- HTTPS:地址是 https://github.com/…,每次push/pull可能需要输入用户名和密码(或token)
- SSH:地址是 git@github.com:…,需要配置SSH密钥,配置好之后不需要每次输入密码,更方便长期使用
推荐配置SSH密钥:
$ ssh-keygen -t ed25519 -C \”your.email@example.com\”
一路回车即可,会在 ~/.ssh/ 目录下生成 id_ed25519(私钥)和 id_ed25519.pub(公钥)。
# macOS/Linux
$ cat ~/.ssh/id_ed25519.pub
# Windows (Git Bash)
$ cat ~/.ssh/id_ed25519.pub
复制公钥内容,到GitHub -> Settings -> SSH and GPG keys -> New SSH key,粘贴进去保存。
测试连接:
$ ssh -T git@github.com
Hi 你的用户名! You\’ve successfully authenticated, but GitHub does not provide shell access.
配置好SSH后,你可以把远程仓库地址改成SSH格式(或者克隆时就用SSH地址):
$ git remote set-url origin git@github.com:你的用户名/devops-git-practice.git
2.10 Pull Request(PR)/ Merge Request(MR)
Pull Request(GitHub叫PR,GitLab叫MR,本质是一回事)是Git协作的核心机制。
当你想把你的分支合并到主分支时,不是直接push然后merge,而是创建一个PR,请求别人review你的代码,讨论修改,确认没问题后再合并。
基本工作流:
PR的好处:
- 代码审查(Code Review):每个变更都有人审查,提高代码质量
- 讨论:可以在PR下讨论设计决策,留下历史记录
- 自动化检查:可以配置CI自动运行测试、代码检查,不通过不能合并
- 清晰的历史:每个PR对应一个功能或修复,历史清晰
本文中提到的\”Pull request\”是必须掌握的Git协作技能。
2.11 其他有用的Git命令和技巧
2.11.1 git stash – 暂存工作进度
当你正在某个分支开发,工作还没完成不想提交,但需要切换到另一个分支处理紧急问题时,可以用stash把当前工作暂存起来:
# 在feature分支上,做了一些修改但不想提交
$ echo \”work in progress\” >> temp.txt
$ git stash
Saved working directory and index state WIP on main: abc1234 Merge ...
# 工作目录干净了,可以切换分支
$ git switch main
# … 处理紧急问题 …
# 回到feature分支,恢复stash的内容
$ git switch feature-branch
$ git stash pop
常用stash命令:
$ git stash list # 查看所有stash
$ git stash show # 查看stash内容
$ git stash drop # 删除stash
$ git stash pop # 恢复并删除stash
$ git stash apply # 恢复但保留stash
2.11.2 git tag – 打标签
标签通常用于标记发布版本(比如v1.0.0、v2.1.3):
# 创建轻量标签
$ git tag v1.0.0
# 创建带注释的标签(推荐)
$ git tag -a v1.0.0 -m \”Release version 1.0.0\”
# 查看标签
$ git tag
# 推送标签到远程
$ git push origin v1.0.0
# 或者推送所有标签
$ git push origin –tags
2.11.3 git rebase – 变基
rebase是另一种整合分支的方式,和merge不同,它会把提交历史\”变基\”,让历史看起来更线性。rebase是一个强大但也比较危险的命令,新手可以先了解概念,等熟练掌握merge后再深入学习。
黄金法则:永远不要rebase已经推送到远程公共分支的提交,否则会给协作者造成大麻烦。rebase只用于你自己的本地私有分支。
2.11.4 撤销已经推送到远程的提交
如果你不小心把错误的代码推送到了远程,有两种选择:
$ git revert <要撤销的提交哈希>
$ git push
$ git reset –hard <要回退到的提交哈希>
$ git push –force # 谨慎使用!
新手优先使用 git revert。
2.12 Git学习资源
本文推荐了很多优质的Git学习资源,在这里列出来供你深入学习:
免费书籍和在线教程:
- Pro
网硕互联帮助中心




评论前必须登录!
注册