GPT 改完配置别直接覆盖:用 git diff 审查两份文件

拿到一份"已经优化"的配置,最容易漏掉的不是文件能否打开,而是它顺便改了什么。比如需求只要求把超时从5秒调到10秒,新文件却同时把TLS证书校验关掉。即使JSON合法,应用也能启动,这个改动仍不该直接上线。
我用Git 2.43.0做了一次完全本地的对照。两份配置都是合成样本,没有发送真实配置给模型,也没有实际修改任何服务。目标是用现成工具把改动摆出来,再分清"有差异""有格式问题"和"不符合业务策略"。
不建仓库也能比较
Git官方文档说明,git diff --no-index可以比较文件系统里的两个路径,不需要先初始化仓库。这个形式隐含--exit-code:无差异返回0,有差异返回1。1 因此脚本看到1就报警"命令执行失败",会把正常比较误报成工具故障。
先保存下面脚本为reproduce.py,在装有Git的Linux环境执行python3 reproduce.py。它只在自动清理的临时目录创建三份文本,不运行git add或git commit,也不改现有仓库。
python
import json
from pathlib import Path
import os
import shutil
import subprocess
import tempfile
GIT = shutil.which("git")
if not GIT:
raise SystemExit("git is required")
with tempfile.TemporaryDirectory(prefix="diff-demo-") as tmp:
root = Path(tmp)
env = {"PATH": "/usr/bin:/bin", "HOME": tmp, "LC_ALL": "C",
"GIT_CONFIG_NOSYSTEM": "1", "GIT_CONFIG_GLOBAL": "/dev/null"}
before = '{\n "timeout_seconds": 5,\n "verify_tls": true\n}\n'
after = '{\n "timeout_seconds": 10,\n "verify_tls": false\n}\n'
(root / "before.json").write_text(before)
(root / "after.json").write_text(after)
(root / "spaced.json").write_text(after.replace('10,', '10, '))
def diff(left, right, *options):
return subprocess.run(
[GIT, "--no-pager", "-c", "core.whitespace=blank-at-eol",
"diff", "--no-index", "--no-ext-diff", "--no-textconv",
"--color=never", *options, "--", left, right],
cwd=root, env=env, capture_output=True, text=True,
timeout=5, check=False,
)
same = diff("before.json", "before.json")
changed = diff("before.json", "after.json", "--word-diff=plain")
assert same.returncode == 0 and changed.returncode == 1
assert '[-true-]{+false+}' in changed.stdout
print("same_exit:", same.returncode)
print("changed_exit:", changed.returncode)
print("word_diff:")
print(changed.stdout, end="")
clean = diff("before.json", "after.json", "--check")
spaced = diff("before.json", "spaced.json", "--check")
assert 'trailing whitespace' not in clean.stdout + clean.stderr
assert 'trailing whitespace' in spaced.stdout + spaced.stderr
print("check_clean_exit:", clean.returncode)
print("check_spaced_exit:", spaced.returncode)
print("check_spaced_output:")
print(spaced.stdout + spaced.stderr, end="")
config = json.loads(after)
assert config["verify_tls"] is False
def acceptable(value):
return value.get("verify_tls") is True
assert acceptable(json.loads(before))
assert not acceptable(config)
print("semantic_acceptance: rejected_verify_tls_false")
invalid = '{"timeout_seconds": }'
try:
json.loads(invalid)
except json.JSONDecodeError:
print("invalid_json: rejected_by_parser")
else:
raise AssertionError("invalid JSON accepted")
print("ALL_ASSERTIONS_PASSED")
脚本用独立临时HOME和明确的Git配置关闭用户、系统配置影响,并禁止外部diff和textconv。这只是让本次实验更可控,不是任意文件处理的完整沙箱。临时目录之外的真实项目没有参与比较。
从整行变化缩小到值变化
常规差异会显示整行删除和新增。--word-diff=plain进一步用[-删除-]与{+新增+}标记变化。1 在本次输出里,超时由5变10,紧接着TLS校验从true变false;第二项不是需求的一部分。
不过词级显示不理解JSON字段。默认分词依赖空白,紧凑的一行JSON可能仍显示大块变化;plain格式也不会转义原文中相同的分隔标记,不能拿它当可靠的机器解析接口。1 我的用法是帮助人定位,然后用结构化解析器读取值,而不是靠高亮判断改动正确。
实际输出揭示了两种误判
脚本保存的stdout关键片段如下,完整差异也已在本次运行输出中保留:
text
same_exit: 0
changed_exit: 1
"timeout_seconds": [-5,-]{+10,+}
"verify_tls": [-true-]{+false+}
check_clean_exit: 1
check_spaced_exit: 3
spaced.json:2: trailing whitespace.
semantic_acceptance: rejected_verify_tls_false
invalid_json: rejected_by_parser
ALL_ASSERTIONS_PASSED

第一种误判是"有差异就失败":这忽略了no-index的正常返回约定。第二种是"空白检查没报问题就安全":这把文本质量当成了业务验收。去掉行尾空格不会把false变回true,配置仍违反本例必须开启证书校验的规则。
这里还特意保留了一个容易混淆的组合:本机把--no-index与--check一起运行时,无空白诊断的改动返回1,有行尾空格时返回3。它们是本次Git版本的实际结果,不是所有环境的统一退出码规范。官方文档明确指出--check与--exit-code不兼容,而no-index又隐含后者。1 所以自动化不能把组合命令所有非零状态统一解释为"发现尾空格"。需要确认具体调用方式,分别记录输出、状态与错误。
接入工作流要守住哪一层
--check用于检查引入的冲突标记和空白错误,具体空白规则由core.whitespace控制。本例明确只指定blank-at-eol,不要把结果扩大成"格式全部合格"。它不会验证字段类型、范围,也不会证明JSON合法。
真正决定是否接受的步骤在解析之后:先用JSON解析器拒绝坏语法,再检查本例的verify_tls策略。正式应用还需要验证超时单位、数值范围、未知字段和必填项。这里仅展示一个策略分支,不冒充完整配置校验器。
我的做法是保留原文件,不把新稿直接覆盖进去;先审查完整diff,再运行业务验收。不能为了让差异看起来少就默认加-w忽略空白,有些文件格式和代码缩进确实依赖空白。比较工具负责说明哪里变了,接受规则负责说明哪些改动允许发生,两者不要混为一谈。
让GPT辅助配置修改时,可以要求只返回需求涉及的字段,并解释每一项差异,但本文没有实际调用模型,不把这次合成文件说成真实模型回复。gpt68.com是第三方AI会员服务平台,并非模型厂商官网或授权合作方;工具输出和可运行验收才是本例的依据。
**AI辅助说明:**本文整理使用AI辅助;合成输入、Git命令和正常、异常断言已本地实际运行,无真实生产配置或虚构上线事故。