[{"content":"前言 你是否经历过这样的场景？\n当你正在为某个功能跑漫长的测试时，突然来了一个紧急的 bug 要修复，但你又不能随便动工作区的代码，因为测试还在进行。此时只能无奈地切换分支，导致 node_modules 需要重新安装，编译需要重新进行\u0026hellip;\nGit Worktree 就是来解决这个问题的。它允许你在同一个 Git 仓库中同时维护多个工作目录，每个目录可以检出不同的分支，彼此独立。\n这篇文章将从理论到实战，深入讲解如何使用 Git Worktree 来优化你的开发流程。\n什么是 Git Worktree？ 基本概念 Git Worktree（工作树）是一个 Git 特性，允许你在同一个 Git 仓库中创建多个工作目录。\n在没有 Worktree 之前：\n一个仓库 = 一个工作目录 切换分支会改变当前工作目录的文件状态 如果当前工作目录有未提交的改动，切换分支可能很困难 有了 Worktree 之后：\n一个仓库 = 多个独立的工作目录 每个工作目录可以检出不同的分支 多个目录可以同时进行开发，互不影响 工作树 vs 传统分支 常见误解： 工作树是对分支的替代\n正确理解： 工作树是对分支的一种**\u0026ldquo;文件系统视图\u0026rdquo;**\n分支：Git 中用来隔离开发路线的概念，存储在 .git/refs/heads/ 中 工作树：只是物理上创建了一个新的目录，让你能同时看到/编辑多个分支 分支的数量和数目都不会因为创建工作树而改变，工作树只是给了你一个新的\u0026quot;窗口\u0026quot;去访问这些分支。\n为什么需要 Git Worktree？ 常见应用场景 1️⃣ 场景：修复紧急 bug，不中断当前工作 你正在 feature/new-api 分支上开发新功能，代码还未提交。突然生产环境爆出一个 bug，需要立即修复。\n传统做法：\n# 代码还没 commit，必须先 stash git stash # 切回 main 分支 git checkout main # 修复 bug，提交 git commit -m \u0026#34;fix: xxx\u0026#34; # 切回开发分支 git checkout feature/new-api # 恢复代码 git stash pop 问题：如果项目很大（如前端项目有巨大的 node_modules），即使只是切换分支也要重新安装依赖！\n使用 Worktree 的做法：\n# 在新的目录中检出 main 分支 git worktree add ../hotfix main # 切换到新目录修复 bug cd ../hotfix git commit -m \u0026#34;fix: xxx\u0026#34; git push # 完成后删除工作树 cd .. git worktree remove hotfix 没有任何 stash、没有分支切换的污染、当前工作目录毫发无损！\n2️⃣ 场景：同时维护多个版本，避免重复安装依赖 你的项目有 main（当前版本）、v1.0（旧版本）、v1.1（预发布）等分支。\n传统做法： 每次切换版本都要 npm install，特别是跨版本时（Node 版本要求可能不同）\n使用 Worktree： 为每个版本创建一个工作树，它们各自拥有独立的 node_modules：\ngit worktree add ../release-v1.0 v1.0 git worktree add ../release-v1.1 v1.1 git worktree add ../release-main main # 现在你可以同时在三个目录中开发，互不影响 cd ../release-v1.0 # 独立的 node_modules cd ../release-v1.1 # 独立的 node_modules cd ../release-main # 独立的 node_modules 3️⃣ 场景：对比不同分支的代码行为 需要同时查看两个分支的代码细节，进行对比测试。使用 Worktree 可以在两个编辑器窗口中同时打开两个版本的代码，一目了然。\n4️⃣ 场景：并行开发相关的功能分支 多个开发者各自在不同的功能分支上工作。一个开发者可以使用 Worktree 快速在多个分支之间切换上下文，而不产生文件系统开销。\nGit Worktree 常用命令详解 1. git worktree add - 创建新工作树 基本语法：\ngit worktree add \u0026lt;path\u0026gt; [\u0026lt;branch-or-commit\u0026gt;] 常用形式：\n# 形式1：检出已有分支到新目录 git worktree add ../feature-x feature/feature-x # 形式2：创建新分支并检出到新目录（-b 选项） git worktree add -b feature/new-feature ../feature-new main # 形式3：强制添加（即使分支已被其他工作树占用） git worktree add -f ../hotfix hotfix # 形式4：基于某个 commit 创建工作树 git worktree add ../debug-point abc1234 # 形式5：检出到分离头指针状态 git worktree add --detach ../experiment main 参数说明：\n参数 说明 \u0026lt;path\u0026gt; 新工作树的目录路径（相对或绝对都可以） \u0026lt;branch-or-commit\u0026gt; 要检出的分支或 commit ID，默认为 HEAD -b \u0026lt;branch-name\u0026gt; 创建新分支并检出，新分支基于 \u0026lt;commit\u0026gt; -B \u0026lt;branch-name\u0026gt; 同 -b，但如果分支已存在则强制覆盖 -f | --force 强制操作，即使该分支已被其他工作树占用 --no-checkout 仅创建工作树目录，不检出文件 --detach 创建分离头指针状态的工作树 2. git worktree list - 列出所有工作树 基本用法：\ngit worktree list # 输出示例： # /home/user/project abc1234 [main] # /home/user/project/../hotfix def5678 [hotfix] 格式化输出：\ngit worktree list --porcelain # 输出示例： # worktree /home/user/project # branch refs/heads/main # detached # worktree /home/user/project/../hotfix # branch refs/heads/hotfix 3. git worktree remove - 删除工作树 基本用法：\n# 删除指定的工作树 git worktree remove hotfix # 强制删除（即使工作树目录损坏） git worktree remove -f hotfix 注意事项：\ngit worktree remove 会删除工作树目录及其所有内容 如果工作树中有未提交的改动，删除会被拒绝（除非使用 -f） 删除工作树不会影响关联的分支 4. git worktree move - 移动工作树 如果你需要重新整理工作树的位置：\n# 将工作树移动到新位置 git worktree move hotfix ../new-location/hotfix # 移动后，该工作树在新位置继续工作 cd ../new-location/hotfix git log # 完全正常 5. git worktree lock/unlock - 锁定工作树 防止工作树被意外删除：\n# 锁定工作树 git worktree lock --reason \u0026#34;Do not delete, in use\u0026#34; hotfix # 尝试删除会报错： # git worktree remove: \u0026#39;/path/to/hotfix\u0026#39; is locked, use \u0026#39;remove -f\u0026#39; to override # 解锁工作树 git worktree unlock hotfix 6. git worktree prune - 清理损坏的工作树 如果工作树目录被手动删除（不推荐），Git 会记住它。使用 prune 清理：\n# 列出将要被清理的工作树（不执行） git worktree prune -n # 清理超过指定时间没有被访问的工作树 git worktree prune --expire 3.days 实战案例：完整工作流 现在用一个真实的场景来演练 Git Worktree 的完整工作流。\n场景描述 你有一个 Next.js 项目，有三个重要分支：\nmain：生产分支 develop：开发分支 hotfix/urgent-fix：紧急修复 现在需要：\n在 develop 分支继续开发新功能（已有 50% 的工作） 同时在 main 分支修复一个生产 bug 并检查 hotfix/urgent-fix 分支是否可以合并 步骤演示 第 1 步：查看当前工作树状态\n$ git worktree list /Users/shawn/projects/app abc1234 [develop] 第 2 步：创建 main 分支的工作树来修复 bug\n$ git worktree add -b fix/production-bug ../app-main main 准备 ../app-main (标识符 fix/production-bug) HEAD 现在位于 def5678 Prepare v2.1.0 第 3 步：查看现在有多少个工作树\n$ git worktree list /Users/shawn/projects/app abc1234 [develop] /Users/shawn/projects/app-main def5678 [fix/production-bug] 第 4 步：在 main 的工作树中修复 bug\n$ cd ../app-main $ vim src/pages/api/checkout.ts $ npm test # 测试修复 $ git add -A $ git commit -m \u0026#34;fix: prevent double-charge in checkout\u0026#34; $ git push origin fix/production-bug 第 5 步：继续在 develop 分支工作（从未切换过！）\n$ cd ../app # 回到原来的开发目录 $ vim src/components/NewFeature.tsx # 继续之前的工作 $ npm test # 开发中的测试 # 一切文件状态保持不变，node_modules 也完整无缺 第 6 步：检查 hotfix 分支状态\n$ git worktree add ../app-hotfix hotfix/urgent-fix $ cd ../app-hotfix $ npm test \u0026amp;\u0026amp; npm run build # 验证可以正常编译 $ cd .. 第 7 步：修复完成后清理工作树\n$ git worktree list /Users/shawn/projects/app abc1234 [develop] /Users/shawn/projects/app-main ghi9012 [fix/production-bug] /Users/shawn/projects/app-hotfix jkl3456 [hotfix/urgent-fix] # 删除已经不需要的工作树 $ git worktree remove fix/production-bug # 这会删除 ../app-main 目录 $ git worktree remove hotfix/urgent-fix # 这会删除 ../app-hotfix 目录 $ git worktree list /Users/shawn/projects/app abc1234 [develop] 最佳实践建议 ✅ 应该这样做 遵循命名约定\n# 好的习惯：工作树目录名和分支名保持一致 git worktree add ../feature-auth feature/auth git worktree add ../release-v2.0 release/v2.0 及时清理不需要的工作树\ngit worktree list # 定期查看 git worktree remove \u0026lt;name\u0026gt; # 及时清理 在工作树中提交代码\n# 工作树中完全可以 commit、push cd ../feature-auth git add . git commit -m \u0026#34;implement oauth\u0026#34; git push 使用 lock 保护重要工作树\ngit worktree lock --reason \u0026#34;In use for v2.0 release\u0026#34; release ❌ 避免这样做 不要手动删除工作树目录\n# ❌ 坏的做法 rm -rf ../feature-auth # ✅ 正确的做法 git worktree remove feature-auth 不要在同一工作树中检出同一分支多次\n# ❌ 会报错 git worktree add ../app1 main git worktree add ../app2 main # ✅ 如果必须这样做，加 -f 强制 git worktree add -f ../app1 main 不要在工作树中执行 git checkout 来切换分支\n# ❌ 这是对工作树功能的误用 cd ../feature-auth git checkout main # 这会改变工作树的分支 # ✅ 应该创建新的工作树 git worktree add ../main-check main 不要忽视工作树的独立性\n每个工作树都有独立的：\n工作目录和文件 暂存区（staging area） HEAD 指向 但共享：\nGit 对象数据库（.git/objects/） 引用和历史 常见问题 Q\u0026amp;A Q1: 工作树会占用很多磁盘空间吗？ A: 不会。工作树只是创建了新的工作目录和独立的索引文件，但Git 对象数据库是共享的。\n例如，在前端项目中，最大的开销是 node_modules，每个工作树都有自己的 node_modules。如果你的项目 node_modules 是 500MB，3 个工作树就会占用 1.5GB。\n但相比于每次切换分支都要重新 npm install（可能需要 2-3 分钟），这是值得的！\nQ2: 工作树中的改动会影响其他工作树吗？ A: 不会。每个工作树都有独立的工作目录和暂存区。一个工作树中的未提交改动不会被其他工作树看到。\n但一旦 commit 和 push，这些改动就会出现在其他工作树的历史中。\nQ3: 能在工作树中直接 push 吗？ A: 完全可以！工作树中的 git 操作和原来的工作目录完全相同。commit、push、pull 都没问题。\n唯一的限制是同一分支不能在多个工作树中同时被检出。\nQ4: 删除分支后，它的工作树怎么办？ A: 工作树仍然存在，但变成了\u0026quot;分离 HEAD\u0026quot;状态。你可以继续在这个工作树中工作，但无法 push（因为分支已删除）。\n通常这种情况下，应该及时删除工作树：\ngit worktree remove \u0026lt;name\u0026gt; Q5: 工作树可以同步远程变化吗？ A: 可以。在工作树中执行 git pull 和 git fetch 完全正常，会自动同步。\n与其他工具的搭配 VS Code 多工作区 你可以将多个工作树添加到 VS Code 的一个工作区中：\n{ \u0026#34;folders\u0026#34;: [ { \u0026#34;path\u0026#34;: \u0026#34;/Users/shawn/projects/app\u0026#34; }, { \u0026#34;path\u0026#34;: \u0026#34;/Users/shawn/projects/app-main\u0026#34;, \u0026#34;name\u0026#34;: \u0026#34;main\u0026#34; }, { \u0026#34;path\u0026#34;: \u0026#34;/Users/shawn/projects/app-hotfix\u0026#34;, \u0026#34;name\u0026#34;: \u0026#34;hotfix\u0026#34; } ] } 现在在 VS Code 中可以同时看到三个分支的代码！\n持续集成 在 CI/CD 中，为了并行构建多个分支，Worktree 非常有用：\n#!/bin/bash # CI 脚本：同时构建多个版本 git worktree add build-main main git worktree add build-develop develop git worktree add build-release release/v2.0 # 并行构建 cd build-main \u0026amp;\u0026amp; npm run build \u0026amp; cd build-develop \u0026amp;\u0026amp; npm run build \u0026amp; cd build-release \u0026amp;\u0026amp; npm run build \u0026amp; wait # 等待所有构建完成 # 清理 git worktree remove build-main git worktree remove build-develop git worktree remove build-release 总结 Git Worktree 是一个强大而优雅的功能，它：\n✅ 解决了什么问题：\n避免频繁切换分支导致的依赖重装 允许同时在多个分支上工作 减少了开发中的上下文切换成本 ✅ 适用的场景：\n修复紧急 bug 而不中断当前工作 同时维护多个版本的代码 对比不同分支的差异 并行开发相关的功能分支 ✅ 核心要点：\nWorktree 不是对分支的替代，而是一种文件系统视图 每个工作树都有独立的工作目录和索引，但共享 Git 对象库 同一分支不能在多个工作树中同时被检出 使用 remove 而不是手动删除目录 如果你的开发流程涉及多分支并行开发或频繁的分支切换，Git Worktree 绝对值得一试。它会显著提升你的开发效率！\n参考资源 Git 官方文档 - git-worktree Git Worktree 的使用 - 张小凯的博客 深入了解 Git Worktree - 博客园 Git 屠龙技：使用 Git Worktree 并行开发测试 Happy coding! 🚀\n","permalink":"https://shawndeng.tech/posts/git-worktree-practical-guide/","summary":"\u003ch2 id=\"前言\"\u003e前言\u003c/h2\u003e\n\u003cp\u003e你是否经历过这样的场景？\u003c/p\u003e\n\u003cp\u003e当你正在为某个功能跑漫长的测试时，突然来了一个紧急的 bug 要修复，但你又不能随便动工作区的代码，因为测试还在进行。此时只能无奈地切换分支，导致 \u003ccode\u003enode_modules\u003c/code\u003e 需要重新安装，编译需要重新进行\u0026hellip;\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003eGit Worktree\u003c/strong\u003e 就是来解决这个问题的。它允许你在同一个 Git 仓库中同时维护多个工作目录，每个目录可以检出不同的分支，彼此独立。\u003c/p\u003e\n\u003cp\u003e这篇文章将从理论到实战，深入讲解如何使用 Git Worktree 来优化你的开发流程。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"什么是-git-worktree\"\u003e什么是 Git Worktree？\u003c/h2\u003e\n\u003ch3 id=\"基本概念\"\u003e基本概念\u003c/h3\u003e\n\u003cp\u003eGit Worktree（工作树）是一个 Git 特性，允许你在\u003cstrong\u003e同一个 Git 仓库中创建多个工作目录\u003c/strong\u003e。\u003c/p\u003e\n\u003cp\u003e在没有 Worktree 之前：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一个仓库 = 一个工作目录\u003c/li\u003e\n\u003cli\u003e切换分支会改变当前工作目录的文件状态\u003c/li\u003e\n\u003cli\u003e如果当前工作目录有未提交的改动，切换分支可能很困难\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e有了 Worktree 之后：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e一个仓库 = 多个独立的工作目录\u003c/li\u003e\n\u003cli\u003e每个工作目录可以检出不同的分支\u003c/li\u003e\n\u003cli\u003e多个目录可以同时进行开发，互不影响\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"工作树-vs-传统分支\"\u003e工作树 vs 传统分支\u003c/h3\u003e\n\u003cp\u003e\u003cstrong\u003e常见误解：\u003c/strong\u003e 工作树是对分支的替代\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e正确理解：\u003c/strong\u003e 工作树是对分支的一种**\u0026ldquo;文件系统视图\u0026rdquo;**\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e分支\u003c/strong\u003e：Git 中用来隔离开发路线的概念，存储在 \u003ccode\u003e.git/refs/heads/\u003c/code\u003e 中\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e工作树\u003c/strong\u003e：只是物理上创建了一个新的目录，让你能同时看到/编辑多个分支\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp\u003e分支的数量和数目都不会因为创建工作树而改变，工作树只是给了你一个新的\u0026quot;窗口\u0026quot;去访问这些分支。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"为什么需要-git-worktree\"\u003e为什么需要 Git Worktree？\u003c/h2\u003e\n\u003ch3 id=\"常见应用场景\"\u003e常见应用场景\u003c/h3\u003e\n\u003ch4 id=\"1-场景修复紧急-bug不中断当前工作\"\u003e1️⃣ \u003cstrong\u003e场景：修复紧急 bug，不中断当前工作\u003c/strong\u003e\u003c/h4\u003e\n\u003cp\u003e你正在 \u003ccode\u003efeature/new-api\u003c/code\u003e 分支上开发新功能，代码还未提交。突然生产环境爆出一个 bug，需要立即修复。\u003c/p\u003e\n\u003cp\u003e\u003cstrong\u003e传统做法：\u003c/strong\u003e\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-bash\" data-lang=\"bash\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 代码还没 commit，必须先 stash\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit stash\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 切回 main 分支\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit checkout main\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 修复 bug，提交\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit commit -m \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;fix: xxx\u0026#34;\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 切回开发分支\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit checkout feature/new-api\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#75715e\"\u003e# 恢复代码\u003c/span\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003egit stash pop\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cp\u003e问题：如果项目很大（如前端项目有巨大的 node_modules），即使只是切换分支也要重新安装依赖！\u003c/p\u003e","title":"Git Worktree 实战指南：平行开发的秘密武器"},{"content":"欢迎！👋 这是我的第一篇博客文章。在这里，我会分享：\n💻 技术文章 - 编程经验和心得 🛠️ 项目记录 - 有趣的项目开发过程 📚 学习笔记 - 新技术的探索和总结 💡 思考感悟 - 对技术和生活的思考 博客技术栈 这个博客使用的技术：\nHugo - 超快的静态网站生成器 PaperMod - 简洁优雅的主题 Nginx - Web 服务器 Let\u0026rsquo;s Encrypt - 免费的 SSL 证书 代码示例 来个经典的 Hello World：\ndef hello_world(): print(\u0026#34;Hello, World!\u0026#34;) print(\u0026#34;欢迎来到我的博客！\u0026#34;) if __name__ == \u0026#34;__main__\u0026#34;: hello_world() function helloWorld() { console.log(\u0026#34;Hello, World!\u0026#34;); console.log(\u0026#34;欢迎来到我的博客！\u0026#34;); } helloWorld(); 结语 希望这个博客能成为我记录技术成长的地方，也希望能帮到访问的你。\nStay tuned! 🚀\n","permalink":"https://shawndeng.tech/posts/hello-world/","summary":"\u003ch2 id=\"欢迎\"\u003e欢迎！👋\u003c/h2\u003e\n\u003cp\u003e这是我的第一篇博客文章。在这里，我会分享：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e💻 \u003cstrong\u003e技术文章\u003c/strong\u003e - 编程经验和心得\u003c/li\u003e\n\u003cli\u003e🛠️ \u003cstrong\u003e项目记录\u003c/strong\u003e - 有趣的项目开发过程\u003c/li\u003e\n\u003cli\u003e📚 \u003cstrong\u003e学习笔记\u003c/strong\u003e - 新技术的探索和总结\u003c/li\u003e\n\u003cli\u003e💡 \u003cstrong\u003e思考感悟\u003c/strong\u003e - 对技术和生活的思考\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"博客技术栈\"\u003e博客技术栈\u003c/h2\u003e\n\u003cp\u003e这个博客使用的技术：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003eHugo\u003c/strong\u003e - 超快的静态网站生成器\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003ePaperMod\u003c/strong\u003e - 简洁优雅的主题\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eNginx\u003c/strong\u003e - Web 服务器\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eLet\u0026rsquo;s Encrypt\u003c/strong\u003e - 免费的 SSL 证书\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch2 id=\"代码示例\"\u003e代码示例\u003c/h2\u003e\n\u003cp\u003e来个经典的 Hello World：\u003c/p\u003e\n\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-python\" data-lang=\"python\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003edef\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehello_world\u003c/span\u003e():\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello, World!\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    print(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;欢迎来到我的博客！\u0026#34;\u003c/span\u003e)\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003eif\u003c/span\u003e __name__ \u003cspan style=\"color:#f92672\"\u003e==\u003c/span\u003e \u003cspan style=\"color:#e6db74\"\u003e\u0026#34;__main__\u0026#34;\u003c/span\u003e:\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e    hello_world()\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003cdiv class=\"highlight\"\u003e\u003cpre tabindex=\"0\" style=\"color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;\"\u003e\u003ccode class=\"language-javascript\" data-lang=\"javascript\"\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#66d9ef\"\u003efunction\u003c/span\u003e \u003cspan style=\"color:#a6e22e\"\u003ehelloWorld\u003c/span\u003e() {\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;Hello, World!\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e  \u003cspan style=\"color:#a6e22e\"\u003econsole\u003c/span\u003e.\u003cspan style=\"color:#a6e22e\"\u003elog\u003c/span\u003e(\u003cspan style=\"color:#e6db74\"\u003e\u0026#34;欢迎来到我的博客！\u0026#34;\u003c/span\u003e);\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e}\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\n\u003c/span\u003e\u003c/span\u003e\u003cspan style=\"display:flex;\"\u003e\u003cspan\u003e\u003cspan style=\"color:#a6e22e\"\u003ehelloWorld\u003c/span\u003e();\n\u003c/span\u003e\u003c/span\u003e\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\u003ch2 id=\"结语\"\u003e结语\u003c/h2\u003e\n\u003cp\u003e希望这个博客能成为我记录技术成长的地方，也希望能帮到访问的你。\u003c/p\u003e\n\u003cp\u003eStay tuned! 🚀\u003c/p\u003e","title":"Hello World - 我的博客上线了！"},{"content":" ","permalink":"https://shawndeng.tech/github/","summary":"\u003cdiv id=\"github-app\"\u003e\u003c/div\u003e\n\n\u003cstyle\u003e\n.github-container {\n  max-width: 1200px;\n  margin: 0 auto;\n  padding: 20px;\n}\n\n.controls {\n  margin-bottom: 30px;\n  display: flex;\n  gap: 15px;\n  flex-wrap: wrap;\n  align-items: center;\n}\n\n.search-box {\n  flex: 1;\n  min-width: 250px;\n  padding: 12px 20px;\n  border: 2px solid #e1e4e8;\n  border-radius: 8px;\n  font-size: 16px;\n  transition: all 0.3s;\n}\n\n.search-box:focus {\n  outline: none;\n  border-color: #0366d6;\n  box-shadow: 0 0 0 3px rgba(3, 102, 214, 0.1);\n}\n\n.filter-buttons {\n  display: flex;\n  gap: 10px;\n  flex-wrap: wrap;\n}\n\n.filter-btn {\n  padding: 8px 16px;\n  border: 2px solid #e1e4e8;\n  background: white;\n  border-radius: 20px;\n  cursor: pointer;\n  transition: all 0.3s;\n  font-size: 14px;\n  font-weight: 500;\n}\n\n.filter-btn:hover {\n  border-color: #0366d6;\n  background: #f6f8fa;\n}\n\n.filter-btn.active {\n  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n  color: white;\n  border-color: transparent;\n}\n\n.stats-bar {\n  display: flex;\n  gap: 20px;\n  margin-bottom: 30px;\n  padding: 20px;\n  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n  border-radius: 12px;\n  color: white;\n  flex-wrap: wrap;\n}\n\n.stat-item {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n}\n\n.stat-icon {\n  font-size: 24px;\n}\n\n.stat-value {\n  font-size: 28px;\n  font-weight: bold;\n}\n\n.stat-label {\n  font-size: 14px;\n  opacity: 0.9;\n}\n\n.repos-grid {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));\n  gap: 25px;\n  margin-bottom: 30px;\n}\n\n.repo-card {\n  background: white;\n  border: 1px solid #e1e4e8;\n  border-radius: 12px;\n  padding: 24px;\n  transition: all 0.3s;\n  position: relative;\n  overflow: hidden;\n}\n\n.repo-card::before {\n  content: '';\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 4px;\n  background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);\n  transform: scaleX(0);\n  transition: transform 0.3s;\n}\n\n.repo-card:hover {\n  transform: translateY(-5px);\n  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15);\n}\n\n.repo-card:hover::before {\n  transform: scaleX(1);\n}\n\n.repo-header {\n  display: flex;\n  justify-content: space-between;\n  align-items: flex-start;\n  margin-bottom: 12px;\n}\n\n.repo-name {\n  font-size: 20px;\n  font-weight: 600;\n  color: #0366d6;\n  text-decoration: none;\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  word-break: break-word;\n  flex: 1;\n}\n\n.repo-name:hover {\n  text-decoration: underline;\n}\n\n.repo-visibility {\n  padding: 4px 10px;\n  border-radius: 12px;\n  font-size: 12px;\n  font-weight: 500;\n  background: #f6f8fa;\n  border: 1px solid #e1e4e8;\n  white-space: nowrap;\n}\n\n.repo-description {\n  color: #586069;\n  margin-bottom: 16px;\n  line-height: 1.5;\n  min-height: 40px;\n}\n\n.repo-stats {\n  display: flex;\n  gap: 16px;\n  margin-bottom: 12px;\n  font-size: 14px;\n  color: #586069;\n}\n\n.stat {\n  display: flex;\n  align-items: center;\n  gap: 4px;\n}\n\n.repo-language {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  padding: 6px 12px;\n  background: linear-gradient(135deg, rgba(102, 126, 234, 0.1) 0%, rgba(118, 75, 162, 0.1) 100%);\n  border-radius: 16px;\n  font-size: 13px;\n  font-weight: 500;\n}\n\n.language-dot {\n  width: 10px;\n  height: 10px;\n  border-radius: 50%;\n}\n\n.loading {\n  text-align: center;\n  padding: 60px 20px;\n  font-size: 18px;\n  color: #586069;\n}\n\n.loading-spinner {\n  border: 4px solid #f3f3f3;\n  border-top: 4px solid #667eea;\n  border-radius: 50%;\n  width: 50px;\n  height: 50px;\n  animation: spin 1s linear infinite;\n  margin: 20px auto;\n}\n\n.error-message {\n  text-align: center;\n  padding: 60px 20px;\n  color: #d73a49;\n  font-size: 16px;\n  background: #ffeef0;\n  border-radius: 8px;\n  margin: 20px 0;\n}\n\n@keyframes spin {\n  0% { transform: rotate(0deg); }\n  100% { transform: rotate(360deg); }\n}\n\n.no-results {\n  text-align: center;\n  padding: 60px 20px;\n  color: #586069;\n  font-size: 18px;\n}\n\n@media (max-width: 768px) {\n  .repos-grid {\n    grid-template-columns: 1fr;\n  }\n  \n  .stats-bar {\n    flex-direction: column;\n  }\n}\n\u003c/style\u003e\n\n\u003cscript\u003e\n(function() {\n  'use strict';\n  \n  const username = 'shawndenggh';\n  let allRepos = [];\n  let filteredRepos = [];\n  let currentLanguage = 'all';\n\n  const languageColors = {\n    JavaScript: '#f1e05a',\n    Python: '#3572A5',\n    Java: '#b07219',\n    Go: '#00ADD8',\n    TypeScript: '#2b7489',\n    C: '#555555',\n    'C++': '#f34b7d',\n    'C#': '#178600',\n    PHP: '#4F5D95',\n    Ruby: '#701516',\n    Swift: '#ffac45',\n    Kotlin: '#F18E33',\n    Rust: '#dea584',\n    HTML: '#e34c26',\n    CSS: '#563d7c',\n    Vue: '#41b883',\n    Dart: '#00B4AB',\n    Shell: '#89e051',\n    default: '#8257e6'\n  };\n\n  function getLanguageColor(language) {\n    return languageColors[language] || languageColors.default;\n  }\n\n  function createApp() {\n    const app = document.getElementById('github-app');\n    app.innerHTML = `\n      \u003cdiv class=\"github-container\"\u003e\n        \u003cdiv class=\"loading\" id=\"loading\"\u003e\n          \u003cdiv class=\"loading-spinner\"\u003e\u003c/div\u003e\n          \u003cp\u003e正在加载 GitHub 仓库...\u003c/p\u003e","title":"GitHub 开源项目"},{"content":"👋 Hi，我是 Shawn Deng 一个热爱技术的全栈工程师，同时也是 Vibe Coding Agent 工程师，专注于用代码创造价值。\n💼 职业经历 当前职位： Vika 维格云 - 后端技术负责人（至今）\n负责后端架构设计与技术选型 带领团队进行产品研发与技术攻关 推动技术创新与最佳实践落地 之前经历：\n【可以补充之前的公司经历】 🛠️ 技术栈 编程语言 主力语言： Java / Node.js / JavaScript / TypeScript 前端框架： React.js / Vue.js 也在用： Python / Go / Shell 等其他语言 框架 \u0026amp; 工具 后端： Spring Boot / Express / Nest.js 前端： React / Vue / Next.js 数据库： MySQL / PostgreSQL / MongoDB / Redis DevOps： Docker / Kubernetes / CI/CD 其他： Git / Nginx / Linux 🎯 当前关注 最近在研究：\n🤖 AI Coding Agent - 探索 AI 辅助编程的新范式 🏗️ 全栈架构 - 从前端到后端的完整技术栈实践 ⚡ 性能优化 - 高并发场景下的系统优化 🔧 工程化实践 - 提升团队开发效率与代码质量 🚀 项目经验 \u0026amp; 代表作品 Vika 维格云 简介： 新一代多维表格协作平台\n技术栈： Java / Spring Boot / Node.js / React\n链接： vika.cn\nAITable 简介： AI 驱动的智能表格平台\n技术栈： AI / Full Stack\n链接： aitable.ai\nBika 简介： 智能协作工具\n技术栈： Full Stack\n链接： bika.ai\n更多项目 更多开源项目请访问我的 GitHub 主页 🚀\n📝 博客主题 这个博客主要分享：\n💻 全栈开发 - 前端、后端技术实践与经验 🤖 AI Coding - Coding Agent 开发与应用 🏗️ 架构设计 - 系统设计与技术选型思考 🔧 工程实践 - 开发效率、代码质量、团队协作 📚 技术探索 - 新技术学习与实验心得 💡 思考感悟 - 技术管理与职业发展 🎓 教育背景 【学校名称】 - 【专业】（本科/硕士/博士）（20XX - 20XX） 或者写：自学成才 / 技术培训 / 等等 🌱 关于这个博客 创建这个博客的初衷：\n📝 记录成长 - 记录技术探索与实践的点滴 🤝 分享知识 - 把踩过的坑和经验分享给更多人 💭 整理思路 - 通过写作加深对技术的理解 🌍 连接世界 - 结识更多志同道合的技术伙伴 技术栈：\n静态博客生成：Hugo 主题：PaperMod 托管：自建服务器 SSL：Let\u0026rsquo;s Encrypt 📫 联系方式 欢迎交流！可以通过以下方式联系我：\n📧 Email： shawndgh@163.com wrdnhdgdgui@gmail.com 35511099@qq.com 🐙 GitHub： @shawndenggh 💼 LinkedIn： 【可选，有的话告诉我】 💬 微信： 【可选，要公开的话告诉我】 🎮 工作之外 除了写代码，我还喜欢：\n【爱好1，比如：跑步/健身】 【爱好2，比如：阅读/摄影】 【爱好3，比如：旅行/音乐】 💬 一句话 \u0026ldquo;【在这里写一句你喜欢的话，比如：代码改变世界 / 持续学习，永不止步】\u0026rdquo;\n最后更新：2026-02-24\n","permalink":"https://shawndeng.tech/about/","summary":"\u003ch2 id=\"-hi我是-shawn-deng\"\u003e👋 Hi，我是 Shawn Deng\u003c/h2\u003e\n\u003cp\u003e一个热爱技术的\u003cstrong\u003e全栈工程师\u003c/strong\u003e，同时也是 \u003cstrong\u003eVibe Coding Agent 工程师\u003c/strong\u003e，专注于用代码创造价值。\u003c/p\u003e\n\u003chr\u003e\n\u003ch2 id=\"-职业经历\"\u003e💼 职业经历\u003c/h2\u003e\n\u003cp\u003e\u003cstrong\u003e当前职位：\u003c/strong\u003e Vika 维格云 - 后端技术负责人（至今）\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e负责后端架构设计与技术选型\u003c/li\u003e\n\u003cli\u003e带领团队进行产品研发与技术攻关\u003c/li\u003e\n\u003cli\u003e推动技术创新与最佳实践落地\u003c/li\u003e\n\u003c/ul\u003e\n\u003c!-- 🔧 TODO: 如果有之前的工作经历，可以继续补充 --\u003e\n\u003cp\u003e\u003cstrong\u003e之前经历：\u003c/strong\u003e\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e【可以补充之前的公司经历】\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"-技术栈\"\u003e🛠️ 技术栈\u003c/h2\u003e\n\u003ch3 id=\"编程语言\"\u003e编程语言\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e主力语言：\u003c/strong\u003e Java / Node.js / JavaScript / TypeScript\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e前端框架：\u003c/strong\u003e React.js / Vue.js\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e也在用：\u003c/strong\u003e Python / Go / Shell 等其他语言\u003c/li\u003e\n\u003c/ul\u003e\n\u003ch3 id=\"框架--工具\"\u003e框架 \u0026amp; 工具\u003c/h3\u003e\n\u003cul\u003e\n\u003cli\u003e\u003cstrong\u003e后端：\u003c/strong\u003e Spring Boot / Express / Nest.js\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e前端：\u003c/strong\u003e React / Vue / Next.js\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e数据库：\u003c/strong\u003e MySQL / PostgreSQL / MongoDB / Redis\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003eDevOps：\u003c/strong\u003e Docker / Kubernetes / CI/CD\u003c/li\u003e\n\u003cli\u003e\u003cstrong\u003e其他：\u003c/strong\u003e Git / Nginx / Linux\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"-当前关注\"\u003e🎯 当前关注\u003c/h2\u003e\n\u003cp\u003e最近在研究：\u003c/p\u003e","title":"关于我"},{"content":"欢迎交换友链！ 如果你也有技术博客，欢迎交换友链。可以通过以下方式联系我：\n📧 Email: shawndgh@163.com 🐙 GitHub: @shawndenggh 友情链接 示例友链 这是一个示例友链，你可以编辑这个文件添加真实的友链。 申请友链 如果想要交换友链，请确保你的博客：\n✅ 内容积极向上，无违法违规内容 ✅ 坚持原创，转载注明出处 ✅ 有一定的更新频率 ✅ 网站可以正常访问 本站信息：\n名称：ShawnDeng\u0026rsquo;s Tech Blog 链接：https://shawndeng.tech 简介：全栈工程师的技术博客，分享编程与技术实践 头像：https://avatars.githubusercontent.com/u/39178385?v=4 ","permalink":"https://shawndeng.tech/links/","summary":"\u003ch2 id=\"欢迎交换友链\"\u003e欢迎交换友链！\u003c/h2\u003e\n\u003cp\u003e如果你也有技术博客，欢迎交换友链。可以通过以下方式联系我：\u003c/p\u003e\n\u003cul\u003e\n\u003cli\u003e📧 Email: \u003ca href=\"mailto:shawndgh@163.com\"\u003eshawndgh@163.com\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e🐙 GitHub: \u003ca href=\"https://github.com/shawndenggh\"\u003e@shawndenggh\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e\n\u003chr\u003e\n\u003ch2 id=\"友情链接\"\u003e友情链接\u003c/h2\u003e\n\u003cstyle\u003e\n.friend-links {\n  display: grid;\n  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));\n  gap: 20px;\n  margin: 30px 0;\n}\n\n.friend-card {\n  background: var(--entry);\n  border: 1px solid var(--border);\n  border-radius: 12px;\n  padding: 20px;\n  transition: all 0.3s;\n  display: flex;\n  gap: 15px;\n  align-items: flex-start;\n}\n\n.friend-card:hover {\n  transform: translateY(-5px);\n  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);\n  border-color: var(--theme);\n}\n\n.friend-avatar {\n  width: 60px;\n  height: 60px;\n  border-radius: 50%;\n  flex-shrink: 0;\n}\n\n.friend-info {\n  flex: 1;\n}\n\n.friend-name {\n  font-size: 18px;\n  font-weight: 600;\n  color: var(--primary);\n  text-decoration: none;\n  margin-bottom: 5px;\n  display: block;\n}\n\n.friend-name:hover {\n  color: var(--theme);\n}\n\n.friend-desc {\n  font-size: 14px;\n  color: var(--secondary);\n  line-height: 1.5;\n}\n\n@media (max-width: 768px) {\n  .friend-links {\n    grid-template-columns: 1fr;\n  }\n}\n\u003c/style\u003e\n\u003cdiv class=\"friend-links\"\u003e\n\u003cdiv class=\"friend-card\"\u003e\n  \u003cimg src=\"https://avatars.githubusercontent.com/u/39178385?v=4\" alt=\"ShawnDeng\" class=\"friend-avatar\" /\u003e\n  \u003cdiv class=\"friend-info\"\u003e\n    \u003ca href=\"https://github.com/shawndenggh\" class=\"friend-name\" target=\"_blank\"\u003e示例友链\u003c/a\u003e\n    \u003cdiv class=\"friend-desc\"\u003e这是一个示例友链，你可以编辑这个文件添加真实的友链。\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n\u003c!-- 添加更多友链，复制上面的 friend-card 结构 --\u003e\n\u003c!--\n\u003cdiv class=\"friend-card\"\u003e\n  \u003cimg src=\"头像链接\" alt=\"名称\" class=\"friend-avatar\" /\u003e\n  \u003cdiv class=\"friend-info\"\u003e\n    \u003ca href=\"博客链接\" class=\"friend-name\" target=\"_blank\"\u003e博客名称\u003c/a\u003e\n    \u003cdiv class=\"friend-desc\"\u003e博客简介\u003c/div\u003e\n  \u003c/div\u003e\n\u003c/div\u003e\n--\u003e\n\u003c/div\u003e\n\u003chr\u003e\n\u003ch2 id=\"申请友链\"\u003e申请友链\u003c/h2\u003e\n\u003cp\u003e如果想要交换友链，请确保你的博客：\u003c/p\u003e","title":"友情链接"}]