云计算百科
云计算领域专业知识百科平台

Git 如何一次 cherry-pick 多个提交?多个 commit 批量合并完整教程

Git 如何一次 cherry-pick 多个提交?多个 commit 批量合并完整教程

在实际开发中,我们经常会遇到这种情况:

某个分支上有好几个已经提交完成的改动,但我并不想把整个分支 merge 过来,只想把其中几个 commit 合并到当前分支,该怎么做?

这时候就可以继续使用 git cherry-pick。

上一篇我们讲的是把某一个 commit 合并到当前分支,而这篇专门解决另一个很常见的问题:

如何一次 cherry-pick 多个提交。

这篇会把最常见的几种情况全部讲清楚:

  • 一次 cherry-pick 多个不连续的 commit
  • 一次 cherry-pick 一段连续的 commit
  • A..D 和 A^..D 到底有什么区别
  • 多个提交发生冲突怎么办
  • 如何中止整个 cherry-pick
  • 如何只应用改动,最后合成一个提交
  • 多个 commit 的顺序应该怎么写
  • 实际开发中应该选择哪一种方式

一、先回顾一下 cherry-pick 是什么

git cherry-pick 的作用可以简单理解成:

从其他位置选中一个或多个已经存在的提交,把这些提交产生的代码改动重新应用到当前分支。

例如现在有两个分支:

feature: A — B — C — D

main: M1 — M2

如果我们只想把 feature 分支中的 B 和 D 放到 main,不想把整个 feature 合并进来,就可以使用 cherry-pick。

这也是它和 git merge 最大的区别之一。

merge 更偏向于合并分支历史,而 cherry-pick 更偏向于精准挑选指定提交。


二、操作前先确认当前分支

这是使用 cherry-pick 时最重要的一步。

因为:

cherry-pick 会把指定提交应用到你当前所在的分支。

假设我们准备把几个提交合并到 main,应该先切换到 main:

git switch main

如果项目里使用的是旧版 Git,也可以使用:

git checkout main

查看当前分支:

git branch

然后确认工作区状态:

git status

正式执行前,最好保证工作区是干净的,不要留着尚未提交的修改。


三、先找到需要 cherry-pick 的 commit

如果不知道提交哈希,可以先查看提交历史:

git log –oneline

例如看到:

8f2a931 fix: 修复订单金额计算问题
51bd822 feat: 增加优惠券校验
9c78a11 refactor: 优化订单查询
3ae24fd feat: 增加订单导出功能

假设现在只需要:

  • 8f2a931
  • 51bd822
  • 3ae24fd

这三个提交。

接下来有几种不同的写法。


四、方法一:一次写多个 commit hash

这是最直观、最好理解,也是我最推荐初学者使用的方法。

语法:

git cherry-pick commit1 commit2 commit3

例如:

git cherry-pick 8f2a931 51bd822 3ae24fd

Git 会依次把这些提交的改动应用到当前分支,并通常为每个提交创建一个新的提交。

在这里插入图片描述

这种方式什么时候最适合?

当你需要的提交不是连续的时,这种写法最合适。

例如原分支历史是:

A — B — C — D — E

你只想要:

B、D、E

那就直接写:

git cherry-pick B D E

这样非常直观,也不容易误选其他提交。


五、多个 commit 的顺序重要吗?

重要。

尤其是多个提交之间存在代码依赖的时候。

例如:

A:创建 UserService
B:给 UserService 增加方法
C:调用 B 中增加的方法

如果你先 cherry-pick C,但当前分支还没有 A 和 B,就很可能出现冲突,甚至代码无法编译。

因此,如果几个提交之间存在前后依赖,通常应该按照原来的提交顺序执行。

例如:

git cherry-pick A B C

而不是:

git cherry-pick C B A

所以在操作之前,可以先用下面的命令确认历史顺序:

git log –oneline –reverse


六、方法二:cherry-pick 一段连续提交

如果需要的提交刚好是一整段连续的历史,就没有必要把每个 commit hash 都手动写出来。

例如:

P — A — B — C — D

假设我们希望把 B、C、D 全部 cherry-pick 到当前分支。

可以使用:

git cherry-pick "A..D"

这里最容易理解错的一点是:

A..D 不包含 A。

在简单线性历史中,它表示从 D 可到达、但从 A 不可到达的这一组提交,因此这里得到的是:

B、C、D


七、如果我想连 A 一起 cherry-pick 呢?

还是这个历史:

P — A — B — C — D

如果你希望一次把:

A、B、C、D

全部带过去,可以写:

git cherry-pick "A^..D"

这里的 A^ 表示 A 的父提交。

因此整个范围就会从 A 开始,一直到 D。

在这里插入图片描述

可以直接这样记:

写法简单线性历史中包含的提交
A..D B、C、D
A^..D A、B、C、D

这也是批量 cherry-pick 时最容易写错的地方之一。


八、为什么我更推荐初学者直接写多个 commit hash?

虽然范围写法很方便,但是当 Git 历史比较复杂、存在分叉或 merge commit 时,revision range 的实际提交集合可能没有你想象中那么直观。

如果只有两三个或者四五个提交,我更建议直接明确写出来:

git cherry-pick A B C D

优点非常明显:

  • 一眼就能知道准备应用哪些提交;
  • 不容易搞错范围边界;
  • 可以明确控制提交顺序;
  • 代码 review 时也更容易确认操作内容。
  • 连续提交非常多时,再考虑使用范围写法会更加方便。


    九、执行多个 cherry-pick 后会发生什么?

    例如执行:

    git cherry-pick A B C

    假设三个提交都成功应用。

    原来当前分支是:

    M1 — M2

    执行之后可能变成:

    M1 — M2 — A' — B' — C'

    需要注意:

    虽然 A' 和原来的 A 代码改动可能相同,但它们并不是同一个 Git commit。

    因为 cherry-pick 是在当前分支上重新创建提交,所以一般会产生新的 commit hash。


    十、多个提交 cherry-pick 到一半冲突了怎么办?

    假设执行:

    git cherry-pick A B C D

    A、B 成功了,但是执行到 C 时发生冲突。

    Git 会停下来,不会直接继续执行 D。

    这时候先查看状态:

    git status

    打开冲突文件,可以看到类似:

    <<<<<<< HEAD
    当前分支中的代码
    =======
    正在 cherry-pick 的提交中的代码
    >>>>>>> C

    根据实际需求修改代码并删除冲突标记。

    然后将解决后的文件加入暂存区:

    git add .

    继续执行:

    git cherry-pick –continue

    Git 完成 C 后,会继续处理后面的提交。

    在这里插入图片描述

    整个流程可以记成:

    cherry-pick 多个提交

    发生冲突

    修改冲突文件

    git add .

    git cherry-pick –continue

    继续处理剩余提交


    十一、不想继续了怎么办?

    如果发现冲突太多,或者自己 cherry-pick 错了,可以放弃当前这次 cherry-pick 序列:

    git cherry-pick –abort

    它会尝试把状态恢复到开始这次 cherry-pick 之前。

    这是处理批量 cherry-pick 时非常重要的一条命令。


    十二、某一个提交不想要了,可以跳过吗?

    如果执行过程中停在某个提交,而你确认这个提交不需要继续应用,可以使用:

    git cherry-pick –skip

    Git 会跳过当前这个提交,然后继续处理后面的提交。

    不过不要为了“快速消除冲突”就随便 –skip。

    如果后面的提交依赖当前提交,跳过之后可能继续出现问题。


    十三、多个提交能不能最后合成一个 commit?

    可以。

    默认情况下:

    git cherry-pick A B C

    通常会生成三个对应的新提交。

    如果你希望只应用这些提交的改动,而暂时不自动 commit,可以使用 -n 或 –no-commit:

    git cherry-pick -n A B C

    也可以写:

    git cherry-pick –no-commit A B C

    执行完成后,这些改动会留在工作区和暂存区中。

    然后你可以自己统一提交一次:

    git commit -m "feat: 合并订单相关功能"

    最终原本多个 commit 的改动,就可以整理成当前分支上的一个新 commit。


    十四、什么时候适合使用 –no-commit?

    例如原分支上有三个非常小的提交:

    A:修改按钮文字
    B:调整按钮间距
    C:修改按钮颜色

    如果目标分支并不需要保留三个独立提交,可以使用:

    git cherry-pick -n A B C

    检查代码:

    git diff –cached

    最后统一提交:

    git commit -m "style: 优化按钮样式"

    这样提交历史会更加简洁。

    但如果三个 commit 本身代表三个独立功能,就不建议为了“好看”强行压成一个提交。


    十五、实际开发案例

    假设团队现在有:

    develop
    release

    develop 中最近有这些提交:

    71a2d11 feat: 新增会员首页
    82bc933 fix: 修复支付金额计算
    93de122 refactor: 重构商品列表
    ac4f650 fix: 修复订单重复提交
    bd5a761 feat: 新增活动页面

    现在 release 分支准备发布,但是只需要把两个 bug 修复带进去:

    82bc933
    ac4f650

    先切换到目标分支:

    git switch release

    更新目标分支:

    git pull

    确认状态:

    git status

    然后一次 cherry-pick 两个修复提交:

    git cherry-pick 82bc933 ac4f650

    检查提交历史:

    git log –oneline -10

    测试没有问题之后推送:

    git push origin release

    这个场景就是 cherry-pick 非常典型的用途:

    不合并整个开发分支,只把确定需要发布的几个修复精准带到 release 分支。


    十六、常见错误 1:忘记切换到目标分支

    很多人查完 commit hash 后马上执行:

    git cherry-pick A B C

    结果发现提交被加到了错误分支。

    所以建议养成一个固定习惯:

    git branch –show-current

    确认当前分支正确以后,再执行 cherry-pick。


    十七、常见错误 2:把 A…D 理解成包含 A

    这是最常见的范围误区。

    简单线性历史:

    P — A — B — C — D

    执行:

    git cherry-pick "A..D"

    不是 A、B、C、D。

    而是:

    B、C、D

    如果 B 的代码依赖 A,而当前分支又没有 A,那么从 B 开始 cherry-pick 甚至可能直接冲突。

    要包含 A,可以使用:

    git cherry-pick "A^..D"


    十八、常见错误 3:多个提交存在依赖却乱写顺序

    如果:

    A:创建类
    B:调用 A 创建的类
    C:继续修改 B

    最好按照:

    git cherry-pick A B C

    执行。

    不要随便改成:

    git cherry-pick C A B

    否则可能会让原本可以正常应用的提交变成冲突。


    十九、常见错误 4:工作区还有修改就开始操作

    开始前建议执行:

    git status

    如果存在未提交修改,可以根据实际情况先提交:

    git add .
    git commit -m "chore: 保存当前修改"

    或者临时保存:

    git stash

    然后再执行 cherry-pick。


    二十、多个 cherry-pick 和 merge 怎么选?

    可以简单按下面的思路判断:

    需求更适合的方式
    整个功能分支都需要 git merge
    只需要其中一个提交 git cherry-pick
    只需要几个指定提交 git cherry-pick
    一整段连续提交需要搬过去 git cherry-pick + revision range
    需要保留完整分支合并关系 git merge
    修复需要回补到旧版本分支 git cherry-pick

    如果你发现自己准备 cherry-pick 一个分支里几乎所有提交,那就应该重新考虑是不是直接 merge 更合适。


    二十一、最常用命令汇总

    查看提交历史:

    git log –oneline

    查看当前分支:

    git branch –show-current

    一次 cherry-pick 多个指定提交:

    git cherry-pick A B C

    cherry-pick A 之后到 D 的提交,不包含 A:

    git cherry-pick "A..D"

    cherry-pick A 到 D,包含 A:

    git cherry-pick "A^..D"

    只应用多个提交的改动,不立即提交:

    git cherry-pick -n A B C

    冲突解决后继续:

    git add .
    git cherry-pick –continue

    跳过当前提交:

    git cherry-pick –skip

    放弃整个 cherry-pick:

    git cherry-pick –abort


    二十二、最后总结

    一次 cherry-pick 多个提交其实并不复杂,最常用的就是下面三种写法。

    多个不连续提交

    git cherry-pick A B C

    连续提交,不包含起点 A

    git cherry-pick "A..D"

    连续提交,包含 A

    git cherry-pick "A^..D"

    如果只记住一句话:

    提交少、位置不连续时,直接把 commit hash 一个一个写出来;连续提交很多时,再使用 revision range。

    同时一定要注意三件事:

  • 先确认当前分支是否正确;
  • 注意多个提交之间的依赖和顺序;
  • 发生冲突后使用 –continue,想全部放弃时使用 –abort。
  • 掌握这些以后,无论是把多个 bug 修复同步到发布分支,还是把一段功能提交迁移到其他分支,都可以比较安全地完成。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Git 如何一次 cherry-pick 多个提交?多个 commit 批量合并完整教程
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!