跳到主要内容

同步Git分支变更的多种姿势

提示

当你在 feat/123 上开发,而队友已经把 feat/456 合并到了 dev,此时最重要的是:先把 dev 的最新变更同步到你的分支,再继续开发或提交。这样可以避免后面再合并时出现一长串难解的冲突。

为什么要在合并前同步 dev

  • 减少冲突:越早同步,差异越小,冲突也越容易处理。
  • 保持上下文:能及时看到团队刚合入 dev 的内容,避免重复劳动。
  • 让提交历史清晰:同步后再提交,记录会直接跟在最新的 dev 之后。

Rebase 系列方法

git pull --rebase(推荐做法)

# 1. 先把当前的开发内容提交或暂存
git status

# 2. 拉取 dev 最新变更,并把自己的提交"摘"下来重新放到 dev 之后
git pull origin dev --rebase

# 3. 如果出现冲突,解决后继续
git add <解决冲突的文件>
git rebase --continue

优势:历史保持线性、减少无关提交、在 git log 中更易审计。

git rebase

git fetch origin dev
git rebase origin/dev
# 或者交互式整理
git rebase -i origin/dev
  • 直接把当前分支的提交"移动"到最新 dev 之后,可顺便调整提交顺序、合并冗余提交;
  • 会重写提交哈希,适用于未共享或可强制推送的分支;
  • 结合 -i 可精细控制提交粒度。

处理未提交的修改:git stash

在执行 git rebasegit pull --rebase 时,如果工作区有未提交的修改,Git 会提示:

error: cannot rebase: You have unstaged changes.
error: Please commit or stash them.

如果不想提交这些修改,可以使用 git stash 暂存:

# 1. 暂存当前未提交的修改
git stash

# 2. 执行 rebase
git rebase origin/dev

# 3. rebase 完成后,恢复之前暂存的修改
git stash pop

git stash 常用操作

# 查看所有暂存的修改
git stash list

# 暂存时添加描述信息
git stash push -m "描述信息"

# 只暂存已暂存的文件(不包括未暂存的文件)
git stash push --staged

# 恢复最近的暂存(保留暂存记录)
git stash apply

# 恢复最近的暂存(删除暂存记录)
git stash pop

# 恢复指定的暂存(stash@{0} 是最近的)
git stash apply stash@{0}

# 删除暂存记录(不恢复)
git stash drop stash@{0}

# 清空所有暂存记录
git stash clear

为什么需要暂存

git rebase 会重写提交历史,需要干净的工作区:

  • 避免未保存的修改在 rebase 过程中丢失
  • 确保冲突解决时状态清晰
  • 保证 rebase 操作的可逆性

注意事项

  1. 冲突处理git stash pop 可能产生冲突,如果恢复的修改与 rebase 后的代码冲突,需要手动解决。
  2. 暂存范围:默认暂存所有修改(包括已暂存和未暂存),使用 --staged 可只暂存已暂存的文件。
  3. 未跟踪文件:默认不暂存未跟踪的文件(新文件),需要时使用 git stash push -u

Merge 系列方法

git merge(备选方案)

git fetch origin dev
git merge origin/dev

不重写历史,适合希望完整保留拓扑结构的团队。但会额外生成 merge commit,git log 中会看到 dev 的全部历史。

为什么会看到很多历史提交但改动很少

执行 git merge origin/dev 时,Git 会把 dev 的全部提交记录纳入当前分支的历史,哪怕这些提交与当前文件无关。git log 因此显得"很长",但 git diff 只显示真正的文件差异,属于日志层面的噪音。

git merge --squash

git fetch origin dev
git merge --squash origin/dev
git commit -m "sync dev changes"
  • 以单个提交带入 dev 的全部改动,保持分支历史紧凑;
  • 不生成 merge commit,也不会记录 dev 的提交拓扑;
  • 执行完必须手动 git commit 才会真正落盘。

git merge --ff-only

git fetch origin dev
git merge --ff-only origin/dev
  • 只允许 fast-forward,确保历史绝对线性;
  • 若存在本地独立提交会被拒绝,需要先 rebase;
  • 适合发布分支或对历史有严格要求的场景。

其他方法

git cherry-pick

# 只需要 dev 上的某个具体提交
git fetch origin dev
git cherry-pick <commit-hash>
  • 精确提取指定提交,适合紧急修复或仅需部分改动;
  • 会在当前分支生成新的提交(哈希不同于原提交);
  • 建议在 commit message 里标注来源,方便追溯。

git reset --hard

git fetch origin dev
git reset --hard origin/dev
  • 直接把当前分支重置为远端 dev,丢弃本地所有提交与修改;
  • 适用于纯同步分支或临时分支;
  • 执行前需确认没有需要保留的本地改动(可先 git stash)。

如何选择

场景推荐命令原因/特点
保持线性历史并完整同步 devgit pull --rebase origin dev无额外提交,记录紧凑,便于审计
保留真实拓扑结构git merge origin/dev完整保留 dev 的历史结构
需要单个同步提交git merge --squash origin/dev用一个汇总提交代替大量历史提交
只需要部分提交git cherry-pick <hash>精确引入特定提交
需要整理提交/调整顺序git rebase origin/dev支持交互式编辑、合并或改写提交
强制要求 fast-forwardgit merge --ff-only origin/dev没有 merge commit,历史严格线性
本地分支可直接重置为远端状态git reset --hard origin/dev丢弃本地修改,最快速地与远端保持一致(需谨慎使用)