Git Cherry-Pick 命令完整指南与示例
git cherry-pick 是 Git 中一个强大而灵活的命令,它允许你从一个分支中挑选(”cherry-pick”)一个或多个提交(commits),并将它们应用到另一个分支上。这与合并(git merge)或变基(git rebase)不同,后两者通常会将整个分支的历史记录整合过来。cherry-pick 提供了更细粒度的控制,非常适合以下场景:
- 修复 Bug: 当你在一个开发分支上修复了一个 bug,但这个修复也需要应用到主分支(
main或master)或发布分支时,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 分支:
-
切换到
feature分支:bash
git checkout feature -
执行 cherry-pick:
bash
git cherry-pick d4c0b1aGit 会将
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 commit3.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"
这将把 e5d1a2b 和 f6a2b3c 的更改应用到工作目录和暂存区,但不会自动提交。然后,你可以使用 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 会暂停操作,并在受影响的文件中标记冲突。你需要手动解决这些冲突:
- 查看冲突: 使用
git status查看哪些文件存在冲突。 -
编辑冲突文件: 打开冲突文件,你会看到类似以下的标记:
“`
<<<<<<< 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可能会使分支历史变得混乱。通常,优先考虑merge或rebase,只有在必要时才使用cherry-pick。 - 测试: 在 cherry-pick 之后,务必进行测试,确保没有引入新的问题。
- 先在本地尝试: 在对远程仓库进行cherry-pick前,最好现在本地仓库进行尝试.
5. 总结
git cherry-pick 是一个强大的工具,可以让你精确地控制 Git 历史记录。通过理解其基本语法、常用选项和最佳实践,你可以更有效地使用 Git 进行开发和协作。记住,cherry-pick 应该谨慎使用,只有在真正需要时才使用它。在大多数情况下,merge 或 rebase 是更好的选择。