Files
ykxmz/_build/ezhub_push_all.py
T
xmz7891 f200240730 发布脚本:EzHub 走 HTTPS+令牌推送(SSH 还没配好)
EzHub 的 SSH 公钥在服务端一直被拒(Permission denied),
但令牌有 push 权限。所以发布脚本里 EzHub 改用
HTTPS + 令牌推,令牌只在进程内拼进 URL,不写进 .git/config。

顺带加了增量推送脚本 ezhub_push_all.py:
一次性推 44 个提交 = 117 MB,被 EzHub 的 nginx 413 拦了。
Git 推送是增量的,逐个提交推每包就小得多 —— 实测 44 个全部推成功。
脚本会先探测远端进度,只推缺的,并且对网络抖动自动重试。
2026-10-07 12:32:11 +08:00

146 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
r'''带重试的增量推送 —— 把 44 个提交逐个推到 EzHub。
为什么逐个推:
一次性推 44 个提交 = 117 MB,EzHub 的 nginx 返回 413。
但 Git 推送是"增量"的:第一个提交推成功后,
后面每个提交只需要传自己新增的对象。
逐个推,每包只有几十 KB ~ 几 MB,就不会撞上限。
为什么带重试:
这台网络(4G + 家宽)会偶发连不上 git.261826.xyz。
实测推第 5 个提交时报 "Failed to connect" —— 纯网络抖动,
重试就好。不加重试会白费前面推成功的部分(虽然它们已经进仓库了,
但脚本会误以为整体失败)。
已经推上去的提交会自动跳过(push 会说 Everything up-to-date)。
'''
from __future__ import annotations
import subprocess
import sys
import time
from pathlib import Path
ROOT = Path(r"C:\Users\shu\Desktop\deepseekagent\LanRemote")
GIT = r"C:\Program Files\Git\bin\git.exe"
TOKEN_FILE = Path.home() / ".ykxmz" / "ezhub_token"
OWNER, REPO, HOST = "xmz", "ykxmz", "git.261826.xyz"
MAX_TRIES = 4
RETRY_WAIT = 6 # 秒,每次重试前等这么久
def git(*args: str) -> subprocess.CompletedProcess:
return subprocess.run([GIT] + list(args), cwd=str(ROOT),
capture_output=True, text=True,
encoding="utf-8", errors="replace")
def remote_main(url: str) -> str:
"""取远端 main 指向哪个提交(空仓库返回空串)。"""
r = subprocess.run([GIT, "ls-remote", url, "refs/heads/main"],
cwd=str(ROOT), capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=120)
line = (r.stdout or "").strip()
return line.split()[0] if line else ""
def push_one(url: str, sha: str, token: str) -> tuple:
"""推一个提交。返回 (成功?, 说明)。
⚠ 如果远端已经超过这个提交了,再推它就是"回退",
Git 会拒绝(non-fast-forward)。这种情况视为成功(跳过),
因为它的内容已经在远端的历史里了。
"""
last = ""
for attempt in range(1, MAX_TRIES + 1):
r = subprocess.run(
[GIT, "push", url, "%s:refs/heads/main" % sha],
cwd=str(ROOT), capture_output=True, text=True,
encoding="utf-8", errors="replace", timeout=900)
err = (r.stderr or r.stdout or "").replace(token, "***")
if r.returncode == 0:
if "Everything up-to-date" in err:
return True, "已是最新"
return True, "ok"
last = [ln for ln in err.strip().splitlines() if ln.strip()]
last = last[-1][:110] if last else "?"
# 远端已经往前走了 -> 这个提交已经在历史里,跳过
if "non-fast-forward" in err or "fast-forwards" in err:
return True, "远端已包含(跳过)"
# 只对"能重试"的错误重试:网络抖动 / 5xx
retryable = any(k in last for k in (
"Failed to connect", "Connection reset", "timed out",
"Could not resolve", "RPC failed", "unexpected disconnect",
" 500", " 502", " 503", " 504"))
if not retryable or attempt == MAX_TRIES:
return False, "第 %d 次: %s" % (attempt, last)
print(" 重试 %d/%d(%s)" % (attempt, MAX_TRIES, last[:50]))
time.sleep(RETRY_WAIT)
return False, last
def main() -> int:
if not TOKEN_FILE.is_file():
print(" [失败] 没有令牌,先跑 ezHub_push.py <令牌>")
return 1
token = TOKEN_FILE.read_text(encoding="utf-8").strip()
url = "https://%s:%s@%s/%s/%s.git" % (OWNER, token, HOST, OWNER, REPO)
out = git("rev-list", "--reverse", "HEAD").stdout or ""
commits = [c for c in out.splitlines() if c.strip()]
total = len(commits)
head = remote_main(url)
if head:
# 远端已经有的那些直接跳过
ahead = git("rev-list", "--reverse", "%s..HEAD" % head).stdout or ""
todo = [c for c in ahead.splitlines() if c.strip()]
print(" 远端 main 已在 %s" % head[:12])
print(" 共 %d 个提交,其中 %d 个已经在远端,需要推 %d 个"
% (total, total - len(todo), len(todo)))
else:
todo = commits
print(" 远端还是空的")
print(" 共 %d 个提交,需要全部推" % total)
print()
if not todo:
print(" ✓ 远端已经是最新,不用推")
done = 0
for index, sha in enumerate(todo, 1):
ok, why = push_one(url, sha, token)
if ok:
done = index
if index % 5 == 0 or index == len(todo):
print(" %3d/%d ✓" % (index, len(todo)))
else:
print(" %3d/%d ✗ %s" % (index, len(todo), why))
r = git("show", "--stat", "--oneline", sha)
print(" 这个提交改了什么:")
for line in (r.stdout or "").strip().splitlines()[:8]:
print(" " + line[:95])
print()
print(" 这一轮推到第 %d 个,还剩 %d 个"
% (done, len(todo) - done))
print(" 再跑一次本脚本会从断的地方继续。")
return 1
print()
print(" ✓ 这一轮全部推完" % ())
# 确认
remote_sha = remote_main(url)
local_sha = git("rev-parse", "HEAD").stdout.strip()
print(" 远端 main: %s" % remote_sha[:12])
print(" 本地 HEAD: %s" % local_sha[:12])
print(" %s" % ("✓ 一致" if remote_sha == local_sha else "✗ 不一致"))
return 0 if remote_sha == local_sha else 1
if __name__ == "__main__":
sys.exit(main())