使用 Tailscale SSH Git 搭建跨网络远程开发工作流技术背景机器角色配置教程1. 在两端安装 Tailscale2. 在台式机 VM 开启 SSH3. 在台式机 VM 初始化 Git 远程仓库4. 添加 .gitignore 并提交源码5. 修复 bare 仓库默认分支6. 在笔记本侧 clone 仓库7. 在 Windows 端配置 SSH alias日常工作流踩过的坑1. ping 通不代表 SSH 登录成功2. Tailscale IP 不是普通局域网 IP3. VMware 共享目录不适合作为 Linux 内核源码主仓库4. Windows OpenSSH 会严格检查 .ssh/config 权限5. git branch -M main 要在第一次 commit 后执行6. clone 成功但无法检出分支7. 不要让 Git 同步构建现场技术背景我的开发环境比较特殊我平时在工位使用一台轻薄本宿舍有一台性能更好的台式机。近期在做嵌入式 SDK 驱动开发常常需要Agent阅读源码帮我定位bug但源码、交叉编译环境和构建产物都比较大如果频繁手工拷贝整个工程效率会很低。最开始容易想到的是把两台机器放进同一个局域网用192.168.x.x访问。但实际情况是笔记本和台式机不在同一个网段普通内网 IP 无法直接访问。最后采用的方案是Tailscale 负责打通网络 SSH 负责远程执行命令 Git 负责同步源码变化 台式机 VM 负责真正编译 笔记本/Agent 负责阅读、分析和小范围修改代码在这个方案里台式机 Ubuntu VM 相当于一个“私人 Git 服务器”。不需要 GitHub也不需要公网 IP、DDNS 或路由器端口映射。机器角色这套环境里我统一使用下面的命名笔记本 Windows 运行 Agent 笔记本 VM 笔记本上的 Ubuntu 虚拟机 台式机 Windows 承载远程桌面和 VMware 台式机 VM 台式机上的 Ubuntu 虚拟机主要开发和编译环境本文命令使用下面这些占位符。实际操作时把它们替换成你自己的信息DESKTOP_VM_TAILSCALE_IP 台式机 Ubuntu VM 的 Tailscale IP YOUR_LINUX_USER 台式机 Ubuntu VM 的 Linux 用户名 DESKTOP_VM_SDK_DIR 台式机 Ubuntu VM 上的 SDK 工作目录例如台式机 VM 中 SDK 主工作区可以写成/home/YOUR_LINUX_USER/work/embedded-sdk台式机 VM 中 bare Git 仓库可以写成/home/YOUR_LINUX_USER/git/embedded-sdk.git配置教程1. 在两端安装 Tailscale如果是windows访问https://tailscale.com/download下载客户端如果是 Ubuntu/Debian 虚拟机可以使用官方安装脚本curl-fsSLhttps://tailscale.com/install.sh|shsudotailscale up执行sudo tailscale up后终端会给出一个网页登录授权地址。两台机器登录同一个 Tailscale 账号即可。检查 Tailscale 服务是否运行systemctl status tailscaled设置开机自启并立即启动sudosystemctlenable--nowtailscaled查看当前机器的 Tailscale IPtailscaleip-4tailscale statusTailscale 的100.x.x.x地址通常会绑定设备。只要不重装系统、不删除 Tailscale 节点、不清空/var/lib/tailscale/这个 IP 一般不会变化。2. 在台式机 VM 开启 SSH在desktop-vm上执行sudoaptupdatesudoaptinstall-ygitopenssh-serversudosystemctlenable--nowssh在笔记本侧测试连接sshYOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IP这里会提醒你输入密码这里的密码是台式机 Ubuntu VM 中YOUR_LINUX_USER用户的密码不是笔记本密码也不是 Windows 开机密码。第一次连接时会提示确认主机指纹Are you sure you want to continue connecting (yes/no/[fingerprint])?输入完整的yes看到Welcome to Ubuntu 20.04.6 LTS之类的欢迎信息就说明 SSH 登录成功。3. 在台式机 VM 初始化 Git 远程仓库在台式机 VM 上创建一个 bare 仓库。bare 仓库不直接编辑文件只作为远程同步仓库使用类似自己的 GitHub。mkdir-p~/gitgitinit--bare~/git/embedded-sdk.git然后进入台式机 VM 上真正的 SDK 工作目录cd~/work/embedded-sdk如果这里还不是 Git 仓库推荐一开始就指定默认分支gitinit-bmain如果已经执行过普通git init也没关系后面第一次 commit 成功后再执行gitbranch-Mmain注意如果还没有任何 commit直接运行git branch -M main可能报error: refname refs/heads/master not found fatal: Branch rename failed这是因为 Git 仓库还没有真正创建出master分支不是严重错误。先 commit再改分支名即可。4. 添加 .gitignore 并提交源码嵌入式 SDK 里通常有大量编译产物例如out/ temp/ *.o *.ko *.cmd *.d *.img *.bin *.log这些不应该进 Git。尤其嵌入式 SDK 这种目录编译产物和源码混在一起。因此需要创建.gitignore文件设置规则避免将这些文件上传到仓库中否则Git 仓库会非常臃肿。提交前先预览将要加入 Git 的文件gitadd-n.确认没有大量构建输出、镜像、临时文件后再真正提交gitadd.gitcommit-mInitial SDK source importgitbranch-Mmaingitremoteaddorigin ~/git/embedded-sdk.gitgitpush-uorigin main如果 Git 提示没有配置用户名和邮箱可以先设置gitconfig--globaluser.nameYour Namegitconfig--globaluser.emailyouexample.com5. 修复 bare 仓库默认分支如果 clone 时出现warning: remote HEAD refers to nonexistent ref, unable to checkout 警告远程 HEAD 指向一个不存在的引用无法检出说明 bare 仓库的HEAD还指向默认的master但实际分支已经是main。在台式机 VM 上修复cd~/git/embedded-sdk.gitgitsymbolic-ref HEAD refs/heads/maingitsymbolic-ref HEAD最后一条命令应该输出refs/heads/main6. 在笔记本侧 clone 仓库如果是在笔记本 VM 的 Linux ext4 目录中 clone推荐mkdir-p~/workcd~/workgitclone YOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IP:/home/YOUR_LINUX_USER/git/embedded-sdk.gitcdembedded-sdk如果只是为了让 Windows 侧 Agent 快速读取源码也可以 clone 到 VMware 共享目录但要明确它只是“轻量阅读/小改副本”不能作为主编译目录。例如cd/mnt/hgfs/SharedFolders/embedded-sdkgitclone YOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IP:/home/YOUR_LINUX_USER/git/embedded-sdk.git.gitconfig core.filemodefalsegitconfig core.autocrlffalse检查配置gitconfig--getcore.filemodegitconfig--getcore.autocrlf期望输出false false7. 在 Windows 端配置 SSH alias为了让 Agent 能直接在 Windows/Codex 环境里远程执行命令可以在 Windows 的 SSH config 中配置 aliasHost desktop-vm HostName DESKTOP_VM_TAILSCALE_IP User YOUR_LINUX_USER IdentityFile ~/.ssh/id_ed25519_remote_dev IdentitiesOnly yes生成一把专用 keyssh-keygen -t ed25519 -f %USERPROFILE%\.ssh\id_ed25519_remote_dev -C laptop-to-desktop-vm把公钥加入台式机 VMtype %USERPROFILE%\.ssh\id_ed25519_remote_dev.pub | ssh desktop-vm mkdir -p ~/.ssh cat ~/.ssh/authorized_keys chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys测试免密登录ssh desktop-vm hostname whoami pwd成功后Agent 就可以用这种方式远程查看状态ssh desktop-vmcd ~/work/embedded-sdk git status --short --branch远程搜索ssh desktop-vmcd ~/work/embedded-sdk rg driver_name path/to/source远程编译ssh desktop-vmcd ~/work/embedded-sdk build-command日常工作流台式机 VM 是主开发和编译环境cd~/work/embedded-sdkgitstatusgitadd-Agitcommit-m描述这次修改gitpush笔记本同步gitpull --ff-onlygit pull --ff-only的意思是如果本地没有额外提交就把远程所有新提交同步下来 如果本地和远程分叉了就停止让人手动处理。如果笔记本也做了修改gitstatusgitadd-Agitcommit-m描述这次修改gitpush然后台式机 VM 再同步并编译gitpull --ff-only踩过的坑1.ping通不代表 SSH 登录成功曾经遇到过pingDESKTOP_VM_TAILSCALE_IP能通但sshdevDESKTOP_VM_TAILSCALE_IP一直Permission denied。原因是dev只是示例用户名真实环境里要替换为台式机 VM 的 Linux 用户名。正确命令应该是sshYOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IPSSH 密码也是台式机 Ubuntu VM 中YOUR_LINUX_USER用户的密码。2. Tailscale IP 不是普通局域网 IP192.168.x.x只能在同一个局域网里用。两台机器跨网络、跨地点时应该使用 Tailscale 分配的100.x.x.x地址。例如台式机 VM 可以记作DESKTOP_VM_TAILSCALE_IPGit remote 可以写成YOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IP:/home/YOUR_LINUX_USER/git/embedded-sdk.git后续如果开启 MagicDNS 或配置 SSH alias可以把 IP 隐藏成desktop-vm:/home/YOUR_LINUX_USER/git/embedded-sdk.git3. VMware 共享目录不适合作为 Linux 内核源码主仓库我曾经把完整 SDK clone 到/mnt/hgfs/SharedFolders/embedded-sdk然后git status出现大量莫名修改例如xt_DSCP.h xt_MARK.h xt_TCPMSS.h ipt_TTL.h ip6t_HL.h aux.c aux这不是因为手动删错了文件而是因为 Linux 内核源码里有大小写仅不同的文件名以及 Windows 保留名例如aux。VMware 共享目录底层受 Windows 文件系统影响不能完全忠实表示 Linux/ext4 的文件名语义。结论/mnt/hgfs 可以给 Agent 读代码、写文档、做小 patch 不要把它当主仓库 不要在这里编译 不要轻易提交这里显示出来的异常 git status真正的主工作区应该放在台式机 VM 的 Linux 文件系统中/home/YOUR_LINUX_USER/work/embedded-sdk4. Windows OpenSSH 会严格检查.ssh/config权限Windows 上曾经出现Bad owner or permissions on C:\Users\YOUR_WINDOWS_USER\.ssh\config这个问题不是 Tailscale也不是 SSH 服务端而是本机.ssh/config权限太开放。尤其如果Everyone有完全控制OpenSSH 会拒绝读取。可以用完整路径调用icacls.exe修复C:\Windows\System32\icacls.exe %USERPROFILE%\.ssh\config /inheritance:r C:\Windows\System32\icacls.exe %USERPROFILE%\.ssh\config /grant:r %USERNAME%:F C:\Windows\System32\icacls.exe %USERPROFILE%\.ssh\config /remove Everyone Users Authenticated Users如果临时想绕过 config可以用ssh -F none YOUR_LINUX_USERDESKTOP_VM_TAILSCALE_IP5.git branch -M main要在第一次 commit 后执行如果刚git init还没有 commit直接改分支名可能失败error: refname refs/heads/master not found fatal: Branch rename failed推荐从一开始就用gitinit-bmain如果已经git init就先 commitgitadd.gitcommit-mInitial SDK source importgitbranch-Mmain6. clone 成功但无法检出分支出现warning: remote HEAD refers to nonexistent ref, unable to checkout不是对象没拉下来而是 bare 仓库默认HEAD指错了。修复cd~/git/embedded-sdk.gitgitsymbolic-ref HEAD refs/heads/main7. 不要让 Git 同步构建现场Git 适合同步源码和配置不适合同步整个编译现场。嵌入式 SDK 的构建产物、镜像、临时对象文件应该通过.gitignore排除。最终边界是Git 同步源码变化 SSH 远程执行命令 台式机 VM 负责编译 笔记本/笔记本 VM 负责查看和小改这个边界清楚之后整个远程开发链路就顺了很多。