技术

Git Merge 无头远程分支小技巧

Git Merge 无头远程分支操作示意图

Git Merge 无头远程分支小技巧

旧项目需要整体升级,因此从旧项目中切出了一个独立仓库。由于没有使用 Fork,现在需要把旧项目后续更新的功能合并到新项目中。

由于提交数量很多,一个个执行 cherry-pick 非常麻烦;直接使用 mergerebase,又会从第一次提交开始产生冲突。

可以使用 grafts / replace 将旧提交映射到新的基准提交,从而解决这个问题。

简单来说,就是把旧项目中“切出新项目”的那个提交 SHA,设置为新项目某个提交的父提交。 在本文示例中,将指定的旧项目提交设置为新项目根提交的父提交,之后就可以直接 Merge 旧项目分支,从而合并指定提交节点到最新提交节点之间的所有变更。

相比逐个执行 cherry-pick,这种方式可以避免同一份文件经过多次修改时, 反复处理合并冲突。

同时,旧项目提交历史中已经完成的 Merge 冲突处理结果,也可以直接继承过来。 如果使用 cherry-pick,这些冲突往往需要重新解决一次,操作复杂且容易出错。

操作模板

git fetch upstream
TARGET=$(git rev-parse upstream/master)
# 假设 my-work 的根提交是 ROOT
ROOT=$(git rev-list --max-parents=0 HEAD)
# 创建 replace
# 推荐使用该方式,因为 grafts 已被废弃
git replace --graft $ROOT $TARGET
git log --oneline --graph --decorate
# 此时可以看到 my-work 的根提交下面出现了 upstream 的提交

持久化 Replace 对象

git replace 默认只保存在本地仓库的 .git/refs/replace/ 目录中。

如果希望其他人克隆仓库后仍然能够使用该 Replace 映射,可以尝试将 Replace 引用推送到远程仓库:

git push origin refs/replace/*

需要注意,远程 Git 服务器必须支持存储和获取 refs/replace/* 引用。

我的操作记录

  1. 在 IDEA 的 Git 提交记录中,找到旧项目的指定提交。
  2. 右键选择 Copy Revision Number,获取 TARGET
  3. 在新项目中找到 Root 提交,使用相同方式获取 ROOT
  4. 执行 git replace --graft 命令。
git replace --graft \
31e8b54b6498404e5383a91c86db233172ebcd37 \
019aece182cdffd15012263ea9671e13447eace6

执行完成后,就可以直接 Merge 旧项目分支。

相关延伸

1. 一个本地项目可以添加多个远程仓库

git remote add store1 http://xxx

2. 本地分支可以合并任意远程仓库的分支

首先获取远程仓库的最新分支信息:

git fetch store1

然后将对应远程分支合并到当前本地分支:

git merge store1/master

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注