Files
dsh_shenxian/scripts/compare-tree.py
T
admin 5ec99ce227
build / build-and-scan (push) Waiting to run
chore: 文档库全量重新入库(2026-10-20)
2026-10-20 15:05:55 +08:00

91 lines
3.1 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.
#!/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))