本地























bash
11400@▒▒ MINGW64 ~
$ git config --global user.name "xiaocao"
11400@ MINGW64 ~
$ git config --global user.email 1140075663@qq.com
11400@ MINGW64 ~
$ cd /D/vsprogram/WpfApp6
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git init
Reinitialized existing Git repository in D:/vsprogram/WpfApp6/.git/
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git add .
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git commit -m "feat:X光检测上位机-完整"
[remove-legacy-mainvm 16e9f15] feat:X光检测上位机-完整
2 files changed, 599 deletions(-)
delete mode 100644 WpfApp6/MainViewModel.cs
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git branch
master
* remove-legacy-mainvm
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git branch -r
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git branch -a
master
* remove-legacy-mainvm
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git branch
master
* remove-legacy-mainvm
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git status
On branch remove-legacy-mainvm
nothing to commit, working tree clean
11400@ MINGW64 /D/vsprogram/WpfApp6 (remove-legacy-mainvm)
$ git checkout -b archive-axiscontrolviewmodel
Switched to a new branch 'archive-axiscontrolviewmodel'
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ mkdir -p Archive/Legecy
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv ViewModel/AxisControlViewModel.cs Archove/Legacy/
fatal: bad source, source=ViewModel/AxisControlViewModel.cs, destination=Archove/Legacy/
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv ViewModel/AxisControlViewModel.cs Archive/Legacy/
fatal: bad source, source=ViewModel/AxisControlViewModel.cs, destination=Archive/Legacy/
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv ViewModel/AxisControlViewModel.cs Archive/Legecy/
fatal: bad source, source=ViewModel/AxisControlViewModel.cs, destination=Archive/Legecy/AxisControlViewModel.cs
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv /ViewModel/AxisControlViewModel.cs Archive/Legec
y
fatal: Invalid path 'C:/Program Files/Git/ViewModel': No such file or directory
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv ViewModel/AxisControlViewModel.cs Archive/Legecy
fatal: bad source, source=ViewModel/AxisControlViewModel.cs, destination=Archive/Legecy/AxisControlViewModel.cs
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ mv Archive/Legecy Archive/Legacy
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ mv ViewModel/AxisControlViewModel.cs Archive/Legacy/
mv: cannot stat 'ViewModel/AxisControlViewModel.cs': No such file or directory
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ ls ViewModel/
ls: cannot access 'ViewModel/': No such file or directory
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ ls ./ViewModel
ls: cannot access './ViewModel': No such file or directory
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git ls-files
.gitattributes
.gitignore
WpfApp6.sln
WpfApp6/AXISafeIO.cs
WpfApp6/App.config
WpfApp6/App.xaml
WpfApp6/App.xaml.cs
WpfApp6/Base/ViewModelBase.cs
WpfApp6/Converters/EnumDescriptionConverter.cs
WpfApp6/Enums/DeviceStatus.cs
WpfApp6/EtherCATConfig.cs
WpfApp6/EtherCATMaster.cs
WpfApp6/Interfaces/IEtherCATMaster.cs
WpfApp6/Interfaces/ILogService.cs
WpfApp6/Interfaces/IXYScanAxis.cs
WpfApp6/MainWindow.xaml
WpfApp6/MainWindow.xaml.cs
WpfApp6/Messages/AppMessages.cs
WpfApp6/Properties/AssemblyInfo.cs
WpfApp6/Properties/Resources.Designer.cs
WpfApp6/Properties/Resources.resx
WpfApp6/Properties/Settings.Designer.cs
WpfApp6/Properties/Settings.settings
WpfApp6/Services/LogService.cs
WpfApp6/ViewModel/AxisControlViewModel.cs
WpfApp6/ViewModel/AxisEcatVM.cs
WpfApp6/ViewModel/MainShellVM.cs
WpfApp6/ViewModel/MainViewModel.cs
WpfApp6/ViewModel/XrayImageVM.cs
WpfApp6/WpfApp6.csproj
WpfApp6/XYScanAxis.cs
WpfApp6/packages.config
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git mv WpfApp6/ViewModel/AxisControlViewModel.cs Archive
/Legacy/
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git commit -m "Archive:移动AxisControlViewModel至Legacy 目录,消除冲突"
[archive-axiscontrolviewmodel f89f4aa] Archive:移动AxisControlViewModel至Legacy目录,消除冲突
1 file changed, 0 insertions(+), 0 deletions(-)
rename {WpfApp6/ViewModel => Archive/Legacy}/AxisControlViewModel.cs (100%)
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git log
commit f89f4aa25d8b2ac32a3487383c47039290c755e0 (HEAD -> acommit f89f4aa25d8b2ac32a3487383c47039290c755e0 (HEAD -> archive-axiscontrolviewmodel)
Author:
Date: Thu Jun 4 20:49:33 2026 +0800
Archive:移动AxisControlViewModel至Legacy目录,消除冲突
commit 16e9f15fe276ee49d3e6afdfa4d62b6379f72b43 (remove-legacy-mainvm)
Author:
Date: Thu Jun 4 19:07:31 2026 +0800
feat:X光检测上位机-完整
commit 5ef4fe5d50ed9b883330864c3df7de772e9ecc2c (master)
Author:
Date: Wed Jun 3 23:01:14 2026 +0800
改
commit 31f222391ee405e5efa18d28410766d76c438e09
Author: 11400 <11400@常念>
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrol
viewmodel)
$
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git push origin archive-archive-axiscontrolviewmodel
error: src refspec archive-archive-axiscontrolviewmodel do
es not match any
error: failed to push some refs to 'https://github.com/zhixincao1123/WpfApp6.git'
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git push origin archive-axiscontrolviewmodel
fatal: unable to access 'https://github.com/zhixincao1123/WpfApp6.git/': Recv failure: Connection was reset
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolvi
ewmodel)
$ git push origin archive-axiscontrolviewmodel
fatal: unable to access 'https://github.com/zhixincao1123/
WpfApp6.git/': Failed to connect to github.com port 443 after 21066 ms: Could not connect to server
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolvi
ewmodel)
$ git push origin archive-axiscontrolviewmodel
fatal: unable to access 'https://github.com/zhixincao1123/WpfApp6.git/': Failed to connect to github.com port 443 after 21065 ms: Could not connect to server
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git reflog
f89f4aa (HEAD -> archive-axiscontrolviewmodel) HEAD@{0}: commit: Archive:移动AxisControlViewModel至Legacy目录,消除
冲突
16e9f15 (remove-legacy-mainvm) HEAD@{1}: checkout: moving from remove-legacy-mainvm to archive-axiscontrolviewmodel
16e9f15 (remove-legacy-mainvm) HEAD@{2}: commit: feat:X光
检测上位机-完整
5ef4fe5 (master) HEAD@{3}: checkout: moving from master to remove-legacy-mainvm
5ef4fe5 (master) HEAD@{4}: commit: 改
31f2223 HEAD@{5}: commit: 添加项目文件。
2ae7d24 HEAD@{6}: commit (initial): 添加 .gitattributes 和 .gitignore。
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git branch
* archive-axiscontrolviewmodel
master
remove-legacy-mainvm
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolvi
ewmodel)
$ git add .
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git commit -m "修改内容:AppMessage AxisEcatVM 增加消息
内容 不可变Dto 改"
[archive-axiscontrolviewmodel cfa853a] 修改内容:AppMessag
e AxisEcatVM 增加消息内容 不可变Dto 改
3 files changed, 60 insertions(+), 33 deletions(-)
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git status
On branch archive-axiscontrolviewmodel
nothing to commit, working tree clean
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git push
fatal: The current branch archive-axiscontrolviewmodel has
no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin archive-axiscontrolviewmodel
To have this happen automatically for branches without a t
racking
upstream, see 'push.autoSetupRemote' in 'git help config'.
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git reflog
cfa853a (HEAD -> archive-axiscontrolviewmodel) HEAD@{0}: commit: 修改内容:AppMessage AxisEcatVM 增加消息内容 不可变Dto 改
f89f4aa HEAD@{1}: commit: Archive:移动AxisControlViewModel
至Legacy目录,消除冲突
16e9f15 (remove-legacy-mainvm) HEAD@{2}: checkout: moving from remove-legacy-mainvm to archive-axiscontrolviewmodel
16e9f15 (remove-legacy-mainvm) HEAD@{3}: commit: feat:X光
检测上位机-完整
5ef4fe5 (master) HEAD@{4}: checkout: moving from master to remove-legacy-mainvm
5ef4fe5 (master) HEAD@{5}: commit: 改
31f2223 HEAD@{6}: commit: 添加项目文件。
2ae7d24 HEAD@{7}: commit (initial): 添加 .gitattributes 和 .gitignore。
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git add .
11400@ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git commit -m "修改MainShellVm.StartScan方法 本质继续增 加消息内容 不可变DTO"
[archive-axiscontrolviewmodel 6b4dfcc] 修改MainShellVm.StartScan方法 本质继续增加消息内容 不可变DTO
2 files changed, 35 insertions(+), 21 deletions(-)
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (archive-axiscontrolviewmodel)
$ git checkout -b xaml
Switched to a new branch 'xaml'
11400@ MINGW64 /D/vsprogram/WpfApp6 (xaml)
$ git add .
11400@ MINGW64 /D/vsprogram/WpfApp6 (xaml)
$ git commit -m "XAML绑定改变 .cs改变"
[xaml 02c1689] XAML绑定改变 .cs改变
3 files changed, 59 insertions(+), 56 deletions(-)
11400@▒▒ MINGW64 /D/vsprogram/WpfApp6 (xaml)
$
Git分支的核心作用
Git分支是隔离开发任务、并行推进工作、保护主代码稳定的核心工具,
一、核心作用总览
| 作用 | 通俗解释 | 上位机开发场景价值 |
|---|---|---|
| 隔离开发 | 一个任务一个分支,互不干扰 | 双扫描模式开发不影响主分支稳定,急停功能调试不打断点位扫描代码 |
| 并行工作 | 多人/多任务同时推进 | 你做运控逻辑,同事做Halcon视觉算法,各自分支独立开发 |
| 风险控制 | 不稳定代码不进主分支 | 限位报警逻辑测试失败时,直接放弃分支即可,不影响已发布版本 |
| 版本管理 | 清晰记录功能迭代历史 | 从remove-legacy-mainvm分支可追溯X光检测系统的演进轨迹 |
| 协作规范 | 强制代码评审与合并流程 | 新功能必须通过PR合并,避免个人错误代码污染生产环境 |
二、详细作用拆解
1. 隔离开发:保护主分支"永远可运行"
- 核心价值 :开发中的半成品代码不会污染稳定的主分支(
main/master),确保随时可发布、可回滚 - 项目实例 :
- 在
feature/double-scan-mode分支开发双扫描模式(点位+连续),即使代码没写完、有bug,也不会影响主分支的基础功能 - 主分支始终保持"初始化→就绪→运行→停止"的完整可用流程,随时可用于演示或测试
- 在
2. 并行开发:多人协作不"打架"
- 核心价值:不同开发者/不同任务可同时推进,无需等待他人完成
- 项目实例 :
- 自己开发运控逻辑(轴移动、限位报警)
- 同事A开发Halcon缺陷检测算法
- 同事B优化UI显示(AxisStatusText、进度条)
- 三个分支并行开发,最后通过合并集成,效率提升3倍
3. 风险控制:安全试错与快速回滚
- 核心价值 :
- 实验性功能(如连续扫描新算法)可在独立分支测试,失败直接删除分支,零成本试错
- 紧急问题(如客户现场发现的轴定位偏差)可在
hotfix/axis-position-error分支修复,不影响正常开发
- 项目实例 :
若连续扫描模式开发中出现轴失控风险,可直接放弃该分支,回退到稳定版本,避免整机故障
4. 功能管理:清晰的迭代轨迹
-
核心价值:每个分支对应明确任务,提交历史清晰,便于追溯与协作
-
分支命名规范(上位机推荐) :
feature/双扫描模式-20260604 # 新功能开发 hotfix/急停逻辑修复-20260604 # 紧急bug修复 release/v1.0.0-20260610 # 版本发布准备 refactor/轴控制代码重构 # 代码重构优化 -
项目实例 :
从remove-legacy-mainvm分支名可快速知道这是"移除老旧MainViewModel冗余代码"的优化任务,便于后续维护
5. 协作规范:强制质量门禁
- 核心价值:通过Pull Request(PR)机制,合并前必须通过代码评审、自动化测试,确保代码质量
- 项目实例 :
双扫描模式开发完成后,发起PR请求合并到主分支,领导/同事可检查:- 限位报警是否触发整机停机
- 急停是否同步记录日志
- 操作互斥是否生效(运行中禁用启动按钮)
问题修复后再合并,避免低级错误进入生产环境
三、实战应用
-
基础流程:
bash# 1. 从主分支创建新功能分支 git checkout main git pull git checkout -b feature/double-scan-mode # 2. 开发双扫描模式+急停+限位功能 git add . git commit -m "feat:完成双扫描模式开发,添加急停和限位报警" # 3. 功能完成,合并到主分支 git checkout main git merge feature/double-scan-mode # 4. 删除已完成分支 git branch -d feature/double-scan-mode -
紧急情况处理(如现场发现轴移动异常):
bash# 从主分支创建紧急修复分支 git checkout main git checkout -b hotfix/axis-move-error # 修复问题并提交 git commit -m "fix:解决轴移动时坐标跳变问题" # 快速合并到主分支并发布 git checkout main git merge hotfix/axis-move-error
四、分支使用的关键原则
- 主分支神圣不可侵犯 :
main分支永远保持可编译、可运行、可测试状态,仅用于发布版本 - 一个分支一个任务:避免在一个分支中同时开发多个不相关功能,便于管理和回滚
- 定期合并更新:功能分支开发期间,定期从主分支合并最新代码,减少冲突
- 及时清理分支:功能合并后删除分支,避免分支泛滥,保持仓库整洁
核心结论速览
- Git本地提交≠没用 :=本地安全网+进度存档,不联网也能随时回滚、实验和整理代码
- 团队协作必须提交到远程 :远程是团队的共享中枢,但建议先在本地分支完成开发+测试+冲突解决,再推送到远程
- 分支是Git的灵魂 :核心作用是隔离风险,让你在不影响主代码的前提下安全做事(如归档旧VM、修复bug、开发新功能)
一、不提交到远程,为什么还要用Git?(3个核心价值)
1. 本地版本"时光机"------随时回滚的安全网
Git本地提交会创建完整的代码快照 ,保存在你电脑的.git文件夹里,相当于给代码拍了"不可修改的照片"
- 归档
AxisControlViewModel时,如果改坏了项目文件,随时能回退到提交前的状态 :git reset --hard HEAD^ - 开发时写坏代码、误删文件,都能通过
git log找到历史版本恢复,不用怕"删了找不回" - 比手动备份更高效:一次
git commit就能保存所有修改,还附带完整的修改记录和注释
2. 无网开发自由------飞机/地铁/断网时照写不误
Git本地操作完全不依赖网络,提交、分支切换、回滚都能离线完成
- 在整理轴VM代码时,就算办公室断网,也能安全提交归档改动,等网络恢复再推送远程
- 这是Git作为分布式版本控制系统的核心优势,每个开发者都有完整的本地仓库
3. 本地"草稿箱"------先整理再发布,避免远程污染
可以在本地多次提交、重构代码,直到功能稳定、测试通过后,再推送到远程共享
- 比如你先在本地归档VM、修复消息契约、重构异步代码,分3次提交,等全部搞定再一次性推到远程
- 避免把"半成品""有bug"的代码直接推到远程,影响团队其他成员
二、团队合作
"共享硬盘"
远程仓库(GitHub/GitLab/Gitee)是团队协作的唯一真相源,用于:
- 同步所有人的代码,避免"各写各的,最后合并灾难"
- 备份代码,防止本地电脑损坏导致代码丢失
- 进行代码审查(PR/MR)、持续集成(CI)等团队协作流程
2. 推荐的团队协作流程
本地开发 → 本地多次commit(存档) → 本地测试/修复 → git push到远程分支 → 团队评审 → 合并到主分支
先在本地分支archive-axiscontrolviewmodel完成文件移动+测试,确认无编译错误后再推到远程,让团队看到你的改动
- 这样做的好处:本地先解决所有问题,再共享成果,避免把未完成的改动或错误代码直接推到主分支影响他人
三、分支有啥用?
1. 隔离风险------你的归档操作安全区
archive-axiscontrolviewmodel分支,就是专门用来隔离归档风险的"安全沙箱"
- 即使在归档过程中不小心改坏了
AxisEcatVM代码,也不会影响主分支的稳定版本 - 测试通过后再合并到主分支,确保主线代码永远可运行、无冲突
- 类比:办公室的"草稿区"整理文件,整理好再放到"正式文件柜"(主分支)
2. 并行开发------多人协作不打架
团队中不同人可以在不同分支做不同事,互不干扰
- 你归档旧VM的同时,同事可以在
feature-scan-optimize分支优化扫描算法,我在bugfix-async-error分支修复异步问题 - 没有分支的话,所有人都在主分支改代码,很容易出现"你改了EtherCAT初始化,我又改了一遍,导致总线冲突"的问题
3. 版本管理------轻松管理不同状态的代码
分支可以用来区分开发/测试/生产环境,或保存不同版本的代码
main/master分支:稳定的生产版本develop分支:日常开发的集成分支feature-xxx分支:新功能开发分支bugfix-xxx分支:紧急bug修复分支- 你的归档分支:专门保存"移除旧VM"这个历史状态,后续想恢复时随时可以找到
4. 实验自由------大胆尝试不怕失败
可以在分支上做任何实验性修改,失败了直接删除分支就行,不会影响主线
- 比如你想尝试把
AxisEcatVM的初始化逻辑移到MainShellVM,可以创建experiment-axis-init分支 - 改坏了?直接
git branch -D experiment-axis-init删除分支,回到主分支继续开发
1. 查看历史版本(两种核心命令)
| 命令 | 作用 | 上位机开发常用场景 |
|---|---|---|
git log |
查看提交历史(完整版本链) | 确认EtherCAT总线配置、Halcon算法的提交节点 |
git reflog |
查看HEAD指针移动记录(含重置/删除操作) | 恢复误操作git reset --hard丢失的代码 |
实战示例:
bash
# 简洁查看提交历史(带分支图)
git log --oneline --graph --decorate
# 查看所有操作记录(救命命令)
git reflog
2. 恢复历史版本(3种安全方案)
方案A:恢复整个项目到指定版本(谨慎使用)
bash
# 先查看版本号(如a1b2c3d)
git reflog
# 硬重置(会丢弃本地修改)
git reset --hard a1b2c3d
方案B:恢复单个文件(上位机开发首选,不影响其他代码)
bash
# 恢复EtherCAT配置文件到上一版本
git checkout HEAD^ -- ViewModel/EtherCATConfigViewModel.cs
# 恢复到指定版本的Halcon算法文件
git checkout 9f7d6e5 -- Services/HalconVisionService.cs
方案C:恢复丢失的提交(误操作后必用)
bash
# 找到丢失的提交ID
git reflog
# 创建临时分支保存恢复内容
git branch recover-axis-control 7g8h9i0
# 合并到当前分支
git checkout main
git merge recover-axis-control
分支是Git中指向提交节点的指针,不是一个版本,而是一条独立的开发时间线。
1. 并行开发,互不干扰(核心价值)
-
场景:同时开发「运动轴控制模块」和「机器视觉检测功能」
-
操作 :
bashgit checkout -b feature-axis-control # 轴控制开发分支 git checkout -b feature-vision-detect # 视觉检测分支 -
好处:修改Halcon算法时不会影响EtherCAT总线代码,反之亦然
2. 隔离风险,保护稳定版本
- 场景:调试新的DC同步逻辑可能引入bug
- 操作 :在
dev分支开发,稳定后再合并到main - 好处:上位机设备的生产环境代码始终稳定,避免调试中的bug导致设备停机
3. 版本管理,清晰迭代
-
场景:设备需要V1.0、V2.0版本维护
-
操作 :
bashgit checkout -b release-v1.0 # 版本分支 git tag v1.0 # 标记正式发布 -
好处:不同版本的bug修复、功能扩展清晰分离,便于追溯
4. 团队协作,分工明确
- 场景:我负责运动控制,同事负责UI界面
- 操作:各自在专属分支开发,定期合并
- 好处:避免代码冲突,提高开发效率
有多种安全方式,无需切换分支即可复用其他分支代码:
方法1:直接复制其他分支的文件(最常用)
bash
# 当前在main分支,恢复来自feature-axis分支的轴控制文件
git checkout feature-axis -- ViewModel/AxisControlViewModel.cs
方法2:合并其他分支到当前分支(完整集成功能)
bash
# 当前在main分支,合并feature-vision分支的视觉检测功能
git merge feature-vision
方法3:选择性合并单个提交(修复bug专用)
bash
# 从bugfix分支提取修复EtherCAT连接问题的提交
git cherry-pick 4a5b6c7
历史版本解决"回退到过去"的问题,分支解决"同时走多条路"的问题。在上位机开发中:
- 调试新的运动轴扫描逻辑 → 用分支(
feature-scan-mode) - 发现上周的EtherCAT配置更稳定 → 用历史版本恢复(
git checkout 9f7d6e5 -- EtherCATConfig.cs) - 既要保留当前功能,又要尝试新算法 → 分支+历史版本结合使用
- 主分支保护 :
main分支只存稳定版本,禁止直接提交 - 功能分支 :新功能(如Halcon视觉优化)从
main创建feature-xxx分支 - 修复分支 :bug修复(如运动轴定位偏差)从
main创建bugfix-xxx分支 - 版本分支 :发布时创建
release-vx.x分支,便于后续维护 - 定期合并 :功能稳定后,通过Pull Request合并到
main
提交到团队远程仓库后,依然可以回退!**
情况1:你只在本地提交了 → 还没推送到远程(git push 没执行)
✅ 随便回退!无任何风险
bash
git reset --hard HEAD^
直接撤销本地最后一次提交,别人完全不知道,也不受影响。
情况2:你已经 git push 推送到团队远程仓库(重点!)
❌ 禁止使用 git reset --hard
✅ 必须使用:git revert
为什么不能用 reset?
reset会删除历史提交- 团队其他人已经拉了你的代码
- 你一 reset 再强制推送 → 所有人的代码历史冲突、文件丢失
- 工控/上位机代码绝对禁止这么干!
git revert 是什么?
它不删除历史 ,而是新建一个"反向提交" ,把错误代码撤销掉,历史记录完整保留。
团队安全、合规、唯一标准做法!
消息
消息 = 一张「带文字/带数据的纸条」
场景:
你在办公室(主VM),
工人在车间(轴VM),
摄影师在暗房(图像VM),
三个人互相不说话、不串门、不认识。
你想让工人移动机器 → 写一张纸条扔过去;
工人到位了 → 写一张纸条扔给摄影师拍照;
你想紧急停机 → 写一张纸条扔给所有人。
这张纸条,就是「消息」。
二、消息是什么?
项目有3个核心模块:
- 主界面VM(发指令)
- 轴控制VM(动XY轴)
- X光图像VM(拍照片)
这三个模块不能直接互相调用 (工业软件规范,解耦),
所以它们靠 消息 传递指令和数据。
三、消息的两种形式
1. 空消息 = 只喊口令,不带数据
就像喊:开始!停止!
csharp
// 空消息:只告诉轴VM「开始扫描」,不说扫哪里
public class StartScanMessage { }
2. 带载荷的消息 = 口令 + 数据
就像喊:移动到 X=10,Y=20,曝光50ms!
csharp
// 带数据的消息:指令+参数一起发
public class StartScanMessage
{
public double TargetX { get; } // 坐标
public double TargetY { get; }
public int ExposureTime { get; } // 曝光时间
}
消息 = 模块之间的「通信工具」
让 主VM、轴VM、图像VM 互不依赖、互不引用,
却能完美配合工作:
- 主VM发消息 → 轴VM动
- 轴VM发消息 → 图像VM拍照
- 任意VM发消息 → 全局写日志
流程:
-
点「开始扫描」按钮
→ 主VM 发送一条消息 :
我要扫X=10,Y=20,曝光50ms -
轴控制VM 收到消息
→ 读取消息里的坐标,控制电机移动
-
轴到位了
→ 轴VM 发送一条消息 :
我到位置了,可以拍照了 -
X光图像VM 收到消息
→ 启动探测器采集图像
全程三个模块谁也不认识谁 ,全靠消息传话!
消息 = 模块之间传递的「指令 + 数据」,
是工业软件里,让不同功能互不干扰、协同工作的核心工具。
不可变 DTO
不可变 DTO = 只读数据传输对象
对象创建之后,永远不能被修改 ,所有数据只能在初始化时赋值,没有任何地方可以改写它。
DTO (Data Transfer Object):数据传输对象,专门用来存数据、传数据,不写业务逻辑(比如你的轴坐标、扫描结果、检测数据)。
核心特征
- 只有
get,没有set(外部不能改) - 只能通过构造函数初始化赋值
- 线程安全(多线程随便传,不会被篡改)
- 纯数据,无逻辑、无状态变化
为什么必须用不可变 DTO**?
异步多线程 (Task.Run/async/await)、运动控制 、状态实时刷新,普通可变对象会出大问题:
- 多线程篡改数据:UI线程、扫描线程、Halcon线程同时改同一个对象 → 轴坐标错乱、状态异常
- 工控安全风险:扫描参数、限位值被意外修改 → 设备撞机、误动作
- Bug 难排查:数据不知道被谁改了,溯源极难
- MVVM 规范:纯数据和业务逻辑分离,代码更整洁
不可变 DTO 直接根治这些问题。
代码对比:可变 vs 不可变
1. ❌ 普通可变DTO
csharp
// 危险!任何地方都能改,多线程会乱
public class ScanResultDTO
{
// 公有set,随时能被篡改
public int DefectCount { get; set; }
public double PosX { get; set; }
public bool IsOk { get; set; }
}
2. ✅ 不可变DTO
C# 推荐写法:init 仅初始化赋值(创建后不能改)
csharp
/// <summary>
/// X光检测结果 不可变DTO
/// </summary>
public class ImmutableScanResult
{
// 只有get,无set → 绝对不能修改
public int DefectCount { get; init; }
public double AxisPosX { get; init; }
public bool IsQualified { get; init; }
public string ScanMode { get; init; }
// 必须通过构造函数一次性赋值
public ImmutableScanResult(int defectCount, double posX, bool isQualified, string scanMode)
{
DefectCount = defectCount;
AxisPosX = posX;
IsQualified = isQualified;
ScanMode = scanMode;
}
}
不可变 DTO 不是消息,但它是「消息的标准载体」
消息 = 快递包裹(用来传递通知)
不可变 DTO = 包裹里的货物(只读、不能改的核心数据)
消息 = 模块/线程之间发的通知
比如:
- 轴到位了
- 检测完成了
- 触发急停了
- 限位报警了
- 扫描进度更新
消息的作用:发通知,告诉别的代码发生了什么事。
「不可变 DTO」?
只读数据容器,创建后不能修改,专门存数据。
不可变 DTO = 消息体(消息里携带的数据)
消息 = 发送通知 + 携带不可变 DTO
工业上位机标准规范:
跨线程、跨模块发消息,必须用不可变DTO装数据
因为消息会在 运控线程 / UI线程 / Halcon线程 之间传递,可变对象会被篡改,导致设备撞机、数据错乱。
partial
把一个类/方法,拆成多份写在不同地方,编译时自动合并成一个完整的整体。
原因
CommunityToolkit.Mvvm ([ObservableProperty]/[RelayCommand]):
- 手写代码(逻辑、命令、属性)
- 编译器自动生成代码(命令、通知属性、回调方法)
这两部分代码必须靠 partial 合并,否则无法一起工作!
手写的代码(AxisControlViewModel.cs)
csharp
// 必须加 partial!
public partial class AxisControlViewModel : ObservableObject
{
// 自动生成 DcSyncOk 属性
[ObservableProperty]
private bool _dcSyncOk;
// 自动生成 StartScanCommand 命令
[RelayCommand]
private async Task StartScan() { }
}
2. 编译器自动生成的隐藏代码(AxisControlViewModel.g.cs)
csharp
// 和上面是同一个类,靠 partial 合并
public partial class AxisControlViewModel
{
// 自动生成的公开属性
public bool DcSyncOk { ... }
// 自动生成的命令
public IRelayCommand StartScanCommand { ... }
}
最终结果
编译后,两个文件合并成一个完整的类,你手写的逻辑 + 自动生成的MVVM代码完美结合。
二、partial 另外两个常见用途
1. 拆分超大代码
一个类代码太多,拆成两个文件,方便维护:
MainViewModel.cs + MainViewModel.Axis.cs,都是 partial class,互不干扰。
2. 分部方法
比如:
csharp
// 编译器自动生成
partial void OnDcSyncOkChanged(bool value);
// 你可以手动实现(不写也不会报错)
partial void OnDcSyncOkChanged(bool value)
{
StartScanCommand.NotifyCanExecuteChanged();
}
这也是 partial 的用法。
sealed 密封类
sealed = 密封、上锁 → 加在类上,表示「这个类禁止被继承**,谁都不能派生子类」**
csharp
// 密封 + 分部 = ViewModel标配
public sealed partial class AxisControlViewModel : ObservableObject
{
}
如果不加 sealed,别人可以随便继承ViewModel:
csharp
// 错误用法:继承轴控制VM
public class BadViewModel : AxisControlViewModel
{
// 会覆盖、篡改原有轴控逻辑,导致硬件失控
}
加了 sealed ,上面的代码直接编译报错,从根源禁止乱继承。
3. 为什么 ViewModel 必须加 sealed?
- 安全第一
轴控制、相机、EtherCAT 逻辑是核心硬件代码,绝对不允许被随意继承、重写,防止逻辑被篡改导致设备故障。 - 无继承需求
WPF 每个页面对应一个独立 VM,从来不需要继承另一个 VM。 - 性能微优化
密封类让编译器运行更快(几乎感知不到,但属于规范)。 - MVVM 最佳实践
用了CommunityToolkit.Mvvm的 VM,官方推荐一律写sealed partial class。