【保姆级】嵌入式工程师的Git第一课:从“硬件版本混乱“到“代码时光机“(环境搭建与核心概念详解)
适用人群STM32/ESP32/FPGA开发者、硬件工程师转型固件开发、单片机裸机开发新手阅读时间15分钟 实践30分钟环境Windows 10/11 Keil MDK / STM32CubeIDE / VS Code目标理解Git设计哲学建立适合硬件开发的版本管理思维避开换行符灾难和二进制文件污染仓库的坑 文章目录为什么硬件工程师更需要Git一、版本控制演进从改崩了只能回炉重造到时空穿梭1.1 本地RCS时代1990s1.2 集中式CVS/SVN2000s1.3 分布式Git2005-至今1.4 嵌入式场景的特殊需求二、Git环境配置避开Windows开发者的第一个坑2.1 安装与基础配置2.2 SSH密钥配置告别每次输入密码2.3 换行符陷阱CRLF vs LF团队混用OS必看2.4 嵌入式专用.gitignore模板三、Git的三区模型理解代码在哪里比会命令更重要3.1 工作区Working Directory3.2 暂存区Staging Area/Index3.3 本地仓库Repository3.4 实战一个STM32文件的生命周期四、阶段实战初始化你的第一个MCU工程仓库五、常见误区与避坑指南总结与下篇预告为什么硬件工程师更需要Git做硬件的兄弟姐妹们都有过这种经历场景A客户说上个版本的固件没问题现在的有问题但你硬盘里只有IMU_v3_FINAL_真的最终版_20240415.hex和IMU_v3_FINAL_不改了_真的_老李看过.hex到底哪个是上个版本场景B同事改了下CAN波特率配置整个系统不通了想看改了哪里结果他说就改了两个寄存器但死活找不回原来的值。场景C你在外地客户现场调试公司内网连不上SVN服务器想保存当前进度都不敢关机。Git就是来解决这些痛点的离线提交在客户现场的笔记本上也能完整记录修改历史回酒店有网了再推送到服务器原子性追溯精确到每一行代码是谁、在哪个硬件版本阶段、为了解决什么问题而修改的分支实验想尝试新的SPI驱动方案开个分支折腾不行就删了重来不影响正在量产的main分支一、版本控制演进从改崩了只能回炉重造到时空穿梭1.1 本地RCS时代1990s最早期的版本控制就像你手动复制粘贴# 假装这是1995年的项目管理project/ ├── main_v1.c ├── main_v2.c ├── main_v3_老板看过.c └── main_v3_老板看过_最终版.c致命缺陷没有差异对比想回退到v1只能手动删除v2/v3的修改且无法协作。1.2 集中式CVS/SVN2000s有了中央服务器解决了协作问题但对嵌入式开发仍有硬伤特性SVN集中式Git分布式嵌入式场景影响网络依赖提交/查看历史必须联网本地完整仓库离线可提交在工厂/外场无网络时可继续开发并记录历史分支操作分支是目录拷贝重且慢分支是指针轻量毫秒级快速切换生产版本和实验版本驱动仓库完整性中央服务器挂掉则历史丢失每个开发者电脑都是完整备份硬件团队的单点故障风险降低嵌入式工程师的选择必须Git。想象一下你在西藏海拔5000米的测试场用笔记本修改了IMU滤波算法SVN没网就提交不了Git可以先本地提交50次有网了再推。1.3 分布式Git2005-至今Git的核心设计哲学是**“快照流”Snapshot Stream而非差异比较Delta**SVN思维记录文件的变化v1→v2改了第3行和第5行Git思维每次提交时如果文件没变就指向上次的快照如果变了存新的Blob对象这对嵌入式开发意味着什么快速切换分支从feature/新算法切回main生产分支时Git不需要像SVN那样来回替换文件内容只是移动HEAD指针毫秒级完成适合频繁在稳定版固件和调试版固件间切换。1.4 嵌入式场景的特殊需求需求Git解决方案实践建议大文件管理Git LFS (Large File Storage).hex、.bin、PDF手册不直接入仓用LFS或Artifactory换行符一致性core.autocrlf配置Windows团队与Linux服务器交叉编译时必须配置代码追溯git blame查Bug时定位这行CAN初始化代码是谁在硬件v2.1时改的版本标签Annotated Tag给发布的v1.2.3固件打标签对应特定硬件BOM版本二、Git环境配置避开Windows开发者的第一个坑2.1 安装与基础配置Windows用户官网下载 Git for Windows安装时注意选择Use Git from Git Bash only推荐避免与Windows cmd冲突Checkout as-is, commit as-is先别选自动转换换行符后面细说基础身份配置必须做否则提交记录找不到人# 配置全局身份公司邮箱gitconfig--globaluser.nameZhang Sangitconfig config--globaluser.emailzhangsancompany.com# 查看配置gitconfig--list# 针对特定项目使用不同身份如个人GitHub vs 公司GitLabcd/path/to/projectgitconfig user.emailzhangsan.personalgmail.com# 去掉--global仅当前仓库生效2.2 SSH密钥配置告别每次输入密码嵌入式项目往往包含子模块或LFS大文件HTTPS每次输入密码很痛苦。# 生成密钥一路回车使用默认路径ssh-keygen-trsa-b4096-Czhangsancompany.com# Windows下查看并复制公钥cat~/.ssh/id_rsa.pub# 或者使用clip命令直接复制到剪贴板clip~/.ssh/id_rsa.pub# 测试连接GitHub/GitLab/Giteessh-Tgitgithub.comssh-Tgitgitlab.com添加到远程仓库GitHubSettings → SSH and GPG keys → New SSH keyGitLabPreferences → SSH Keys标题建议注明设备如ZhangSan-ThinkPad-Win11-20242.3 换行符陷阱CRLF vs LF团队混用OS必看这是嵌入式团队最容易踩的坑Windows默认使用CRLF\r\n作为换行符记事本、KeilLinux/macOS使用LF\n作为换行符交叉编译工具链后果Windows开发者提交的文件到Linux服务器上编译可能每行都显示^M字符甚至导致Shell脚本无法执行配置策略# 方法1强制Linux风格推荐嵌入式团队因为编译服务器多为Linuxgitconfig--globalcore.autocrlf input# 含义提交时自动将CRLF转为LF检出时不转换# 方法2Windows风格如果团队全是Windows开发且使用IAR/Keilgitconfig--globalcore.autocrlftrue# 含义提交时CRLF转LF检出时LF转CRLF# 方法3原汁原味确保文件与操作系统一致二进制文件不会被破坏gitconfig--globalcore.autocrlffalse# 配合.gitattributes精细控制推荐高级用户保险配置配合safecrlf防止混合换行符提交gitconfig--globalcore.safecrlftrue# 拒绝提交混合换行符的文件强制修复后才能提交2.4 嵌入式专用.gitignore模板绝对不能提交到Git的文件编译生成的.axf,.hex,.bin,.lst,.map,.o,.objIDE配置Keil的.uvguix.*用户界面配置、.scvd调试视图临时文件JLinkLog.txt,EventRecorderStub.scvd敏感信息包含WiFi密码或API Key的config.h创建模板保存为项目根目录的.gitignore# Keil MDK *.uvguix.* *.uvoptx *.scr *.scvd JLinkLog.txt EventRecorderStub.scvd Listings/ Objects/ DebugConfig/ RTE/ # 编译输出根据实际输出目录调整 *.axf *.hex *.bin *.elf *.map *.lst *.crf *.d *.o *.obj *.lib *.a # IAR *.eww *.ewd *.ewt settings/ # STM32CubeIDE .metadata/ Debug/ Release/ *.launch # 敏感配置示例 config_secret.h wifi_credentials.h # 通用 .DS_Store Thumbs.db验证.gitignore是否生效# 查看哪些文件被忽略gitcheck-ignore-vmain.hex# 如果已经误提交了build目录从仓库移除但不删除本地文件gitrm-r--cachedbuild/gitcommit-mchore: remove build artifacts from tracking三、Git的三区模型理解代码在哪里比会命令更重要很多新手死记git add和git commit却不理解文件此刻到底在哪。3.1 工作区Working Directory就是你电脑硬盘上能看到的实际文件包括main.c你正在修改的stm32g4xx_hal.c库文件未修改build/编译生成的被.gitignore忽略的状态已修改Modified但Git还没追踪到这些变化。3.2 暂存区Staging Area/Index虚拟的准备打包台。你可以把工作区的多个修改分批放入暂存区组成一个逻辑提交单元。关键理解为什么需要暂存区想象你在调试STM32的CAN通信同时修改了can_driver.c修复波特率计算错误→重要要提交main.c临时加的printf调试信息→只想本地测试不要提交到仓库有了暂存区你可以只把can_driver.c放入暂存区提交而main.c保持在工作区不被提交。3.3 本地仓库Repository.git目录下的数据库保存了所有历史提交的快照。这是Git的时光机核心。关键特性提交到本地仓库后不需要网络历史就已经被永久保存除非你强行删除。3.4 实战一个STM32文件的生命周期# 1. 创建新项目工作区mkdirIMU_ProjectcdIMU_Projectgitinit# 初始化仓库生成.git目录# 2. 添加初始文件从CubeMX生成的工程复制过来# 此时文件在工作区状态为Untracked未被追踪gitstatus# 显示Untracked files: (use git add file... to include in what will be committed)# Inc/# Src/# .mxproject# 3. 选择性地添加到暂存区StaginggitaddSrc/main.c# 只添加源文件gitaddInc/*.h# 添加头文件# 不添加.mxprojectIDE配置不同的人生成的不一样gitstatus# 显示Changes to be committed:# new file: Inc/main.h# new file: Src/main.c# 4. 提交到本地仓库Repositorygitcommit-mfeat: initialize STM32G431 IMU project with HAL library - Add main.c with UART1 initialization - Add BMI323 driver skeleton - Configure HSE 8MHz for 170MHz sysclk# 5. 继续开发修改main.c增加I2C初始化工作区状态# 修改后gitstatus# 显示Changes not staged for commit:# modified: Src/main.c# 6. 查看工作区与暂存区的差异此时暂存区还是旧版本gitdiffSrc/main.c# 7. 添加到暂存区gitaddSrc/main.c# 8. 查看暂存区与上次提交的差异即将提交的变更gitdiff--staged# 9. 提交gitcommit-mfeat: add I2C1 initialization for BMI323 communication# 10. 查看历史时光机启动gitlog--oneline--graph# 输出# * 2a3b4c5 (HEAD - main) feat: add I2C1 initialization for BMI323 communication# * 1d2e3f4 feat: initialize STM32G431 IMU project with HAL library可视化流程工作区Working Dir 暂存区Index 本地仓库Repository main.c (modified) → git add → Staged → git commit → Commit 2a3b4c5 [I2C新代码] [I2C新代码] [永久保存I2C新代码]四、阶段实战初始化你的第一个MCU工程仓库场景你刚用STM32CubeMX生成了一个STM32G431的IMU工程要建立版本管理。步骤清单创建仓库cdD:\Projects\STM32_IMU_v1gitinit创建.gitignore复制上面提供的模板保存为.gitignore文件初始提交只提交源码和配置不提交编译垃圾gitadd.gitignoregitaddCore/Src Core/Inc Drivers/gitadd*.ioc# CubeMX配置文件用于重新生成代码gitcommit-minit: STM32G431 IMU base project - HSE 8MHz, SYSCLK 170MHz - UART1 for debug (115200) - I2C1 for BMI323 (400kHz) - TIM2 for 1ms system tick关联远程仓库假设已在GitLab创建空项目gitremoteaddorigin gitgitlab.company.com:firmware/imu-project.gitgitbranch-Mmaingitpush-uorigin main验证配置检查换行符设置gitconfig--list|findstr crlf# Windows# 应显示 core.autocrlfinput 或 false绝不能是true如果是跨平台团队五、常见误区与避坑指南误区后果正确做法提交.hex文件到仓库仓库体积迅速膨胀每次编译hex都不同几十KB→几MB累积clone极慢用Git LFS管理或在CI中生成hex作为Artifacts不配置.gitignore就提交仓库混入JLinkLog.txt、Objects/目录代码审查时满屏垃圾文件先建.gitignore再git addWindows团队设autocrlftrueLinux服务器拉代码编译Makefile或shell脚本中的换行符变成CRLF执行报错/bin/bash^M: bad interpreter统一设core.autocrlfinput或仓库根目录放.gitattributes强制LF用git commit -m “update”两个月后完全不知道这次提交干了什么无法回退到特定功能版本遵循约定式提交type(scope): subject如feat(can): add 500k baud rate support认为git commit就是保存到服务器了笔记本丢了代码没push几个月工作丢失commit是本地保存push才是同步到远程。重要节点务必push到GitLab/GitHub总结与下篇预告今天我们建立了Git的空间观三区模型和时间观版本控制演进并完成了防坑配置SSH、换行符、.gitignore。核心要点回顾Git是分布式的你的笔记本就是完整仓库离线也能提交历史三区模型决定了代码状态工作区实际文件→ 暂存区准备提交→ 本地仓库永久历史换行符配置是嵌入式Windows开发者必须 explicit 设置的否则跨平台编译会炸.gitignore是仓库的门卫.hex、.o、IDE配置不该进门自检问题如果你修改了main.c后执行git add然后继续修改main.c此时git diff和git diff --staged看到的内容有什么不同为什么git commit后还需要git push如果此时你的硬盘坏了代码会丢失吗下篇预告《【保姆级】Git第二课分支管理与嵌入式Feature开发——如何在维护量产固件的同时开发新传感器驱动》将涵盖分支的本质轻量级指针Gitflow工作流在硬件开发中的应用main量产分支develop集成分支feature/xxx新传感器实验解决合并冲突当同事改了同样的寄存器配置位git stash的妙用临时保存现场去修复产线紧急Bug思考题在你现在的项目中如果让你用Git管理你觉得最大的阻力会是什么是二进制文件太多还是团队不会用命令行欢迎在评论区讨论。版权声明本文为博主原创文章遵循 CC 4.0 BY-SA 版权协议转载请附上原文出处链接和本声明。分类嵌入式开发 版本控制 Git标签Git, STM32, 嵌入式开发, 版本控制, 新手教程, Keil MDK---