Git:Cherry-Pick命令的完整指南和示例 – wiki基地

Git Cherry-Pick 命令完整指南与示例

git cherry-pick 是 Git 中一个强大而灵活的命令,它允许你从一个分支中挑选(”cherry-pick”)一个或多个提交(commits),并将它们应用到另一个分支上。这与合并(git merge)或变基(git rebase)不同,后两者通常会将整个分支的历史记录整合过来。cherry-pick 提供了更细粒度的控制,非常适合以下场景:

  • 修复 Bug: 当你在一个开发分支上修复了一个 bug,但这个修复也需要应用到主分支(mainmaster)或发布分支时,cherry-pick 可以直接将修复的提交复制过去,而无需合并整个开发分支。
  • 提取特性: 如果你在一个实验性分支上开发了多个新特性,但只想将其中一个或几个特性应用到另一个分支,cherry-pick 可以精确地选择这些特性提交。
  • 代码共享: 当你在多个分支上工作,并且需要在这些分支之间共享特定的代码更改时,cherry-pick 可以避免重复工作。
  • 回滚错误提交: 虽然不推荐,但 cherry-pick 也可以用来“反向”应用一个提交,从而达到撤销某个更改的效果(后面会详细解释)。

1. 基本语法

git cherry-pick 的基本语法非常简单:

bash
git cherry-pick <commit-hash>

其中 <commit-hash> 是你要挑选的提交的 SHA-1 哈希值。你可以使用 git log 命令来查看提交历史并找到相应的哈希值。

更常用的形式:

bash
git cherry-pick <options> <commit-hash>...

可以一次挑选多个提交,用空格隔开。

2. 常用选项

git cherry-pick 提供了许多选项来控制其行为,以下是一些最常用的选项:

  • -e--edit (默认): 允许你在应用提交之前编辑提交信息。Git 会打开你的默认文本编辑器,让你修改提交信息。这对于修改提交描述、添加说明或更正错误非常有用。

  • -n--no-commit: 执行 cherry-pick 操作,但 自动创建新的提交。这允许你将更改应用到工作目录和暂存区,然后你可以根据需要进行修改、添加其他文件,最后再手动创建一个提交。这在你想将多个提交合并成一个提交时非常有用。

  • -x: 在提交信息中自动添加一行,注明该提交是从哪个提交 cherry-pick 过来的。这有助于跟踪提交的来源,特别是在团队协作中。提交信息会类似于:”This commit was cherry-picked from commit “。

  • -s--signoff: 使用你的 Git 配置中的用户名和邮箱地址在提交信息末尾添加签名。这表明你是将这个提交应用到当前分支的人。

  • -m parent-number--mainline parent-number: 当 cherry-pick 的提交是一个合并提交(merge commit)时,Git 不知道应该选择合并的哪一个父提交作为主线。-m 选项指定了父提交的编号(从 1 开始),Git 将使用该父提交作为主线来进行 cherry-pick。通常,合并提交的第一个父提交是合并时所在的分支,第二个父提交是要合并进来的分支。

  • --abort: 取消当前的 cherry-pick 操作。如果在 cherry-pick 过程中发生冲突,并且你不想继续解决冲突,可以使用 --abort 来放弃整个操作,回到 cherry-pick 之前的状态。

  • --continue: 在解决完 cherry-pick 引起的冲突后,使用 --continue 来继续 cherry-pick 操作。Git 会将解决后的更改添加到暂存区,并继续应用提交。

  • --quit: 退出当前的 cherry-pick 序列。与 --abort 不同,--quit 不会回滚已经成功 cherry-pick 的提交。

3. 详细示例

3.1. 挑选单个提交

假设你有以下提交历史:

* f6a2b3c (HEAD -> feature) Add feature C
* e5d1a2b Add feature B
* d4c0b1a (main) Fix bug X
* c3b2a10 Add feature A
* b2a1c09 Initial commit

你想将 main 分支上的提交 d4c0b1a(修复了 bug X)应用到 feature 分支:

  1. 切换到 feature 分支:

    bash
    git checkout feature

  2. 执行 cherry-pick:

    bash
    git cherry-pick d4c0b1a

    Git 会将 d4c0b1a 的更改应用到 feature 分支,并自动创建一个新的提交。提交信息默认与原始提交相同,但你可以使用 -e 选项来编辑它。

    现在的提交历史会变成:

    * g7h3i4j (HEAD -> feature) Fix bug X (cherry-picked from d4c0b1a)
    * f6a2b3c Add feature C
    * e5d1a2b Add feature B
    * d4c0b1a (main) Fix bug X
    * c3b2a10 Add feature A
    * b2a1c09 Initial commit

    3.2. 挑选多个提交

你可以一次挑选多个提交,只需将它们的哈希值用空格隔开:

bash
git cherry-pick c3b2a10 d4c0b1a

Git 会按照你指定的顺序依次应用这些提交。

3.3. 使用 --no-commit

如果你想将多个提交合并成一个提交,可以使用 -n--no-commit 选项:

bash
git cherry-pick -n e5d1a2b
git cherry-pick -n f6a2b3c
git commit -m "Add features B and C"

这将把 e5d1a2bf6a2b3c 的更改应用到工作目录和暂存区,但不会自动提交。然后,你可以使用 git commit 手动创建一个包含所有更改的提交。

3.4. 处理合并提交

假设你有以下提交历史,其中 d4c0b1a 是一个合并提交:

* d4c0b1a (main) Merge branch 'bugfix'
|\
| * c3b2a10 Fix bug Y
|/
* b2a1c09 Initial commit

如果你直接执行 git cherry-pick d4c0b1a,Git 会提示你选择一个父提交:

error: commit d4c0b1a is a merge but no -m option was given.
fatal: cherry-pick failed

你需要使用 -m 选项来指定主线。通常,如果你想合并的是bugfix分支的修改,你会选择第二个父提交(-m 2):

bash
git cherry-pick -m 2 d4c0b1a

如果想合并main分支在bugfix分支合并进来的修改,则选择第一个父提交(-m 1

3.5. 解决冲突

如果在 cherry-pick 过程中发生冲突,Git 会暂停操作,并在受影响的文件中标记冲突。你需要手动解决这些冲突:

  1. 查看冲突: 使用 git status 查看哪些文件存在冲突。
  2. 编辑冲突文件: 打开冲突文件,你会看到类似以下的标记:

    “`
    <<<<<<< HEAD
    This is the change in the current branch.
    =======
    This is the change from the cherry-picked commit.

    d4c0b1a
    “`

    你需要手动编辑这些文件,删除冲突标记,并选择保留哪些更改或进行合并。
    3. 暂存解决后的文件: 使用 git add <file> 将解决后的文件添加到暂存区。
    4. 继续 cherry-pick: 使用 git cherry-pick --continue 继续 cherry-pick 操作。Git 会创建一个新的提交,包含解决后的更改。

如果你想放弃 cherry-pick,可以使用 git cherry-pick --abort

3.6 使用Cherry-Pick进行代码回滚(“反向”应用提交)

虽然cherry-pick主要用于将提交从一个分支应用到另一个分支,但它也可以用来“反向”应用一个提交,从而达到撤销某个更改的效果。这通常不是推荐的做法,因为更好的方法是使用git revert,但理解这个技巧有时会有帮助。

假设你想撤销提交c3b2a10

bash
git cherry-pick -n c3b2a10

这里使用了-n选项,因为我们不想立即创建一个新的提交。现在,工作目录中的更改将是c3b2a10反向更改。

接下来,你需要手动检查这些更改是否正确。如果一切正常,你可以创建一个新的提交来“撤销”c3b2a10

bash
git commit -m "Revert commit c3b2a10"

重要提示: 这种方法与git revert不同。git revert会创建一个新的提交,该提交的内容是撤销目标提交的更改。而使用cherry-pick进行“反向”应用,实际上是将目标提交的更改“反向”应用到当前分支,然后创建一个新的提交。这两种方法都可以达到撤销更改的效果,但git revert通常是更好的选择,因为它更清晰、更安全,并且不会改变历史记录(cherry-pick会创建一个新的提交哈希)。

4. 最佳实践

  • 保持提交的原子性: 每个提交应该只包含一个逻辑更改。这使得 cherry-pick 更加容易,也更容易理解和调试。
  • 清晰的提交信息: 编写清晰、有意义的提交信息。这有助于其他开发人员(包括未来的你)理解提交的目的和内容。
  • 谨慎使用: cherry-pick 会复制提交,这可能会导致重复的提交历史。在团队协作中,过度使用 cherry-pick 可能会使分支历史变得混乱。通常,优先考虑 mergerebase,只有在必要时才使用 cherry-pick
  • 测试: 在 cherry-pick 之后,务必进行测试,确保没有引入新的问题。
  • 先在本地尝试: 在对远程仓库进行cherry-pick前,最好现在本地仓库进行尝试.

5. 总结

git cherry-pick 是一个强大的工具,可以让你精确地控制 Git 历史记录。通过理解其基本语法、常用选项和最佳实践,你可以更有效地使用 Git 进行开发和协作。记住,cherry-pick 应该谨慎使用,只有在真正需要时才使用它。在大多数情况下,mergerebase 是更好的选择。

发表评论

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

滚动至顶部