合并和变基都用于整合历史,但产生的提交图不同。先决定要保留怎样的历史,再处理具体冲突,避免把“保存文件”“完成合并”“推送远端”混成一个动作。
merge 与 rebase 的区别
跳转到“merge 与 rebase 的区别”分叉: A--B--C main \--D feature
merge: A--B--C--M main \--D--/ M 有两个父提交
rebase: A--B--C--D' feature D' 是重新应用 D 的新提交快进只是移动引用;两条分支已经分叉时,即使没有文件冲突,也可能创建 merge commit。rebase 通常改变被重放提交的哈希,适合尚未公开的个人提交;已共享的历史应先按项目协作规则处理。
开始前保护工作区
跳转到“开始前保护工作区”git status --short --branchgit diffgit diff --cachedgit branch backup/before-integration HEAD本地备份分支保护已提交历史,不保存未提交文件。未完成的改动可以精确 stash:
git stash push -u -m "work before integration" -- .gitignore src/main.cgit stash list默认 stash 不包含未跟踪文件,-u 包含未跟踪文件,-a 还包括被忽略文件。操作完成后先 git stash apply --index 'stash@{0}',检查工作区和暂存状态,再决定是否 drop;apply 本身也可能产生冲突。
合并的完整路径
跳转到“合并的完整路径”假设需要把开发分支 qt_derived 合入 main:
git switch maingit merge --no-ff qt_derived若合并成功,检查代码并测试后推送。若出现冲突,先查看 git status,再逐个编辑文件,删除冲突标记并保留正确的逻辑。确认后按精确路径暂存,以下完成方式选一种:
git add -- .vscode/settings.json assets/assets.qrcgit diff --cached --checkgit merge --continuegit commit 也能完成这一步;已经 commit 后不必再执行 merge continue。不准备继续时用 git merge --abort。开始时保留复杂未提交修改可能导致 abort 无法完整重建原状态,因此应先保护工作区。
一个实际冲突记录应如何读
跳转到“一个实际冲突记录应如何读”原实践记录同时出现三类状态:
| 文件/状态 | 解释 | 处理方法 |
|---|---|---|
.vscode/settings.json both added | 两边分别新增同一路径 | 比较两份设置,选择正确项目配置 |
assets/assets.qrc both modified | 两边都改了资源清单 | 合并资源条目,检查路径、重复项与实际文件 |
.gitignore 普通未暂存修改 | 不一定属于本次冲突 | 单独保留,别被 git add . 顺手带入 |
记录中还出现名为 --[no-]pathspec-file-nul、--post-rewrite、git、read、show、with 的未跟踪文件,疑似误粘贴命令帮助造成。它们的名称异常不等于内容必然无用:先检查准确路径、内容和创建原因,再清理,不能直接对整个工作区运行 git clean -fd。
变基的完整路径
跳转到“变基的完整路径”先进入需要重放的分支:
git switch featuregit fetch origingit rebase origin/main冲突时编辑并 git add -- <文件>,然后 git rebase --continue;放弃则 git rebase --abort。--skip 会跳过当前提交,只有确定该变更应丢弃或已等价包含时才使用。完成后比较结果、运行测试,再按 远程同步 推送。
git rebase --onto new-base old-base topic 选择 topic 中不属于 old-base 的提交重放到 new-base;两个 base 必须按提交图确定,不能仅按日期猜测。要为已有远程分支建立本地 jp2,应先 fetch,再 git switch --track -c jp2 origin/jp2。
常见选项的真实含义
跳转到“常见选项的真实含义”| 选项 | 含义与限制 |
|---|---|
--ff-only | 只接受快进,分叉时停止 |
--no-ff | 即使可快进也保留一次合并提交 |
--squash | 将合并结果放进工作区/索引;不记录合并父关系,需自行提交 |
-X ours | 对可按该选项处理的冲突偏向当前一侧,仍接纳对方非冲突修改 |
-s ours | 结果树完全取当前分支,忽略其他树;语义远强于解决冲突 |
| octopus | 多头合并策略,不适合复杂手工冲突 |
--gpg-sign、--stat | 分别涉及提交签名和变化摘要,不决定冲突内容 |
--autostash | 临时保存未提交工作,恢复时仍可能冲突 |
空白忽略、重命名检测等 -X 选项应按实际策略文档使用;它们不能代替审查。详见 git-merge。
撤销合并后,为什么再合并没有恢复
跳转到“撤销合并后,为什么再合并没有恢复”原记录中的合并提交 1fd7eec 有父提交 b752882 与 1a86620。必须先用 git show --no-patch --pretty=raw 1fd7eec 验证顺序,不能假定 -m 1 永远指想保留的一侧。
git revert -m 1 <merge> 创建新的反向提交,历史仍记得旧分支已合并。因此再次 merge 相同祖先历史,不会自动把已撤销内容全部带回。后续若要恢复,应讨论撤销那次 revert,或引入真正的新提交,再检查依赖关系。尚未公开的错误操作可从备份引用重新整理,但不是任何情况都需要强推。