未记录事实核验 · 状态:维护中

记录仅说明核验时间与维护状态,不保证适用于所有环境;使用前请留意正文中的版本、适用条件与风险提示。

warning 适用范围与待维护事项

本文用于代码版本控制概念入门,不是生产发布或数据恢复操作指南。开篇“2023 年某公司小王”及“少了好几百万”没有可核实来源,应仅作为保留原稿情节与数字的教学假设,不作真实事故证据。完整本地历史以普通完整克隆为前提,浅克隆不适用;Git 的快照是逻辑模型,底层仍可能采用差异压缩。Git 回退代码不会自动撤销数据库变更,分析与模型复现还依赖数据、依赖版本和运行环境。

版本控制概念 - 为什么数据从业者必须用 Git

abstract 本章概要

  • 理解版本控制解决的核心问题
  • 了解 Git 与 SVN 的根本区别
  • 认识数据项目中版本管理的真实痛点
  • 建立"快照"和"历史"的基本思维模型

一个教学假设故事(原稿情节未核实)

以下将原稿未核实的情节作为教学假设,年份、人物和损失数字均不代表已核实事实:假设在 2023 年,某公司数据团队的 ETL 工程师小王,负责维护一套订单数据清洗脚本。

某天接到需求,要给 VIP 用户的订单金额打 9 折。他改了脚本,上线测试。没问题,发布。

三天后,财务发现对账数字不对,少了好几百万。

排查发现:小王改脚本时,不小心把一行过滤逻辑给注释掉了,导致部分无效订单也进了统计。

最大的问题是:他已经找不回改之前的代码了。备份文件夹里有五六个版本,每个都叫 etl_orders_final.py、etl_orders_final_v2.py,但哪个是"改之前"的那个,没人说得清。

这个教学假设用来说明缺乏版本记录可能造成的排查困难,不代表此类事件的实际发生频率。


什么是版本控制

版本控制(Version Control)是一种记录文件变化历史的系统,使你可以查看特定版本的文件内容,比较不同时间点的差异,以及在需要时恢复到已记录且仍可访问的历史状态。

简单说:版本控制就是给你的代码拍照片,建相册。

每次你做了有意义的修改,就按一次快门(commit),系统记录下此刻代码的状态。以后任何时候,你都能翻回到这张"照片"的时刻。

时间线 ──────────────────────────────────────────►

  v1.0         v1.1         v1.2          v1.3
   │            │            │             │
   ●────────────●────────────●─────────────●
  初始版本    添加VIP折扣   修复过滤bug   优化性能

没有版本控制,数据工作有多痛

痛点一:手动备份地狱

orders_etl.py
orders_etl_v2.py
orders_etl_v2_final.py
orders_etl_v2_final_修改.py
orders_etl_v2_final_修改_确认.py
orders_etl_备份20240315.py
orders_etl_上线前备份.py

这个目录你一定见过。它有几个致命问题:

  • 不知道每个版本改了什么
  • 不知道哪个是真正在用的
  • 存储浪费(每个文件都是全量备份)
  • 时间久了没人敢删

痛点二:协作就是噩梦

小李在改 dim_user.sql 的用户分层逻辑,小张同时也在改这个文件优化 JOIN 性能。

两个人改完,怎么合并?

  • 用邮件互相发文件?丢修改
  • 共享网盘?会互相覆盖
  • 用企业微信发来发去?版本完全乱掉

痛点三:出了问题无法追责也无法回滚

生产环境出了数据质量问题:

  • 谁改的这行代码?
  • 什么时候改的?
  • 改之前是什么逻辑?
  • 怎么快速回到改之前的状态?

没有版本控制,这四个问题没有一个能快速回答。

痛点四:无法并行开发

数据仓库上新功能时,需要同时:

  • 修复生产 bug(紧急)
  • 开发新的指标逻辑(需要两周)
  • 优化现有 SQL 性能(实验性)

没有分支机制,这三件事根本没法同时进行,只能排队做。


Git 是什么

Git 是广泛使用的分布式版本控制系统,由 Linux 内核的创始人 Linus Torvalds 于 2005 年开发。

note Git 的三个关键特性

  1. 分布式:普通完整克隆通常包含所获取分支的完整版本历史,本地查看历史和提交不依赖中央服务器;浅克隆不包含完整历史
  2. 快照模型:逻辑上记录每次提交时已跟踪文件的状态,而非仅记录修改指令;底层存储仍可能采用差异压缩
  3. 轻量分支:创建分支几乎是零成本的,鼓励多分支工作流

Git 的工作区域模型

工作区                暂存区              本地仓库          远程仓库
(Working Dir)    (Staging Area)      (Local Repo)      (Remote Repo)
     │                 │                  │                 │
     │  git add ──►   │  git commit ──►  │  git push ──►   │
     │                 │                  │                 │
     │  ◄── git checkout ──────────────── │  ◄── git pull ──│

这个模型是理解 Git 的关键。先不用完全搞懂,学到 03-Git基础操作 时会有深入讲解。


Git vs SVN:一个根本性的区别

如果你所在的团队使用 SVN(Subversion),有必要了解它与 Git 的差异;本文不据此判断具体行业的采用比例。

对比维度 SVN(集中式) Git(分布式)
存储架构 版本历史由中央仓库管理 普通完整克隆包含所获取分支的完整历史,浅克隆除外
网络依赖 大多数操作需要联网 大多数操作可以离线
分支成本 通常以仓库内的廉价目录拷贝实现,不复制全部文件内容 分支是引用,创建成本很低
分支策略 支持分支,使用频率和合并流程取决于团队 轻量分支常用于并行开发工作流
历史回溯 可以,但需要服务器 本地即可,速度极快
灾难恢复 中央服务器故障可能中断服务,能否恢复取决于仓库备份等措施 完整克隆可恢复其包含的提交历史,但不一定包含服务器配置、权限及外部资产
学习曲线 相对平缓 初期陡峭,熟练后更强大
适用判断 是否保留取决于现有系统与协作需求 是否采用取决于团队工作流与迁移成本

tip 如果你现在还在用 SVN

SVN 支持分支,仓库内创建分支通常也是廉价拷贝,不能理解为“只有主干,分支很贵”。Git 的分支是轻量引用,本地提交和分支工作流更灵活;选择工作流时仍需考虑合并、评审和发布规则。


Git 如何存储数据

理解这个会让你更不容易犯错。

SVN 的方式:集中管理版本

以下保留差异存储的简化示意,用于帮助理解,不代表 SVN 所有存储后端的具体实现,也不能据此推断其历史恢复性能。

版本1: 完整文件 [A, B, C]
版本2: 在版本1基础上改了A → [ΔA, B, C]
版本3: 在版本2基础上改了C → [ΔA, B, ΔC]
恢复到版本3 = 版本1 + ΔA + ΔC(需要计算)

Git 的方式:记录快照

版本1: [A1, B1, C1]     (完整快照,未改变的文件指向同一个对象)
版本2: [A2, B1, C1]     (A改了,用A2;B和C没变,复用之前的对象)
版本3: [A2, B1, C2]     (C改了,用C2;A和B没变,复用)

Git 用这种方式实现了:

  • 按提交访问已记录的快照(逻辑上不必逐次重放修改;底层仍可能解压或还原差异,速度取决于仓库规模和存储布局)
  • 存储高效(相同内容只存一份,用哈希去重)
  • 内容变化可由哈希标识反映(提交内容改变会产生不同的对象标识,但分支引用和历史仍可被重写或删除,不能据此保证历史不可篡改)

三个关键概念

在正式开始操作之前,把这三个概念搞清楚,后续学习会顺畅很多。

概念一:仓库(Repository / Repo)

仓库就是一个被 Git 管理的目录。这个目录里有你的代码文件,还有一个隐藏的 .git 文件夹(Git 用来存储所有版本信息的地方)。

my_data_project/
├── .git/           ← Git 的"大脑",里面是所有历史
├── sql/
│   └── orders.sql
└── scripts/
    └── etl.py

warning 不要手动修改 .git 目录

.git 文件夹是 Git 的核心数据存储,除非你知道自己在做什么,否则永远不要手动改这里的任何东西。误操作可能导致整个仓库损坏。

概念二:提交(Commit)

提交是版本历史中的一个节点,代表某一时刻代码的完整快照。每次提交都有:

  • 一个内容寻址的对象标识(常见仓库使用 SHA-1,也支持 SHA-256;a3f8b2c 是缩写示例,缩写需在当前仓库中足以区分对象)
  • 提交人信息
  • 提交时间
  • 提交说明(你写的 commit message)
  • 零个或多个父提交引用(初始提交没有父提交,普通提交通常有一个,合并提交可有多个)

概念三:分支(Branch)

分支是指向某个提交的可移动指针。创建分支不复制代码,只是新增一个指针。

main  ───●────●────●────●
                        ↑
                   feature/vip-discount
                   (从这里分叉出去)
                        │
                        ●────●
                   (新功能的独立开发)

数据项目的版本管理策略思考

不同类型的数据工作,Git 的使用侧重点不同:

工作类型 核心场景 Git 价值
数据分析师 Jupyter Notebook、分析脚本、SQL 查询 复现分析结果、回溯历史版本
数据开发工程师 ETL 脚本、数据管道、调度配置 协作开发、变更管理、回滚
数据架构师 建表脚本、数据模型、架构文档 方案演进历史、评审记录
数据科学家 模型训练代码、特征工程、实验配置 实验追踪、模型复现

具体的数据项目实践,参见 08-数据项目Git实践。


小结

核心概念 一句话理解
版本控制 给代码建时光机
Git 分布式版本控制,普通完整克隆可在本地保有所获取分支的完整历史
仓库(Repo) 被 Git 管理的项目目录
提交(Commit) 代码历史上的一个存档点
分支(Branch) 并行开发的独立空间
Git vs SVN Git 分布式+引用式分支,SVN 集中式+廉价目录拷贝式分支


掌握检查

  • [ ] 能用一句话解释版本控制解决了什么问题,不用"改来改去"之类的模糊表述
  • [ ] 能解释 Git 的逻辑快照模型与 SVN 的集中式版本管理,并知道不能仅凭快照或差异示意推断历史恢复性能
  • [ ] 知道 .git 文件夹存放什么,以及为什么不能手动修改它
  • [ ] 能区分"工作区""暂存区""仓库"三个概念,并说出数据流向(改了文件 → add → commit)
  • [ ] 知道 Git 的分布式特性意味着什么:普通完整克隆可在本地保有所获取分支的完整历史,断网也能查看已有日志和回退到已有提交;浅克隆的历史范围有限

下一步:Git安装与配置 - 把 Git 装好,连上 GitHub,准备开始实操。