跳到主要内容
🔍
0.3.5已发布beginner · 约 1 课时 · P0

提交规范与 .gitignore

养成规范提交(feat/fix/refactor 前缀)与忽略编译产物的习惯

  • 来源
  • 补充

标记说明:【来源】来自上传资料 · 【补充】课程新编 · 【纠错】按勘误表修正 · 【更新】过时内容已现代化 · 【待确认】无法可靠还原

完成标准(本章)

  • 📖 已阅读:滚动 ≥ 80% 且有效阅读 ≥ 120
  • ✏️ 已练习:小练习正确率 ≥ 60%
  • 📝 已通过测验:分数 ≥ 60
  • 🛠️ 已掌握还需完成实践任务
学习状态:未开始

0.3.5 提交规范与 .gitignore

本章来源:提交规范、分支管理模型与 tag 概念来自《第一阶段讲义》1.6/1.7 节【来源】,经重新组织表述;C/C++ .gitignore 模板、core.autocrlf 说明、本机实验与全部练习为新编【补充】。平台适用性 universal。

① 学习目标

  1. type: 说明 格式写出规范的提交信息(feat/fix/docs/refactor 等前缀);
  2. 说出 main/dev/feature/hotfix 分支模型里各分支的职责;
  3. 会用轻量与附注两种方式打 tag,并说出 tag 与分支的区别;
  4. 为 C/C++ 项目编写 .gitignore,忽略 *.o/*.exe/build/ 等编译产物;
  5. 理解 core.autocrlf 换行符配置的意义(Windows/Linux 协作)。

② 前置知识

  • 必需:0.3.4 远程仓库 Gitee(规范提交是为了让协作方看懂你的历史);
  • 建议:0.3.1-0.3.3(init/add/commit、分支与合并);本章实验只需 gcc 与本机 git。

③ 核心概念【来源】

概念说明
提交规范type: 一句话说明:feat(新功能)、fix(修复缺陷)、docs(文档)、refactor(重构,不改行为)、test(测试)、style(格式)、chore(杂项);如 feat: 添加环境检测脚本
message 三问写清楚为什么改、改了什么、是否影响行为;第一行保持简短(50 字内),细节放正文
分支模型main(稳定发布)、dev(集成开发)、feature/(新功能,合并回 dev)、hotfix/(紧急修复,合并回 main 与 dev);这是团队约定,不是 git 强制
tag给某个提交打不会移动的标签:git tag v0.1(轻量);git tag -a v0.1 -m "说明"(附注,额外记录打标人/时间/说明);用于标记发布版本
tag 与分支分支是"会前进的指针"(新提交自动跟随);tag 是"钉在历史上的图钉"(永远指向打标那次提交)
.gitignore让 git 忽略不需要版本化的文件;语法要点:*.o 通配、build/ 结尾斜杠表示目录、! 否定、/ 开头锚定根目录
core.autocrlfWindows 换行符是 CRLF、Linux/Mac 是 LF;该配置控制仓库内外的换行符转换,避免"整个文件都显示被修改"的噪音

④ 通俗解释【补充】

  • 提交信息 = 快递面单:feat/fix 是"货物类别",一句话说明是"里面装了什么"。写"改了一下"等于面单上只写"东西"两个字——一个月后没人知道这箱货是什么;
  • 分支 = 并行生产线:main 是货架上的稳定版,feature/* 是试验车间,hotfix/* 是紧急维修线,dev 是总装车间;
  • tag = 里程碑印章:v0.1 盖在历史时间轴的某个点上,发布、回滚都按章找;
  • .gitignore = 门禁清单.o/.exe 是"半成品",从不入库——它们随时能重新编译出来,存进版本库只会让仓库臃肿、让 diff 全是噪音。

⑤ 示例代码

代码示例与验证记录

  • examples/gitignore-template.txtC/C++ 项目 .gitignore 模板(实测验证)✓ 已实测(git 2.53.0.windows.2 / Windows 11, 2026-08-15
    编译:复制文件内容为项目根目录的 .gitignore
    适用环境:LinuxWindows(MinGW)macOS
    展开预期输出(实测)
    === .gitignore 生效前(git status --short)===
    ?? build/
    ?? hello.c
    ?? hello.exe
    ?? hello.o
    === 加入 .gitignore 后 ===
    ?? .gitignore
    ?? hello.c
    === 提交后 ===
    (无输出 = 产物已被忽略,工作区干净)
    

    差异说明:本输出为 git 2.53.0.windows.2 / Windows 11 本机实测(实验在系统临时目录进行,结束后已删除);.o/.exe 由 gcc 15.2.0 编译 hello.c 产生,build/ 为手建目录

    完整源码见 /code 代码示例页

  • examples/commit-convention-commands.txt规范提交 + tag 实测序列(feat/fix/docs → v0.1)✓ 已实测(git 2.53.0.windows.2 / Windows 11, 2026-08-15
    编译:按文件内顺序在终端逐行执行
    适用环境:LinuxWindows(MinGW)macOS
    展开预期输出(实测)
    [main (root-commit) 8aa3215] feat: 添加 hello.c
    [main 19b1a9a] fix: 修正返回值
    [main 433c516] docs: 补充 README
    === git tag ===
    v0.1
    === git log --oneline ===
    433c516 docs: 补充 README
    19b1a9a fix: 修正返回值
    8aa3215 feat: 添加 hello.c
    

    差异说明:哈希值(8aa3215 等)每台机器不同;本输出为 git 2.53.0.windows.2 / Windows 11 本机实测

    完整源码见 /code 代码示例页

⑥ 编译与运行方法

本章为文本模板与命令清单,无编译步骤:

  • ex1 是 C/C++ 项目 .gitignore 模板,复制到项目根目录即可;验证方式:git status --short 不再列出 *.o/*.exe/build/
  • ex2 是"规范提交 + 打 tag"的实测序列(feat → fix → docs → tag v0.1 → 查看历史);
  • 两个示例均在本机 git 2.53.0 实测,实验目录在系统临时目录、结束后已删除(见示例卡实测输出)。

⑦ 常见错误

症状原因解决
.gitignore 加了 *.o,git status 仍显示它文件此前已被跟踪(.gitignore 只影响未跟踪文件)git rm --cached 文件 移出跟踪后重新提交
想只忽略根目录 build,结果别处 build 也没了build(无斜杠)会匹配任意层级按需写 build//build(前者只匹配目录,后者锚定根)
! 否定规则不生效父目录整体被忽略时,无法重新包含其子文件先放开父目录再否定子项(进阶用法,见 man gitignore)
git log 里全是"改了一下/update"提交信息无语义,历史无法回溯feat:/fix:/docs: 重写习惯——历史即文档
警告 LF will be replaced by CRLFWindows 与仓库换行符的自动转换提示正常警告;团队统一 core.autocrlf 配置即可

⑧ 小练习

小练习

学习自测:提交后才显示答案与解析(前端判分,不作为正式考试)
  • ex-0-3-5-1.下面哪条提交信息最规范?(单选)

    ◌ 未作答
  • ex-0-3-5-2.想让 git 忽略项目里的 build 目录,.gitignore 里写哪个最合适?(单选)

    ◌ 未作答
  • ex-0-3-5-3.hello.o 之前已被跟踪,加入 *.o 后 git status 仍显示它被修改,原因是?(单选)

    ◌ 未作答

⑨ 章节测验

章节测验

5 题题库 · 随机抽 5 题 · 及格线 60 分 · 前端判分(学习自测)
开始测验 →

⑩ 实战任务

实践任务

给 C 项目配 .gitignore 并打 tag v0.1

用 0.2.4 的 hello 程序(或任意一个 C 项目)编译出 .o/.exe 产物,编写 .gitignore 让 git status 保持干净,按 feat:/fix:/docs: 规范提交 2-3 次,最后打 tag v0.1 标记第一个可用版本。

输入与输出

无程序输入输出。交付物:① 项目目录(含 .gitignore 与至少 2 条规范提交);② git tag 列表含 v0.1。

功能要求

  • 编译自己的 hello 程序产生 .o/.exe 等产物(gcc 15.2.0 或本机任一 C 编译器)
  • 编写 .gitignore 忽略 *.o、*.exe 与 build 目录
  • 按规范前缀完成至少 2 次提交(如 feat: 添加 hello.c、fix: 修正返回值)
  • 用 git tag v0.1 打标签(可进阶使用 -a 附注标签)

限制条件

  • 实验只在本地仓库进行,不创建远程仓库
  • 实验在专用目录进行,不污染课程仓库与已有项目

验收步骤(自检清单 0/4

验收标准

  • git status --short 无 *.o/*.exe/build 产物(验收步骤 2)
  • git log --oneline 至少 2 条且均以 feat:/fix:/docs: 等前缀开头(验收步骤 3)
  • git tag 列表包含 v0.1(验收步骤 4)

常见失败原因

  • 产物此前已被跟踪:.gitignore 不生效(需 git rm --cached 移出跟踪)
  • 提交信息没有前缀(直接写内容,历史无语义)
  • tag 名与已有 tag 重复(git tag 先查看再打)
  • 忘了 git add 就直接 commit(提交里没有文件)

可选扩展

  • 用 git tag -a v0.1 -m 说明 打附注标签,对比 git show v0.1 的信息差异
  • 在 build 目录放一个空文件,确认 build/ 规则同时忽略目录内全部内容

完成必要清单后才能计入"已完成实践"(学习状态自动推导,不提供一键完成)

⑪ 面试问题

面试问题

  • 好的 commit message 有什么标准?团队为什么要统一提交规范?高频C/C++ · easy

    要点:标准:type 前缀 + 一句话说明(feat/fix/docs/refactor 等),第一行简短说清改了什么,需要时正文补充为什么改。统一规范让历史可检索、可回溯、可自动生成发布说明。

    一条好的提交信息回答两个问题:改了什么、为什么改。常见约定(Conventional Commits 风格): feat(新功能)、fix(修复)、docs(文档)、refactor(重构不改行为)、test、style、chore; 第一行保持在 50 字以内,必要时用空行分隔正文补充动机与影响面。团队统一规范的价值: ① git log 即文档——新成员看历史就能理解演进;② 检索与统计——按前缀过滤 git log --grep=fix 快速定位缺陷修复;③ 自动化——按类型自动生成 CHANGELOG、 判断版本号(fix 升 patch、feat 升 minor)、触发对应流水线;④ code review 效率—— 提交粒度与语义清晰,评审者不用猜。反例是"update""改了一下",这类信息对回溯毫无价值。

    追问:
    • 追问:一次提交应该包含多少改动?(单一职责:一个提交只做一件事)
    • 追问:refactor 与 fix 怎么区分?(行为不变是重构;行为变化是修复或新功能)
    评分要点:
    • type 前缀与一句话说明
    • 历史可回溯/可检索/可自动化
    • 提交粒度单一职责
  • .gitignore 的语法要点有哪些?实际使用中最常见的坑是什么?高频C/C++ · medium

    要点:要点:* 通配、以 / 结尾匹配目录、! 否定、/ 开头锚定根目录。最常见坑:已跟踪文件不受 .gitignore 影响,需要 git rm --cached。

    语法要点:① *.o 这类通配匹配任意层级的同名文件;② build/ 结尾斜杠只匹配目录 (build 不带斜杠则文件目录都匹配);③ ! 前缀表示否定(重新包含),但父目录已被整体 忽略时子文件无法用 ! 找回,需先放开父目录;④ / 开头把模式锚定到 .gitignore 所在目录。 常见坑:文件已经被 git 跟踪后,再把它写进 .gitignore 不会生效——.gitignore 只作用于 未跟踪文件;要先 git rm --cached <文件> 把它移出跟踪(保留磁盘文件)并提交。 另一个高频问题是把编译产物(.o/.exe/build)长期留在仓库里,导致每次 diff 全是 产物噪音、仓库膨胀;正确做法是建仓第一版就提交 .gitignore。

    追问:
    • 追问:全局 .gitignore 怎么配置?(core.excludesFile,如 ~/.gitignore_global)
    • 追问:如何查看某个文件为什么被忽略?(git check-ignore -v 文件)
    评分要点:
    • 通配/目录/否定/锚定四点
    • 已跟踪文件不受影响的坑
    • 产物入库的工程危害
  • git tag 与分支有什么区别?发布版本时一般怎么做?C/C++ · medium

    要点:分支是可移动的指针,随新提交自动前进;tag 是固定在某个提交上的标签,不会移动。发布流程:在要发布的提交上打 tag(如 v1.0.0),必要时推送 tag 到远程。

    从实现看两者都是指向提交的引用(refs/heads/* 与 refs/tags/*),但语义完全不同: 分支是"活"的——在其上继续提交时指针自动向前移动;tag 是"死"的——永远指向打标时的 那次提交,用于标记里程碑(发布版本、验收基线)。tag 分轻量(仅一个指针)与附注 (git tag -a,额外记录打标人、时间、说明与 GPG 签名,发布推荐附注标签)。 发布流程:main 上代码稳定后 git tag -a v1.0.0 -m "发布 1.0.0",再 git push origin v1.0.0 推送到远程;之后无论代码怎么演进,都能 git checkout v1.0.0 精确回到发布状态。 反例是把 tag 当分支用(在 tag 上继续提交),会破坏"里程碑不可变"的团队共识。

    追问:
    • 追问:tag 打错了怎么办?(git tag -d 本地删除;已推送的需 git push origin :refs/tags/名字)
    • 追问:语义化版本号 v1.2.3 三段分别代表什么?(major.minor.patch)
    评分要点:
    • 可移动与固定的本质区别
    • 轻量/附注两种 tag
    • 发布与回滚场景

⑫ 延伸阅读

  • Conventional Commits 规范(conventionalcommits.org,只引名称不复制内容);
  • 《Pro Git》第 2 章"记录每次更新到仓库"(官方免费书);
  • 本地手册:git help commit / git help tag / man gitignore
  • 下一章预告:1.1.1 GCC 编译四阶段与常用选项——正式进入 C 语言正文。

迁移训练(migration training)

把本章技能迁移到 LinuxMac

环节WindowsLinuxMac
命令一致一致一致
换行符CRLF(core.autocrlf=true 入库转 LF)LF,无需转换同 Linux

不变的:提交规范、分支模型、tag、.gitignore 语法完全一致;要配的:Windows 的换行符转换。

内容来源映射

内容部分资料位置标记说明
提交规范(type 前缀与 message 结构)、分支管理模型概览、tag 概念、.gitignore 语法要点第一阶段讲义1.6/1.7 节来源正文在原资料基础上重新组织表述,未大段复制原文
C/C++ .gitignore 模板、core.autocrlf 换行符说明、全部本机实验与练习补充原资料无 C/C++ 专用 .gitignore 模板与换行符配置说明;模板与实验输出为本机实测(git 2.53.0 / Windows 11,实验在系统临时目录进行)