Git 支持的合并方式只有两种:ff 和 no-ff。
如果当前分支是并入 commit 的祖先,执行 ff commit。直接将当前分支快进到指定 commit 而不产生 Merge commit。
如果无法执行 ff merge 或者强制使用了
--no-ff
,处理冲突并合并代码后会产生一个 Merge commit。如果对 Merge commit 执行 reset 操作,则相当于 merge 被取消。
根据功能上还有下面几种合并方式:
rebase merge。合并前在并入分支上执行 rebase 以执行 ff merge。这是 线性提交历史 要求的做法。
squash merge。合并时添加参数
--squash
。这将导致并入分支上的 commit 被压缩成一个被合并。
线性提交历史
通过确保代码合并总是以 ff 的形式进行合并,能够避免产生 Merge commit,从而形成整洁的、单一线性的提交历史。线性提交历史具备一些优点。例如:
线性提交历史比非线性提交历史更易于理解。
更易于回溯更改。
易于跟踪错误。例如有利于 git bitset 的使用。
易于回滚更改。revert merge commit 会导致整个合并被回滚,而线性历史不会。
线性提交历史的关键之处在于在合并之前总是执行 rebase 以确保当前分支已经包含了被并入分支的所有 commit。从而在合并时执行 ff 合并。然而,由于 rebase 自身的问题,这可能带来一些问题:
rebase 会更改当前分支的历史 commit id。
rebase 需要解决每个 commit 带来的冲突。而 no-ff 只需要解决最终冲突即可。