Git cherry-pick命令的适用场景与实例


搞懂 git cherry-pick,这篇就够了!

哈喽,大家好!今天我们来聊聊 Git 里面一个非常实用的命令——git cherry-pick

你可能会有疑问,已经有了 mergerebase,为什么还需要 cherry-pick 呢?别急,听我慢慢道来。

cherry-pick 是什么?

cherry-pick,顾名思义,就是“摘樱桃”。在 Git 的世界里,我们可以把它理解为“挑选提交”。它的作用就是将一个或多个指定的提交(commit)从一个分支“复制”到当前所在的分支。

这里要注意,说是“复制”,其实 Git 会在当前分支上创建一个新的提交,这个新提交包含了被“摘”过来的提交的所有代码变更。虽然提交信息、作者等元数据可以保持一致,但它们的哈希值(commit ID)是不同的。

什么时候适合用 cherry-pick

设想一下,你是不是也遇到过下面这些场景:

  • 紧急修复线上 Bug:线上版本出了个紧急 Bug,你在 hotfix 分支上修复了它,并经过了测试。现在,你不仅需要将这个修复合并到 master 主干,也需要同步到正在开发的 develop 分支,以避免下一个版本再次出现同样的问题。这时候,cherry-pick 就能大显身手,让你精确地只把修复 Bug 的那个提交应用到 develop 分支,而不会带上 hotfix 分支上其他的提交。
  • “移植”某个功能:假设你在一个功能分支 feature-A 上开发了几个功能,后来发现其中某个提交实现的功能,对于另一个功能分支 feature-B 来说也同样需要。你总不想再写一遍同样的代码吧?通过 cherry-pick,你可以轻松地将那个特定的功能提交“移植”到 feature-B 分支。
  • 从废弃的分支中“抢救”代码:有时候,一个功能分支可能因为需求变更等原因被废弃了,但其中有那么一两个提交还是有用的。cherry-pick 就像一个“代码救援队”,可以帮你把这些有价值的提交从即将被删除的分支里拯救出来。
  • 提交错了分支:这绝对是手滑党们的痛。本来应该在 develop 分支提交的代码,一不小心提交到了 master。别慌,先切换回 develop 分支,然后用 cherry-pick 把那个提交“摘”回来,再把 master 分支上的错误提交 reset 掉,完美解决!

总而言之,当你需要将一个分支的部分代码变更应用到另一个分支时,cherry-pick 就是你的不二之选。

实战演练:cherry-pick 怎么用?

光说不练假把式,我们来看几个实例。

假设我们现在的分支情况是这样的:

a - b - c - d   (master)
     \
       e - f - g   (feature)

现在我们想把 feature 分支上的 f 这个提交应用到 master 分支。

1. 摘取单个提交

首先,切换到你的目标分支,也就是 master 分支:

git checkout master

然后,执行 cherry-pick 命令,后面跟上你要摘取的提交的哈希值:

git cherry-pick f

(这里的 ‘f’ 是 commit ‘f’ 的哈希值简写)

执行成功后,master 分支的提交历史会变成这样:

a - b - c - d - f'  (master)
     \
       e - f - g   (feature)

注意,f' 是一个新的提交,但它引入的变更和 f 完全一样。

2. 摘取多个提交

如果你想一次性摘取多个提交,比如 fg,只需要把它们的哈希值依次列在后面,用空格隔开即可:

# 切换到 master 分支
git checkout master

# 摘取多个提交,建议按照提交的时间顺序
git cherry-pick f g

3. 摘取一个区间的提交

有时候你想摘取一个连续的提交区间。比如,我们想把 feature 分支上从 eg 的所有提交都应用到 master 上。

  • 不包含起始提交commit1..commit3 表示从 commit1 之后到 commit3 的所有提交。
        git cherry-pick e..g
        ```    这会把 `f``g` 两个提交应用到当前分支。
    
    *   **包含起始提交**:如果你也想要 `e` 这个提交,可以使用 `^` 符号。
        ```bash
        git cherry-pick e^..g
    这就会把 e, f, g 三个提交都应用过来。

可能会遇到的问题

冲突解决

cherry-pick 并非总是顺风顺水。如果在应用提交的过程中,Git 发现代码有冲突,它会停下来,等待你手动解决。

这个过程和解决 merge 冲突非常相似:

  1. 手动修改冲突文件,完成后 git add <文件名>
  2. 执行 git cherry-pick --continue,让 Git 继续应用剩余的提交。
  3. 如果你中途想放弃,可以执行 git cherry-pick --abort,分支会恢复到 cherry-pick 之前的状态。

常用选项

cherry-pick 还有一些有用的选项,可以帮助你更好地控制整个过程:

  • --no-commit-n:只将代码变更应用到工作区和暂存区,但不会自动生成新的提交。这给了你在提交前再次检查和修改代码的机会。
  • --edit-e:在提交前,会打开编辑器让你重新编辑提交信息。
  • -x:在生成的提交信息的末尾,会自动加上一行 (cherry picked from commit ...),方便追溯这个提交的来源。

cherry-pick 的优缺点

优点:

  • 精确灵活:可以精确地选择需要的提交,而不是整个分支。
  • 保持历史整洁:相比于为了一个小小改动而去 merge 整个分支,cherry-pick 可以让你的提交历史更加清晰。

缺点:

  • 可能产生重复提交:如果在 cherry-pick 之后,你又将整个分支 merge 到当前分支,可能会出现内容相同的重复提交。
  • 丢失上下文:只复制代码变更,可能会丢失原始提交的上下文信息,给代码审查带来一定困难。

总结

git cherry-pick 是一个强大的工具,它赋予了我们“挑选”提交的能力,极大地提高了我们处理特定场景的灵活性。尤其是在处理紧急 Bug 修复和跨分支同步少量代码变更时,它的优势尤为明显。

不过,请记住,它并不是 mergerebase 的替代品,而是一种补充。理解它的适用场景,并谨慎使用,才能真正发挥它的威力,让你的版本控制工作流更加高效和清晰!


  目录