git diff 仅同步代码变更且需严格对齐基准版本,git format-patch + git am 才能保留完整提交历史;参数顺序错误(如颠倒基准与目标分支)会导致补丁反向,引发“patch does not apply”错误。

能同步,但必须严格对齐两端的 Git 基准版本,否则 git apply 会失败;git format-patch + git am 才能带提交历史,单纯 git diff 只同步代码变更。
用 git diff 同步分支差异时,参数顺序不能颠倒
比如要把 feature/login 的改动合入 main,命令是:
git diff main feature/login > login-change.patch
这里 main 是基准(“旧”),feature/login 是目标(“新”)。如果写成 git diff feature/login main,补丁内容就是反向的——删除本该新增的代码、添加本该删除的代码,git apply 必然报 patch does not apply。
- 确认基准是否一致:目标机器上执行
git log -1 --oneline,和生成 patch 时的main最新 commit ID 必须完全相同 - 只同步部分文件?加路径限定:
git diff main feature/login src/utils/ auth.js src/components/Login.vue > partial.patch - 含新建文件?先在源端执行
git add -N,再用git diff --cached,否则新文件不会进 patch
git apply 失败的常见原因和应对
git apply 不是万能的,它只做内容叠加,不处理分支逻辑。失败时别急着重传,先看提示:
-
error: patch failed: xxx.js:123→ 目标文件第 123 行上下文和 patch 里不匹配,大概率是目标代码比基准版本多了其他修改 -
fatal: unrecognized input→ Windows CMD 下常见,改用 Git Bash 或 VSCode 集成终端执行,避免换行符解析错误 - 想预演能否成功?运行
git apply --check login-change.patch,返回 0 表示可干净应用 - 有冲突又不想中断流程?加
--reject参数:git apply --reject login-change.patch,冲突块会写入xxx.rej文件,手动修完再git add提交
要保留 commit 历史?必须用 git format-patch + git am
git diff 生成的是纯文本差异,git format-patch 生成的是带元数据的邮件格式补丁,包含作者、时间、提交信息。比如在 feature/login 分支上:
git format-patch -1 HEAD # 生成最近一次提交的 .patch 文件
得到类似 0001-add-login-validation.patch 的文件,传到目标机器后,在 main 分支上运行:
git am 0001-add-login-validation.patch
- 成功后
git log会看到完整提交记录,作者、日期、message 全部保留 - 若中途出错,
git am --abort可回退,git am --continue继续 - 注意:目标分支必须是干净工作区(
git status无未提交变更),否则git am拒绝执行 - 多个 patch?按顺序命名(如
0001-xxx.patch,0002-yyy.patch),直接git am *.patch
离线同步最易被忽略的细节
两端仓库结构必须一致:补丁里所有路径都是相对于 Git 仓库根目录的。如果源端在 /project 下执行 git diff,目标端也必须在 /project 根目录下 git apply,哪怕只是多了一层子目录,路径就全错。
新建文件的父目录不存在?git apply 不会自动创建,得提前 mkdir -p;而 git am 在裸仓库或非标准结构下也可能失败,这时就得回到 git diff --cached + 手动 git add + git commit 的组合拳。











