Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

huarkiou’s notes

个人技术笔记,记录实践中遇到的问题排查过程、常用命令速查、软件操作指南及学习资料。

内容按场景分为四类:

  • 问题排查 — 软件故障的诊断与修复,含根因分析
  • 工具速查 — 命令行工具的常用操作,cheatsheet 风格
  • 操作指南 — 以完成特定任务为目标的步骤教程
  • 资料收集 — 外链、书签、学习资源索引

本站使用 mdBook 构建,托管于 GitHub Pages。

PowerToys 右键菜单重复条目

问题

Windows 11 经典右键菜单中,File Locksmith 出现两个条目:一个中文,一个英文。

根因

PowerToys 0.99.1 的 File Locksmith 被两套机制同时注册,各自的显示名来源不同:

注册方式CLSID注册位置显示名来源
经典 ShellEx{84D68575-E186-46AD-B0CB-BAEB45EE29C0}AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExtDLL 内 GetCommandString,随系统语言返回中文
AppX 现代版{AAF1E27D-4976-49C2-8895-AAFA743C0A7E}AppX 包的 desktop4:FileExplorerContextMenusPackage PRI 资源文件,仅含 en-us,显示英文

两条路径都注册在 AllFileSystemObjects 下,所以右键任何文件/文件夹都会同时触发两份,产生中英文两个条目。

排查过程

1. 拉出所有 PowerToys 相关注册表项

Get-ChildItem -Path "HKCR:\","HKCU:\Software\Classes" -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.Name -match 'Locksmith' } |
    Select-Object -ExpandProperty Name

发现两条关键的 ContextMenuHandler 注册:

  • HKEY_CURRENT_USER\Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt
  • HKEY_CURRENT_USER\Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt

2. 追踪 CLSID

Get-ItemProperty "HKCU:\Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt"
# → {84D68575-E186-46AD-B0CB-BAEB45EE29C0}

查 CLSID 详情:

Get-ChildItem "HKCU:\Software\Classes\CLSID\{84D68575-E186-46AD-B0CB-BAEB45EE29C0}" -Recurse
# → InprocServer32: C:\Program Files\PowerToys\WinUI3Apps\PowerToys.FileLocksmithExt.dll
# → 这是经典 COM Shell Extension

3. 发现 AppX 并行注册

Get-AppxPackage -Name "*FileLocksmith*"
# → Microsoft.PowerToys.FileLocksmithContextMenu (AppX 包)

读 AppX Manifest:

<desktop4:Extension Category="windows.fileExplorerContextMenus">
  <desktop5:Verb Id="FileLocksmithCommand" Clsid="AAF1E27D-4976-49C2-8895-AAFA743C0A7E" />
</desktop4:Extension>

→ 这是文件管理器上下文菜单的现代注册方式,CLSID 与经典注册不同。

4. 结论

两套完全独立的注册并存 → 两个右键条目。

修复

保留 AppX 现代注册,删除经典 ShellEx 注册:

# 删除经典注册
Remove-Item "HKCU:\Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt" -Force
Remove-Item "HKCU:\Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt" -Force

# 重启资源管理器
taskkill /f /im explorer.exe; start explorer.exe

验证

Test-Path "HKCU:\Software\Classes\AllFileSystemObjects\ShellEx\ContextMenuHandlers\FileLocksmithExt"
# → False ✓
Test-Path "HKCU:\Software\Classes\Drive\ShellEx\ContextMenuHandlers\FileLocksmithExt"
# → False ✓

注意事项

  • PowerToys 后续版本更新可能重新写入经典注册,届时间隔跑一次同样命令即可
  • 如果希望保留经典版而非 AppX 版,反向操作:删除 AppX 包 Get-AppxPackage -Name "*FileLocksmith*" | Remove-AppxPackage
  • shellshellex 是两套不同的注册机制,排查时两者都要查

GitHub 官方仓库追踪

此问题是 PowerToys 已知 bug,从 2022 年延续至今,影响 File Locksmith、PowerRename、Image Resizer 三个模块。

关键 Issue

Issue状态日期说明
#20255Open2022-09总跟踪 Issue,三个模块的重复都归到这里
#31701Open2024-03维护者确认:“Win11 tier1 menu is a msix package…ends up duping with classic context menu”
#32097Closed2024-03与本文完全一致:非英文系统,标准+扩展菜单,一英文一本地语言
#39699Open2025-05西班牙语系统,v0.91.1
#44394Open2025-12意大利语系统,v0.97.0,最新报告
#34080Closed (dup)2024-07中文用户报告 “powerrename、filelocksmith两项重复”

关键 PR:问题如何演变

PR日期作者影响
#313882024-02@stefansjfw引入 AppX 包 — File Locksmith 首次有了 Win11 tier1 现代菜单,但没有移除经典 ShellEx 注册,埋下隐患
#413512025-08@lei9444加剧问题 — 移除了 if (!IsWin11OrGreater()) 条件守卫,让 Win11 上经典 ShellEx 无条件注册。PR 描述承认了副作用:“Ensure Windows 11 adds the registry entries for the old context menu so that ‘Show more options’/classic menu always includes them”
#414112025-08@lei9444修了 GPO 禁用时注册表残留的问题,但未修重复

PR #41351 的核心代码变更

// 之前:Win11 只注册 AppX,不注册经典 ShellEx
if (!package::IsWin11OrGreater()) {
    FileLocksmithRuntimeRegistration::EnsureRegistered();  // 经典 COM 方式
}

// 之后:Win11 上经典 ShellEx 无条件注册 → 与 AppX 包重复
FileLocksmithRuntimeRegistration::EnsureRegistered();  // 经典 COM 方式

官方态度

  • 为了确保经典右键菜单(“显示更多选项”)中一定出现 File Locksmith,宁可接受重复也不愿冒菜单丢失的风险
  • 维护者在 #31701 的回复:“At the time we couldn’t find a solution that also supported keeping the context menus on for the cases where the win11 tier 1 menus don’t install or show properly”

社区其他 Workaround

除本文方案外,社区还提供了反向操作(删 AppX PackagedCom 注册,保留经典 ShellEx):

# 管理员 PowerShell
Get-ChildItem "Registry::HKEY_CLASSES_ROOT\PackagedCom\Package\Microsoft.PowerToys.FileLocksmithContextMenu_*\Class\*" |
    Remove-Item -Recurse

taskkill /f /im explorer.exe; start explorer.exe

两种方案原理相同:删掉两套注册中的一套,没有对错之分。

Epic Launcher 因代理残留无法连接

问题描述

  • Epic 网页端正常打开可以登录;
  • 启动 Epic Games Launcher 客户端会提示无法建立连接,点击其中的感叹号图标会跳转到“SU-BI-CA:客户端构建信息校验错误 - Epic Games 商店 支持“的页面,但是其中并没有有用的信息;
  • 卸载重装、删除客户端缓存都没有作用;
  • 尝试网上的各种解决方案均无效;
  • 尝试使用雷神加速器没有改变,但是使用加速器中的启动按钮启动客户端时有一点不同:客户端开始正常更新,更新完成后自动重启后再次回到原本的状态。启动时加 -SkipBuildPatchPrereq 也没用。

解决方案

先确认当前 WinHTTP 代理状态:

netsh winhttp show proxy

如果输出包含 127.0.0.1:10809(或其它代理地址)且你并未主动配置,说明是残留的代理设置。

确认后在管理员权限运行的命令行中执行:

netsh winhttp reset proxy

终端中会提示:

Current WinHTTP proxy settings: Direct access (no proxy server)

然后重新启动客户端即可正常登录。

如果你在局域网环境通过代理上网:不要执行 reset,那会破坏你的网络连接。你应该用 netsh winhttp set proxy 配置正确的代理地址,而非直接清除。

若 reset 后无效可能是你遇到的问题与我并不同,建议直接去寻找其它解决方案。

排查过程

1. 查看日志

在客户端提示无法建立连接后,去到 %localappdata%\EpicGamesLauncher\Saved\Logs 目录下,可以找到日志文件 EpicGamesLauncher.log,打开后往后翻看,发现如下关键内容:

[2025.06.05-08.51.35:709][ 1]LogInit: - bUseHttpProxy = true  - Libcurl will use HTTP proxy
[2025.06.05-08.51.35:709][ 1]LogInit: - HttpProxyAddress = '127.0.0.1:10809'

2. 定位根因

此时猜测到客户端内部使用了 HTTP 代理,但是之前检查过系统代理,设置一切正常,并没有设置代理。

系统代理设置正常

然而客户端中的 libcurl 却异常设置了代理,因此合理推测这就是无法建立连接的原因所在。

询问 DeepSeek 后得到线索:

DeepSeek 指出 WinHTTP 代理

系统代理(IE/Edge 设置)和 WinHTTP 代理是两套独立的机制。Epic Games Launcher 的 libcurl 读取的是 WinHTTP 层的代理设置,而非系统代理。

3. 验证修复

执行 netsh winhttp reset proxy 重置 WinHTTP 代理:

执行 netsh winhttp reset proxy

重置后客户端恢复正常。

根因总结

代理层次设置位置Epic 客户端是否使用
系统代理Windows 设置 → 网络和 Internet → 代理
WinHTTP 代理netsh winhttp 管理✅ (libcurl 读取)

曾经使用过的代理工具(如 Clash、v2ray 等)可能在 WinHTTP 层留下了 127.0.0.1:10809 的代理配置,即使工具已卸载、系统代理已关闭,这个残留配置仍然存在。Epic Games Launcher 的 libcurl 按照 WinHTTP 代理配置尝试连接 127.0.0.1:10809,但代理服务已不在,导致“无法建立连接“。

附录:EpicGamesLauncher.log 部分内容

[2025.06.05-08.51.35:611][ 0]LogSelfUpdateService: ExecuteEpicGamesUpdater: Executing: "C:/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/EpicGamesUpdater.exe" queryinstallation
[2025.06.05-08.51.35:635][ 0]LogSelfUpdateService: ExecuteEpicGamesUpdater: "C:/Program Files (x86)/Epic Games/Launcher/Portal/Binaries/Win32/EpicGamesUpdater.exe" queryinstallation - SUCCESS.
[2025.06.05-08.51.35:635][ 0]LogSelfUpdateService: Initialising for EpicGamesLauncher:EpicGamesLauncher:EpicGamesLauncher:18.5.0-41681068+++Portal+Release-Live-Win32.
[2025.06.05-08.51.35:685][ 1]LogStreaming: Warning: Failed to read file 'C:/ProgramData/Epic/EpicGamesLauncher/Data/Launcher.manifest' error.
[2025.06.05-08.51.35:685][ 1]LogStreaming: Warning: Failed to read file 'C:/ProgramData/Epic/EpicGamesLauncher/Data/LauncherUpdate.manifest' error.
[2025.06.05-08.51.35:685][ 1]LogSelfUpdateService: Error: No local manifest loaded in HandleLauncherManifestLoaded.
[2025.06.05-08.51.35:709][ 1]LogInit: Using libcurl 7.55.1-DEV
[2025.06.05-08.51.35:709][ 1]LogInit: - built for i386-pc-win32
[2025.06.05-08.51.35:709][ 1]LogInit: - supports SSL with OpenSSL/1.1.1
[2025.06.05-08.51.35:709][ 1]LogInit: - supports HTTP deflate (compression) using libz 1.2.8
[2025.06.05-08.51.35:709][ 1]LogInit: - bUseHttpProxy = true  - Libcurl will use HTTP proxy
[2025.06.05-08.51.35:709][ 1]LogInit: - HttpProxyAddress = '127.0.0.1:10809'
[2025.06.05-08.51.37:707][120]LogHttp: Warning: invalid HTTP response code received. URL: https://account-public-service-prod.ak.epicgames.com/account/api/oauth/token, HTTP code: 0, content length: 0, actual payload size: 0
[2025.06.05-08.51.37:707][120]LogHttp: Warning: request failed, libcurl error: 7 (Couldn't connect to server)
[2025.06.05-08.51.37:707][120]LogHttp: Warning: libcurl info message cache 0 (  Trying 127.0.0.1...)

FFmpeg 常用命令

格式转换

# 视频转码(H.264,CPU)
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4

# 视频转码(H.265/HEVC,CPU)
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4

# 视频转码(H.265/HEVC,NVIDIA GPU)
ffmpeg -i input.mp4 -c:v hevc_nvenc -b:v 512k output.mp4

# 音频格式转换
ffmpeg -i input.wav -c:a aac -b:a 128k output.m4a

# 音频转为 Opus
ffmpeg -i audio.webm -c:a libopus -b:a 128k output.opus

# 无损提取(-c copy 不重新编码)
ffmpeg -i input.mkv -c copy output.mp4

码率控制

# 修改音频比特率(视频流直接复制)
ffmpeg -i input.mp4 -c:v copy -c:a aac -b:a 128k output.mp4

# 指定视频码率
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M output.mp4

# CRF 模式(恒定质量,18=近无损,23=默认,28=可接受)
ffmpeg -i input.mp4 -c:v libx264 -crf 18 output.mp4

尺寸与裁剪

# 缩放到指定分辨率
ffmpeg -i input.mp4 -vf scale=1280:720 output.mp4

# 按比例缩放(宽度 1080,高度自动)
ffmpeg -i input.mp4 -vf scale=1080:-1 output.mp4

# 裁剪矩形区域(宽:高:X偏移:Y偏移)
ffmpeg -i input.mp4 -vf crop=1920:1080:0:0 output.mp4

# 旋转 90 度
ffmpeg -i input.mp4 -vf transpose=1 output.mp4

# 翻转水平
ffmpeg -i input.mp4 -vf hflip output.mp4

截取与拼接

# 从开头截取 30 秒
ffmpeg -i input.mp4 -t 30 -c copy output.mp4

# 从 01:30 开始截取 10 秒
ffmpeg -i input.mp4 -ss 00:01:30 -t 10 -c copy output.mp4

# 从 01:30 截取到 02:00
ffmpeg -i input.mp4 -ss 00:01:30 -to 00:02:00 -c copy output.mp4

# 精确截取(重新编码,避免关键帧问题)
ffmpeg -i input.mp4 -ss 00:01:30 -t 10 output.mp4

# 拼接多个视频(先创建文件列表)
# filelist.txt 内容:
# file 'video1.mp4'
# file 'video2.mp4'
ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp4

音频处理

# 从视频中提取音频
ffmpeg -i video.mp4 -vn -c:a copy audio.m4a

# 替换视频的音频轨(保留视频流)
ffmpeg -i video.mp4 -i audio.aac -c:v copy -c:a copy -map 0:v:0 -map 1:a:0 output.mp4

# 合并无声视频和音轨(长度取最长)
ffmpeg -i video.mp4 -i audio.aac -c:v copy -c:a copy output.mp4

# 调节音量(2 倍)
ffmpeg -i input.mp4 -af "volume=2" output.mp4

# 去除音频(静音输出)
ffmpeg -i input.mp4 -an output.mp4

字幕

# 硬编码字幕到视频
ffmpeg -i input.mp4 -vf subtitles=subtitle.ass output.mp4

# 封装字幕到容器(软字幕,可开关)
ffmpeg -i input.mkv -i subtitle.ass -c copy -map 0 -map 1 -disposition:s:0 default output.mkv

# 提取内封字幕
ffmpeg -i input.mkv -map 0:s:0 subtitle.ass

帧与截图

# 截取一帧(1 秒处)
ffmpeg -i input.mp4 -ss 00:00:01 -vframes 1 output.png

# 每隔 10 秒截一帧
ffmpeg -i input.mp4 -vf fps=1/10 frames_%04d.png

# 视频转 GIF
ffmpeg -i input.mp4 -vf "fps=10,scale=480:-1" output.gif

# 高质量 GIF(调色板优化)
ffmpeg -i input.mp4 -vf "fps=10,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse" output.gif

# PPT 用 GIF(小体积)
# 降分辨率、降帧率、截取片段、限制颜色数、加抖动掩盖色阶断层
ffmpeg -i input.mp4 -ss 00:01:30 -t 3 \
  -vf "fps=8,scale=480:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=64[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3" \
  output.gif

PPT 配方中各参数作用:fps=8 足够流畅且不臃肿;scale=480 在幻灯片中清晰度足够;max_colors=64 限制调色板以减小体积;dither=bayer 在颜色断层处引入规律噪点,看起来反而自然。如需更小体积可进一步降到 fps=6scale=320max_colors=32

帧率与速度

# 修改帧率
ffmpeg -i input.mp4 -r 30 output.mp4

# 倍速播放(2 倍速)
ffmpeg -i input.mp4 -vf "setpts=0.5*PTS" -af "atempo=2" output.mp4

# 慢放(0.5 倍速)
ffmpeg -i input.mp4 -vf "setpts=2*PTS" -af "atempo=0.5" output.mp4

信息查看

# 查看媒体文件信息
ffmpeg -i input.mp4

# 只显示关键信息(不输出配置列表)
ffprobe -v quiet -show_format -show_streams -print_format json input.mp4

# 查看视频流详情
ffprobe -v error -select_streams v:0 -show_entries stream=width,height,codec_name,duration -of csv=p=0 input.mp4

Git 常用命令

commit

# 提交暂存区内容
git commit -m "message"

# 跳过暂存,直接提交所有已跟踪文件的改动
git commit -am "message"

# 追加到上一次提交(不新建 commit)
git commit --amend -m "new message"

#  amend 保持原提交信息
git commit --amend --no-edit

push

# 推送当前分支到远程
git push

# 推送并设置上游分支(首次推送)
git push -u origin main

# 强制推送(慎用)
git push --force

# 更安全的强制推送,不会覆盖他人提交
git push --force-with-lease

# 删除远程分支
git push origin --delete branch-name

pull / fetch

# 拉取并合并(fetch + merge)
git pull

# 拉取并变基(fetch + rebase,保持历史线性)
git pull --rebase

# 仅拉取远程数据,不合并
git fetch

# 拉取所有远程仓库
git fetch --all

# 拉取后清理远程已删除的分支
git fetch --prune

# 查看远程分支与本地分支的差异(fetch 后)
git diff origin/main

pull --rebase 比默认的 pull(merge)更适合个人开发分支,历史更干净;但已推送的公共分支应避免 rebase。

branch

# 列出本地分支
git branch

# 列出远程分支
git branch -r

# 列出所有分支
git branch -a

# 创建分支
git branch new-branch

# 删除已合并的分支
git branch -d branch-name

# 强制删除(即使未合并)
git branch -D branch-name

# 查看已合并到当前分支的分支
git branch --merged

# 查看尚未合并的分支(删除前排查用)
git branch --no-merged

# 重命名分支
git branch -m old-name new-name

checkout

# 切换到已有分支
git checkout branch-name

# 创建并切换到新分支
git checkout -b new-branch

# 基于远程分支创建本地分支
git checkout -b local-name origin/remote-name

# 恢复某个文件到最近提交的状态
git checkout -- file

# 切换到指定 commit(detached HEAD)
git checkout <commit-hash>

较新版本的 Git 中 git switchgit restore 分别替代了 checkout 的分支切换和文件恢复功能,语义更清晰。

log

# 简洁单行展示
git log --oneline

# 带分支图
git log --oneline --graph --all

# 查看某文件的提交历史
git log -- file

# 查看某文件的每次改动摘要
git log -p -- file

# 按关键字搜索提交信息
git log --grep="keyword"

# 搜索代码变更内容(某段代码的引入/删除历史)
git log -S "code snippet"

# 按日期范围
git log --since="2024-01-01" --until="2024-12-31"

# 按作者
git log --author="name"

# 最近 n 条
git log -5

diff

# 查看未暂存的改动
git diff

# 查看已暂存的改动
git diff --staged

# 与上一次提交比较
git diff HEAD~1

# 比较两个分支的差异
git diff branchA..branchB

# 比较两个分支的差异(三点语法:branchB 自分叉点以来的改动)
git diff branchA...branchB

# 只列出有差异的文件名
git diff --name-only branchA..branchB

# 查看某个文件的差异
git diff branchA..branchB -- file

stash

# 暂存当前未提交的改动
git stash

# 暂存时附带说明
git stash push -m "description"

# 查看暂存列表
git stash list

# 恢复最近一次暂存(保留 stash 记录)
git stash apply

# 恢复最近一次暂存(删除 stash 记录)
git stash pop

# 恢复指定暂存
git stash apply stash@{1}

# 删除指定暂存
git stash drop stash@{1}

# 清空所有暂存
git stash clear

merge

# 将指定分支合并到当前分支
git merge branch-name

# 合并时禁止快进,始终生成 merge commit
git merge --no-ff branch-name

# 压缩合并,将所有 commit 合并为一个
git merge --squash branch-name
git commit -m "merge branch-name"

# 放弃合并(冲突时)
git merge --abort

rebase

# 将当前分支变基到目标分支
git rebase main

# 交互式变基,合并/编辑/丢弃 commit
git rebase -i HEAD~3

# 冲突时:解决冲突后继续
git rebase --continue

# 跳过当前 commit
git rebase --skip

# 放弃变基
git rebase --abort

reset

# 回退到指定 commit,保留工作区和暂存区改动(最安全)
git reset --soft <commit-hash>

# 回退并清空暂存区,保留工作区改动(默认模式)
git reset --mixed <commit-hash>

# 回退并丢弃所有改动(危险)
git reset --hard <commit-hash>

# 将某个文件从暂存区移除(不影响工作区)
git reset -- file
git restore --staged file    # 新写法
模式HEAD暂存区工作区场景
--soft回退保留保留合并多个 commit 后重提交
--mixed回退清空保留重新整理本次要提交的内容
--hard回退清空清空彻底放弃改动(可用 reflog 恢复)

revert

# 撤销指定 commit(创建新的反向 commit,安全)
git revert <commit-hash>

# 撤销时不自动提交
git revert --no-commit <commit-hash>

# 撤销多个连续 commit
git revert <oldest>..<newest>

cherry-pick

# 将指定 commit 应用到当前分支
git cherry-pick <commit-hash>

# 批量 cherry-pick(不含 A)
git cherry-pick A..B

# 冲突时:解决后继续
git cherry-pick --continue

# 跳过当前 commit
git cherry-pick --skip

# 放弃 cherry-pick
git cherry-pick --abort

tag

# 创建轻量标签
git tag v1.0.0

# 创建附注标签(推荐,含作者和日期)
git tag -a v1.0.0 -m "release v1.0.0"

# 查看所有标签
git tag

# 查看标签详情
git show v1.0.0

# 推送单个标签
git push origin v1.0.0

# 推送所有标签
git push origin --tags

# 删除本地标签
git tag -d v1.0.0

# 删除远程标签
git push origin --delete v1.0.0

轻量标签只是一个指向 commit 的引用;附注标签是一个独立对象,包含打标签者、日期、注释,适合正式发布。

remote

# 查看远程仓库列表
git remote -v

# 添加远程仓库
git remote add upstream https://github.com/original/repo.git

# 修改远程仓库地址
git remote set-url origin git@github.com:user/repo.git

# 删除远程仓库
git remote remove upstream

# 查看远程仓库详情
git remote show origin

# 清理本地已不存在于远程的分支引用
git remote prune origin

config

# 设置全局用户名和邮箱
git config --global user.name "name"
git config --global user.email "email@example.com"

# 为当前仓库单独设置
git config user.name "name"

# Windows 换行符处理(检出 LF 转 CRLF,提交 CRLF 转 LF)
git config --global core.autocrlf true

# 常用别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.st status
git config --global alias.lg "log --oneline --graph --all"

# 查看所有配置
git config --list

reflog

# 查看所有操作历史(含 HEAD 移动记录)
git reflog

# 查看指定分支的操作历史
git reflog show branch-name

# 恢复到 reflog 中的某次操作(误 reset 后救命)
git reset --hard HEAD@{2}

reflog 只记录本地操作,不随 push 传输。reset --hard 误操作后只要没超过过期时间(默认 90 天)都能找回。

blame

# 查看每行代码的修改者和 commit
git blame file

# 指定行范围
git blame -L 10,20 file

# 忽略空白改动
git blame -w file

# 显示完整 commit hash
git blame -l file

clean

# 预览将被删除的未跟踪文件
git clean -n

# 删除未跟踪的文件
git clean -f

# 同时删除未跟踪的目录
git clean -fd

# 同时删除 .gitignore 中指定的文件
git clean -fx

-n 预览再执行,以免误删。

git-lfs

# 安装 LFS(首次使用)
git lfs install

# 追踪某类大文件
git lfs track "*.psd"
git lfs track "*.zip"

# 查看已追踪的文件类型
git lfs track

# 列出当前仓库中的 LFS 文件
git lfs ls-files

# 拉取 LFS 文件
git lfs pull

# 迁移已有文件到 LFS
git lfs migrate import --include="*.psd" --everything

.gitattributes 会被 git lfs track 自动更新,记得提交该文件。

移除某个文件的所有 commit 记录

git filter-branch -f --index-filter 'git rm -rf --cached --ignore-unmatch file-to-delete' HEAD
git push origin --force --all

UG NX 通过点拟合曲面

关键词:UG, NX, .dat 文件, 通过点拟合曲面

简介

有时候需要将自己程序中生成的曲面(已知曲面上各点坐标)导入 CAD 软件做一些处理,并生成三维模型,而 IGES 和 STEP 格式又过于复杂,绝大多数功能也用不到。UG NX 提供了通过读入 .dat 文件中的点信息拟合曲面的功能,因此可以将自己生成的曲面点用对应的文件格式规范写入文件,从而读入软件。

通过点拟合曲面

示例

曲面由三条曲线组成,分别为:

  • 曲线1: (1,0,0), (2,1,0), (3,0,0)
  • 曲线2: (1,0,1), (1.5,2,1), (2.5,2,1), (3,0,1)
  • 曲线3: (1,0,2), (2,1,2), (3,0,2)

这三条曲线1

按照 UG NX 通过点拟合曲面命令所需的 .dat 文件格式的规范,生成 test.dat 文件内容如下:

ROW
1.0 0.0 0.0
2.0 1.0 0.0
3.0 0.0 0.0
ROW
1.0 0.0 1.0
1.5 2.0 1.0
2.5 2.0 1.0
3.0 0.0 1.0
ROW
1.0 0.0 2.0
2.0 1.0 2.0
3.0 0.0 2.0

文件格式说明

  • 点的位置用笛卡尔坐标 (x, y, z) 描述,每行一个点,每列坐标之间用空格分隔。
  • ROW 行仅仅作为一个标记,分隔各条曲线,从而对应 UG NX 中的“通过点“和“从极点“命令中的行和列。
  • 可以大致理解为每个 ROW 后的点集对应一条曲线,曲线上的各点顺序应该一一对应从而减少生成过度扭曲的曲面的可能。
  • .dat 文件中不要空行,不要无效信息和多余内容。

不同的对象选择顺序和所得到的面

在 UG NX 中操作

1. 打开命令

菜单路径:插入 → 曲面 → 通过点从极点

通过点命令所在位置

  • 通过点:类似于插值,所得曲面严格通过所给定的点,但是可能生成的曲面质量比较差。
  • 从极点:所给定的点只是控制点,在一定程度上控制曲面形状,但是曲面不严格通过那些点,可能导致得到的曲面不符合需求。

关于两条命令的详细说明及不同对象选择顺序对生成曲面的影响,参见 Siemens NX 官方文档2

通过点命令对话框

2. 设置阶次

示例文件中的每行 (ROW) 最少只有 3 个点,只有 3 行,阶次最高只能二次。把行阶次和列阶次都改为 2,然后点击“文件中的点“打开文件选择窗口。

  • 文件选择窗口左下角可以改文件中描述点所用的坐标系(工作坐标系和绝对坐标系),没有建工作坐标系直接用默认即可。
  • 文件类型筛选为 *.dat,因此生成的文件后缀只能是 .dat

选择生成的 .dat 文件

3. 选择文件完成

选择 test.dat,点击 OK,即可生成曲面。

最终效果

参考文献


  1. Eng-Tips. “.dat file format for freeform surface - through points?”.

  2. Siemens NX 文档: 创建通过点和从极点曲面.

乐理学习资料

教程与课程

乐谱

工具