diff --git a/engine.go b/engine.go index 9abbf93..9f12aad 100644 --- a/engine.go +++ b/engine.go @@ -531,6 +531,7 @@ func (e *Engine) syncOnce(s *repoState, trigger string) { // 分支对齐:本地当前分支与配置不一致时,自动切换/创建(对齐原 bash 脚本行为) // 否则 push 会因 src refspec 不存在而失败 if cur, cerr := currentBranch(cfg.RepoPath); cerr == nil && cur != cfg.Branch { + tip, remoteHasBranch := remoteTip(cfg.RepoPath, remote, cfg.Branch) switch { case branchExists(cfg.RepoPath, cfg.Branch): if _, err := gitRun(cfg.RepoPath, 30*time.Second, "checkout", cfg.Branch); err != nil { @@ -538,12 +539,12 @@ func (e *Engine) syncOnce(s *repoState, trigger string) { } else { e.logf(s, "info", "本地分支与配置不一致(%s → %s),已自动切换", cur, cfg.Branch) } - case remoteRefExists(cfg.RepoPath, remote, cfg.Branch): - if _, err := gitRun(cfg.RepoPath, 30*time.Second, "checkout", "-B", cfg.Branch, remote+"/"+cfg.Branch); err != nil { - e.logf(s, "warn", "基于 %s/%s 创建分支失败: %v(继续在 %s 上同步)", remote, cfg.Branch, err, cur) + case remoteHasBranch: + if _, err := gitRun(cfg.RepoPath, 30*time.Second, "checkout", "-B", cfg.Branch, tip); err != nil { + e.logf(s, "warn", "基于远程 %s 创建分支失败: %v(继续在 %s 上同步)", cfg.Branch, err, cur) } else { _, _ = gitRun(cfg.RepoPath, 15*time.Second, "branch", "--set-upstream-to", remote+"/"+cfg.Branch, cfg.Branch) - e.logf(s, "info", "本地无分支 %s,已基于 %s/%s 创建并跟踪", cfg.Branch, remote, cfg.Branch) + e.logf(s, "info", "本地无分支 %s,已基于远程 %s(%s)创建并跟踪", cfg.Branch, cfg.Branch, tip[:8]) } default: if _, err := gitRun(cfg.RepoPath, 30*time.Second, "checkout", "-B", cfg.Branch); err != nil { @@ -576,8 +577,9 @@ func (e *Engine) syncOnce(s *repoState, trigger string) { var ahead, behind int var err error - if remoteRefExists(cfg.RepoPath, remote, cfg.Branch) { - ahead, behind, err = aheadBehind(cfg.RepoPath, remote, cfg.Branch) + tip, remoteHasBranch := remoteTip(cfg.RepoPath, remote, cfg.Branch) + if remoteHasBranch { + ahead, behind, err = aheadBehindSha(cfg.RepoPath, tip) if err != nil { e.setFail(s, "获取领先/落后信息失败: "+err.Error()) return diff --git a/git.go b/git.go index c1dd787..91ab1d3 100644 --- a/git.go +++ b/git.go @@ -87,6 +87,42 @@ func branchExists(path, branch string) bool { return err == nil } +// remoteTip 返回远程分支当前指向的 SHA。 +// 优先读本地远程跟踪引用(refs/remotes//,快); +// 若本地跟踪引用不可用(个别环境下 ref 存储读写异常),回退用 ls-remote 直查远程。 +func remoteTip(path, remote, branch string) (sha string, exists bool) { + if remoteRefExists(path, remote, branch) { + out, err := gitRun(path, 15*time.Second, "rev-parse", remote+"/"+branch) + if err == nil { + return strings.TrimSpace(out), true + } + } + out, err := gitRun(path, 30*time.Second, "ls-remote", remote, "refs/heads/"+branch) + if err != nil { + return "", false + } + fields := strings.Fields(strings.TrimSpace(out)) + if len(fields) < 2 { + return "", false + } + return fields[0], true +} + +// aheadBehindSha 基于远程分支的具体 SHA 计算 (领先, 落后),不依赖本地跟踪引用 +func aheadBehindSha(path, tip string) (int, int, error) { + out, err := gitRun(path, 30*time.Second, "rev-list", "--left-right", "--count", "HEAD..."+tip) + if err != nil { + return 0, 0, err + } + parts := strings.Fields(out) + if len(parts) != 2 { + return 0, 0, fmt.Errorf("无法解析 rev-list 输出: %q", out) + } + a, _ := strconv.Atoi(parts[0]) + b, _ := strconv.Atoi(parts[1]) + return a, b, nil +} + func dirtyCount(path string) int { out, err := gitRun(path, 30*time.Second, "status", "--porcelain") if err != nil { diff --git a/logs/git-auto-sync.log b/logs/git-auto-sync.log index e341236..477b6b1 100644 --- a/logs/git-auto-sync.log +++ b/logs/git-auto-sync.log @@ -175,3 +175,10 @@ hint: See the 'Note about fast-forwards' in 'git push --help' for details. [2026-09-08 18:13:59] 推送失败,本轮同步已终止(跳过拉取以避免分叉加剧) [2026-09-08 18:14:59] === 开始同步(定时检查,模式 push)=== [2026-09-08 18:15:09] 检测到 2 个未提交改动,执行自动提交 +[2026-09-08 18:15:13] 自动提交完成,将随本轮同步推送 +[2026-09-08 18:15:15] 远程分支 origin/main 不存在(远程仓库可能为空或分支名不一致),将推送本地 23 个提交以建立远程分支 +[2026-09-08 18:20:25] 推送至 origin 失败: 命令超时: git push origin main +[2026-09-08 18:20:25] 推送失败,本轮同步已终止(跳过拉取以避免分叉加剧) +[2026-09-08 18:21:31] 监控已启动 +[2026-09-08 18:21:31] === 开始同步(启动检查,模式 push)=== +[2026-09-08 18:21:40] 检测到 4 个未提交改动,执行自动提交 diff --git a/stats/git-auto-sync.csv b/stats/git-auto-sync.csv index 33b0eec..6371d75 100644 --- a/stats/git-auto-sync.csv +++ b/stats/git-auto-sync.csv @@ -20,3 +20,4 @@ timestamp,action,result,commits 2026-09-08 18:01:06,push,failed,20 2026-09-08 18:07:32,push,failed,21 2026-09-08 18:13:59,push,failed,22 +2026-09-08 18:20:25,push,failed,23