21、代码版本控制:Git基础、.gitignore配置、分支管理策略
说到代码版本控制,我敢说这是每个嵌入式工程师的必修课。早些年我刚入行那会儿,项目组还在用U盘拷代码、用日期命名文件——"main_final_0315.c"、"main_final_0315_v2.c"……现在想想真是后怕。有一次我改了个驱动文件,同事也改了同一个文件,结果我俩的修改互相覆盖,查了两天bug才发现问题。从那以后,我彻底成了Git的忠实用户。
说白了,Git就是你的代码时光机。它能记录每一次修改,能让你在不同版本之间自由穿梭,还能让团队协作变得井井有条。今天我就把Git在嵌入式项目中的核心用法掰开揉碎了讲给你听。
Git基础:你只需要记住这几个命令
很多初学者一上来就被Git的复杂概念吓住了。其实你想想看,日常开发中真正高频使用的命令就那么几个。我个人的习惯是:先掌握核心工作流,再慢慢深入高级功能。
嵌入式项目通常包含源码、头文件、链接脚本、Makefile、配置文件等。我们用一个简单的STM32项目来演示:
# 初始化一个仓库
git init
# 把文件加入暂存区
git add main.c
git add driver/
git add Makefile
# 提交到本地仓库
git commit -m "feat: 添加GPIO驱动和主循环框架"
# 查看当前状态
git status
# 查看提交历史
git log --oneline --graph
这里有个小细节我要提醒你:git commit 的提交信息一定要写清楚。我在项目中见过太多"update"、"fix"、"aaa"这种毫无意义的提交信息。等过两个月回来看,根本不知道当时改了啥。我建议你参考 Conventional Commits 规范,用 feat:、fix:、docs: 这样的前缀来分类。
核心工作流总结
工作区 → git add → 暂存区 → git commit → 本地仓库 → git push → 远程仓库
反过来:远程仓库 → git pull → 本地仓库 → git checkout → 工作区
.gitignore配置:别把垃圾文件提交上去
嵌入式项目有个特点:编译产物特别多。.o 文件、.hex 文件、.map 文件、IDE的工程配置……这些东西如果都提交到仓库里,那仓库体积会迅速膨胀,而且每次编译都会产生变更,非常烦人。
我曾经接手过一个项目,仓库里塞满了各种编译中间文件,光是 .o 文件就有几百兆。clone一次要等半天,而且每次pull都会因为 .o 文件冲突而报错。后来我花了一下午清理仓库,并配置了 .gitignore,世界清净了。
下面是一个嵌入式C项目的标准 .gitignore 模板:
# 编译产物
*.o
*.a
*.so
*.elf
*.hex
*.bin
*.map
# IDE配置(不同IDE不同)
.idea/
.vscode/
*.uvoptx
*.uvguix
*.uvprojx
# 构建目录
build/
Debug/
Release/
# 系统文件
.DS_Store
Thumbs.db
# 日志和临时文件
*.log
*.tmp
*.swp
小技巧:如果你不确定某个文件该不该忽略,可以先 git add 试试。如果Git提示"文件已被忽略",那就说明 .gitignore 生效了。另外,.gitignore 本身也要提交到仓库里,这样团队所有人都能共享相同的忽略规则。
分支管理策略:让团队协作不再打架
分支管理是Git的精髓所在。我见过不少团队,所有人都在 master 分支上开发,结果就是天天冲突、天天合并,代码质量一塌糊涂。其实只要用对分支策略,这些问题都能避免。
我个人最推荐的是 Git Flow 的简化版,特别适合嵌入式项目。为什么?因为嵌入式项目通常有明确的硬件版本、固件版本,需要同时维护多个release分支。
下面这张图展示了嵌入式项目常用的分支结构:
具体怎么用呢?我拿一个实际项目举例:
# 1. 从develop分支创建feature分支
git checkout develop
git checkout -b feature/add-i2c-driver
# 2. 在feature分支上开发
# ... 写代码、测试 ...
git add .
git commit -m "feat: 添加I2C驱动基础框架"
# 3. 开发完成,合并回develop
git checkout develop
git merge --no-ff feature/add-i2c-driver
# 4. 准备发布时,创建release分支
git checkout -b release/v1.2.0
# 5. 在release分支上只做bug修复,不添加新功能
# ... 修复bug ...
git commit -m "fix: 修复I2C时钟配置错误"
# 6. 发布后合并到master和develop
git checkout master
git merge --no-ff release/v1.2.0
git tag v1.2.0
git checkout develop
git merge --no-ff release/v1.2.0
注意:千万不要在 master 分支上直接开发。master只用来存放已经发布的、稳定的版本。每次合并到master时,都应该打一个tag,比如 v1.0.0、v2.1.3。这样万一出了问题,可以快速回退到上一个稳定版本。
嵌入式项目的特殊考量
嵌入式开发和纯软件项目不太一样。我遇到过几个坑,这里一并告诉你:
- 硬件依赖问题:不同硬件版本的代码可能不兼容。建议为每个硬件版本创建独立的分支,比如
hw-v2.0、hw-v3.0。通用代码放在develop分支,硬件相关代码放在对应分支。 - 二进制文件管理:编译生成的
.hex或.bin文件不要提交到Git仓库。这些文件体积大、变更频繁,而且无法diff。应该用CI/CD工具自动构建和存档。 - 子模块(submodule)的使用:如果项目依赖第三方库(比如FreeRTOS、LwIP),建议用Git submodule来管理。这样能保持依赖版本可控,不会因为第三方库更新而意外破坏你的代码。
# 添加子模块
git submodule add https://github.com/FreeRTOS/FreeRTOS.git libs/FreeRTOS
# 克隆包含子模块的项目
git clone --recursive https://github.com/your/project.git
# 更新子模块
git submodule update --remote
我的习惯:每次提交前,我都会先 git diff 看一下改了什么。这能帮我发现一些无意的修改,比如不小心改了个空格、多了个空行。保持提交的"原子性"——一个提交只做一件事,这样回滚和代码审查都会轻松很多。
好了,Git的基础用法、.gitignore 配置和分支管理策略就讲到这里。这些内容看起来简单,但真正用好需要在实际项目中不断练习。记住一点:版本控制不是束缚你的工具,而是保护你的铠甲。养成好习惯,你的代码会感谢你的。
公众号:蓝海资料掘金营,微信deep3321