在 git 无法联网时发布到 Gitee
适用场景
- 执行环境中
git push报getaddrinfo() thread failed to start(git 自带 libcurl 的 DNS 解析故障),但 PowerShell/.NET 能正常联网。 - 需要把代码发布到 Gitee,却无法用普通 git 推送。
前置
- 一个 Gitee 个人访问令牌(PAT),至少勾选
projects权限。 - 本地已
git init+ 写好.gitignore+git commit完成。
步骤
- 确认 PAT 所属真实账号(关键):
GET https://gitee.com/api/v5/user带Authorization: token $PAT,读取返回的login。用户填写的用户名常与 PAT 实际账号不符,后续所有路径必须用真实login。 - 建仓(用最小 body,避免 400):
POST https://gitee.com/api/v5/user/repos,Headers{Authorization="token $PAT"},
Body'{"name":"<repo>","private":true}'。若已存在会返回 409,可忽略。 - 逐个上传文件(排除
.git/node_modules/data)。Gitee 的 contents 接口状态码不可靠(已存在文件用POST创建会返回 400 而非 409;不存在路径GET返回 200 空数组[]而非 404)。因此不要靠状态码判断新建/更新,改为:先GET该路径,若响应带有sha字段说明文件已存在 →PUT更新;否则 →POST创建(路径含子目录如lib/store.js,Gitee 会自动建目录):
powershell $b64=[Convert]::ToBase64String([IO.File]::ReadAllBytes("$dir/$f")) $sha=$null try { $g=Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/contents/$f`?ref=master" -Headers @{Authorization="token $PAT"} if ($g.sha) { $sha=$g.sha } # 有 sha = 文件已存在,走更新 } catch { } # GET 失败(含 400/404)一律视为不存在,忽略 if ($sha) { $body=@{message="update $f"; content=$b64; sha=$sha; branch="master"} | ConvertTo-Json -Compress Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/contents/$f" ` -Method Put -Headers @{Authorization="token $PAT"} -ContentType "application/json" -Body $body } else { $body=@{message="add $f"; content=$b64; branch="master"} | ConvertTo-Json -Compress Invoke-RestMethod -Uri "https://gitee.com/api/v5/repos/$owner/$repo/contents/$f" ` -Method Post -Headers @{Authorization="token $PAT"} -ContentType "application/json" -Body $body } - 验证:
GET /api/v5/repos/{owner}/{repo}/contents/确认根目录文件齐全,默认分支为master。 - 清理:删除临时文件;本地
git remote set-url origin https://gitee.com/{owner}/{repo}.git(勿在 remote 中残留 PAT)。
注意事项
- PowerShell 工具的 stdout 可能不被界面捕获,把结果
Out-File到项目外文件再Read查看。 - PAT 会进入命令日志,完成后提醒用户到 Gitee「设置 → 私人令牌」撤销/重生成该令牌。
- 本环境的 git 即便 remote 已设好也无法 pull/push,用户需在有网的机器
git clone获取代码(远程仓库本身是完整正确的)。 - 不要尝试用
git push或curl联网——两者在本环境都会因 DNS 故障失败。 - Gitee contents 接口状态码不可靠:
POST创建已存在文件返回400(不是 409);GET不存在路径返回200空数组[](不是 404)。判断新建/更新的唯一可靠依据是响应里有没有sha字段——有则PUT更新,无则POST创建(见步骤 3)。
Pitfalls(本环境 PowerShell 5.1 专项,已踩坑)
- ① 脚本含中文字面量会被按 GBK 解析而报错:PowerShell 5.1 读无 BOM 的 UTF-8
.ps1时按系统默认 ANSI/GBK 解码。若脚本里出现中文字面量(最常见是路径"C:\...\libTV开发"),解码后会产生乱码字节、破坏字符串/命令的 token 化,报表达式或语句中包含意外的标记之类的解析错误。解决办法:脚本里不要写中文字面量——目录路径改用Get-ChildItem "C:\Users\<user>\WorkBuddy" -Directory | Where-Object { $_.Name -like "libTV*" }解析出全路径,再由 .NET 字符串正确返回;日志文案也尽量用英文。 - ② 函数内
$x +=是局部变量,不修改脚本级$x:在 PowerShell 函数中对脚本级数组做$x += ...会在函数作用域新建一个局部$x,脚本级数组保持为空,导致后续遍历上传时一个文件都没传(日志里既无 OK 也无 FAIL,但删除/校验等硬编码列表照常执行)。解决办法:函数内用$script:x += ...显式写回脚本作用域;或把收集逻辑写成内联循环而非函数。 - ③ 分支创建接口路径:建分支是
POST /api/v5/repos/{owner}/{repo}/branches(body{branch_name, refs}),不要拼在/contents之后(/contents/../branches虽能归一化但易误读),单独定义$branchesUrl。分支已存在会返回 400,可忽略继续。 - ④ 删除文件:
DELETE /api/v5/repos/{owner}/{repo}/contents/{path},body 需带sha(先 GET 取)+branch;不存在则 GET 无 sha,跳过即可。