跳转到内容
新建笔记

Git 实践:同树不同提交的分叉同步

处理这种状态:本地分支和远程分支显示同时领先、落后,但双方某些提交产生的文件内容完全相同。目标是保留真正的新改动,跳过重复补丁,形成线性历史并完成非强制推送。

本次实例最初显示:

v20-noddr...origin/v20-noddr [ahead 2, behind 1]
> 6e82349 本地实际更新
> e1032c1 本地重复提交
< ab26824 远程重复提交

e1032c1 与 ab26824 的提交哈希、作者信息和说明不同,但树对象相同,说明两次提交的最终文件快照一致。

git pull 的整合方式取决于选项与配置。先 fetch 再查看提交图,才能决定使用 merge、rebase 还是只允许快进;不能因为树相同就直接 force push。这个案例采用以下顺序:

  1. 检查并保护工作区。
  2. 确认重复提交是否真的具有相同树对象。
  3. 建立本地备份引用。
  4. 获取并清理远程跟踪引用。
  5. 将真正的本地提交 rebase 到远程分支。
  6. 普通推送并比较远程提交号。

先查看分支、工作区和分叉图:

终端窗口
git status --short --branch
git branch -vv
git fetch origin
git log --oneline --decorate --graph --left-right origin/v20-noddr...v20-noddr

不要只依据提交说明判断内容。使用树对象比较两个提交的完整文件快照:

终端窗口
git show -s --format=%T e1032c1
git show -s --format=%T ab26824
git diff --stat e1032c1 ab26824
git diff --name-status e1032c1 ab26824

本实例中两个 %T 输出一致,两个 diff 也为空,因此可以确认最终快照相同。仍应检查父提交和各自差异;树相同本身并不保证任意 rebase 都可以无冲突跳过对应提交。

执行 rebase 前必须先处理未提交内容。Vivado 等 IDE 可能只因打开工程就改写绝对路径、UUID、运行目录或仿真元数据,这类变化不能未经检查就提交或丢弃。

终端窗口
git diff --check
git diff --stat
git diff -- path/to/project.xpr

若需要暂存这些变化,应限定精确路径并写清原因:

终端窗口
git stash push -m "IDE automatic project rewrite" -- path/to/project.xpr

不要在工作区有未知改动时执行 reset --hard 或开始 rebase。

工作区干净后,先给当前状态建立本地备份引用:

终端窗口
git switch v20-noddr
git branch backup/v20-noddr-before-sync-20260817 HEAD
git fetch --prune origin
git rebase origin/v20-noddr

本实例的 rebase 输出包含:

warning: skipped previously applied commit e1032c1
Successfully rebased and updated refs/heads/v20-noddr.

Git 识别出 e1032c1 的补丁已由远程提交实现,因此跳过它,只把实际更新重新应用到 ab26824 之后。rebase 后实际更新的提交哈希由 6e82349 变为 ee85e14,这是重建提交的正常结果。

先确认只领先远程一个真实提交,再使用普通推送:

终端窗口
git status --short --branch
git diff --check origin/v20-noddr...HEAD
git log --oneline --decorate --graph -n 5
git push origin v20-noddr

最后不要只相信 git push 的文字提示,应读取远程引用并和本地 HEAD 比较:

终端窗口
git rev-parse HEAD
git ls-remote --heads origin v20-noddr
git status --short --branch

本实例最终本地和远程都指向:

ee85e14bd6fa9b06f0475b8960833ae2badd8d5b

工作区干净,分支不再领先或落后,整个过程没有 merge commit、force push 或历史分支删除。

若此前创建了 IDE 修改的 stash,应选择正确条目 git stash apply --index,检查并解决可能的冲突后,再删除该 stash;不要为了得到干净状态而丢弃原有修改。

  • ahead/behind 描述提交图关系,不等同于文件内容不同。
  • 比较提交树比比较提交信息更可靠;树相同表示完整文件快照相同。
  • git fetch --prune 的清理范围取决于 refspec;默认分支映射通常清理失效的远程跟踪分支,自定义标签映射应另外检查。
  • rebase 可能自动跳过已在上游实现的补丁,这是本场景需要的行为。
  • rebase 会改变被重新应用提交的哈希,所以推送前必须重新记录最终提交号。
  • IDE 自动改写与功能修改要分开审查,不能因为工程“验证通过”就把所有元数据变化一并提交。
  • 同步完成的判据是本地引用、远程引用和工作区状态一致,不只是命令返回成功。

如果 rebase 尚未完成且结果不正确:

终端窗口
git rebase --abort

如果 rebase 已完成但尚未推送,可以从事先创建的备份分支检查或恢复提交。不要在未确认目标提交和工作区状态时使用破坏性重置。