Git 实战教程:如何使用 Cherry-pick 或直接覆盖让两个分支同步公共功能
在团队协作中,我们经常会遇到这样的情况:
1.某个功能在分支 B 上开发的,但后来在分支 A 上也需要,现在想把 B 的最新修改同步回 A。
2.某个功能原本是在分支 A 上开发的,但后来你在分支 B 上把它完善了,现在想把 B 的最新修改同步回 A。
这篇文章将从 两种常见需求 出发,带你掌握:
✅ 精准迁移指定提交(
git cherry-pick)🔄 完整覆盖某个分支的内容(用
checkout/reset/merge --strategy=ours)
场景说明
假设你现在有两个分支:
A 分支:业务功能还未完成(写了一半的公共模块)
B 分支:基于 A 新建的分支,已经完善了公共功能
目标是把: B 分支中的完整功能代码同步回 A 分支。
✳️ 场景 1:只想迁移某次提交(推荐用 Cherry-pick)
如果你只需要迁移某个功能提交,不想引入 B 分支其他修改,可以使用 cherry-pick。
1️. 查看 B 分支的提交记录
git checkout B
git log --oneline输出示例:
8cd3611 feat: 新增AI对话模块
6606298 fix: 修复配置项显示错误找到你想迁移的那一条(例如 8cd3611)。
2️. 切回 A 分支并执行 cherry-pick
git checkout A
git cherry-pick 8cd361164aaaee470b15b9e6f73f82fe2282c8fcGit 会尝试把该提交应用到当前分支。
如果成功,会直接生成新的 commit。
如果有冲突,会提示你手动解决。
3️. 解决冲突(尤其是图片或资源文件)
假设冲突信息如下:
Unmerged paths:
both added: src/assets/images/icon.png说明两边都新增了相同文件。
保留 A 分支版本:
git checkout --ours src/assets/images/icon.png git add src/assets/images/icon.png使用 B 分支版本:
git checkout --theirs src/assets/images/icon.png git add src/assets/images/icon.png
解决完所有冲突后:
git cherry-pick --continue4️. 不想立即提交推送?让修改停留在工作区
如果 cherry-pick 完后想先修改一下,不想提交成新 commit:
git reset --mixed HEAD~1此时修改会被保留在工作区,你可以继续调整或重新提交。
适用场景总结
| 目标 | 推荐命令 | 说明 |
|---|---|---|
| 从 B 拿一部分功能 | git cherry-pick <commit> | 精准迁移提交 |
| 冲突后保留当前分支版本 | --ours | 保留自己版本 |
| 冲突后使用对方版本 | --theirs | 用 cherry-pick 传入版本 |
| 不想立即提交 | git reset --mixed HEAD~1 | 撤销提交但保留修改 |
✳️ 场景 2:B 分支已完善功能,想直接覆盖 A 分支
如果你在 B 分支中完成了功能,A 分支原来的实现已经废弃, 最简单的做法就是——让 A 分支直接使用 B 的最新内容。
这里有三种安全做法,取决于你是否想保留 A 的提交历史。
方法 1:完全覆盖(推荐干净方式)
# 切换到 A 分支
git checkout A
# 让 A 分支的内容与 B 完全一致
git reset --hard B🔹 这会让 A 的工作区直接变成 B 的版本, 🔹 之前 A 的提交记录仍保留在历史中,但最新状态和 B 一样。
最后推送:
git push -f origin A⚠️ 注意:
-f表示强制推送,请确认团队内没有其他人在此分支工作。
方法 2:用合并策略覆盖(适合保留分支差异)
如果你想让 Git 记录一次“合并”的动作,而不是直接替换:
git checkout A
git merge -s ours B-s ours 策略的意思是:
把 B 的改动标记为已合并,但保持当前分支的内容。
合并后再把 B 的代码内容覆盖进来:
git checkout B -- .
git commit -am "直接同步B分支代码到A"方法 3:通过压缩合并
如果你想把 B 分支整个合并进 A,但不带上 B 的中间提交:
git checkout A
git merge --squash B
git commit -m "同步 B 分支功能至 A"squash 会把所有 B 的提交压缩成一次新的提交。
覆盖方案对比表
| 方式 | 是否保留 A 历史 | 是否保留 B 历史 | 是否需要强推 | 适合场景 |
|---|---|---|---|---|
git reset --hard B | ✅ | ✅ | ✅ | A 完全作废,直接用 B |
git merge -s ours B | ✅ | ❌ | ❌ | 想保留 A 的提交记录 |
git merge --squash B | ✅ | ❌ | ❌ | 想保留提交为一次整合提交 |
常见问题
Q1. 为什么我 git stash 后新文件没有被保存?
git stash 默认只保存已追踪文件的修改。 要让它保存新文件(untracked)也一起存:
git stash -uQ2. 我能查看 cherry-pick 或 reset 前的提交吗?
当然可以:
git log --oneline --graph -n 10HEAD 表示当前提交,HEAD~1 是上一个提交。
总结
| 操作 | 命令 | 说明 |
|---|---|---|
| 精确迁移某个提交 | git cherry-pick <commit> | 最常用方式 |
| 解决冲突取自己版本 | git checkout --ours <file> | 用自己分支的 |
| 解决冲突取对方版本 | git checkout --theirs <file> | 用目标分支的 |
| 撤销最近一次提交 | git reset --mixed HEAD~1 | 保留修改 |
| 完全覆盖为另一分支 | git reset --hard B | 彻底替换 |
| 合并但覆盖内容 | git merge -s ours B | 保留合并历史 |
小结
如果只是想同步某个功能,cherry-pick 是最稳妥;
如果目标分支原有内容已废弃,直接 reset --hard 是最高效;
无论哪种操作,推送前务必
git log+git status核对;最后养成好习惯:每一步前先新建备份分支,例如:
git branch backup-A-before-sync防止误操作无法恢复。