Files

90 lines
3.1 KiB
Python
Raw Permalink Normal View History

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""compare-tree.py —— 把**本地 git 基线**(manifest:mode/type/sha\\tpath)与服务器工作树逐文件比对。
输出三类(这是"能不能整树覆盖"的唯一判据,不盲覆盖):
· 一致 :服务器文件内容 == 本地基线
· 不一致 :两边都有但内容不同(**要逐个看是谁的改动**)
· 服务器独有:服务器有、基线里没有(**绝不能抹**)
再加一类「仅在基线里」:本地有、服务器缺(同步时要补上)。
用法(在服务器上):python3 scripts/compare-tree.py <manifest> <工作树根>
"""
import os
import subprocess
import sys
manifest, root = sys.argv[1], sys.argv[2]
entries = []
for line in open(manifest, encoding='utf-8'):
line = line.rstrip('\n')
if not line.strip():
continue
head, path = line.split('\t', 1)
mode, typ, sha = head.split()
entries.append((path, sha))
paths = [p for p, _ in entries]
present = [p for p in paths if os.path.isfile(os.path.join(root, p))]
missing = [p for p in paths if p not in set(present)]
# 批量算 sha(git hash-object --stdin-paths)
hash_out = {}
if present:
proc = subprocess.run(['git', 'hash-object', '--stdin-paths'], cwd=root,
input='\n'.join(present) + '\n', capture_output=True, text=True)
for p, h in zip(present, proc.stdout.split('\n')):
if h.strip():
hash_out[p] = h.strip()
same, diff = [], []
for p, sha in entries:
if p in missing:
continue
if hash_out.get(p) == sha:
same.append(p)
else:
diff.append((p, sha, hash_out.get(p)))
# 服务器独有:扫同一批顶层目录,取基线里没有的文件
tops = sorted({p.split('/')[0] for p, _ in entries})
known = set(paths)
extra = []
for top in tops:
base = os.path.join(root, top)
if not os.path.isdir(base):
continue
for dirpath, dirnames, filenames in os.walk(base):
dirnames[:] = [d for d in dirnames if d not in ('node_modules', '.git', 'dist')]
for fn in filenames:
rel = os.path.relpath(os.path.join(dirpath, fn), root).replace(os.sep, '/')
if rel not in known:
extra.append(rel)
print('=== 汇总 ===')
print(' 基线条目 : %d' % len(entries))
print(' 一致 : %d' % len(same))
print(' 不一致 : %d' % len(diff))
print(' 仅基线有(缺) : %d' % len(missing))
print(' 服务器独有 : %d' % len(extra))
if diff:
print('\n=== 不一致(要逐个判断是谁的改动)===')
for p, want, got in diff[:60]:
print(' %-58s 基线 %s 服务器 %s' % (p, want[:10], (got or '')[:10]))
if len(diff) > 60:
print(' … 还有 %d 个' % (len(diff) - 60))
if missing:
print('\n=== 仅基线有(服务器缺)===')
for p in missing[:40]:
print(' ' + p)
if len(missing) > 40:
print(' … 还有 %d 个' % (len(missing) - 40))
if extra:
print('\n=== 服务器独有(⛔ 覆盖前必须保留/处理)===')
for p in extra[:60]:
print(' ' + p)
if len(extra) > 60:
print(' … 还有 %d 个' % (len(extra) - 60))