Move the most recent commit(s) to a new branch with Git

Move the most recent commit(s) to a new branch with Git

技术背景

在使用 Git 进行版本控制时,有时会不小心将提交误操作到错误的分支上,或者需要将一些提交从一个分支移动到另一个新的分支。这时就需要掌握如何将最近的提交移动到新的分支的方法。

实现步骤

移动到现有分支

如果你想将提交移动到一个现有分支,可以按以下步骤操作:

1
2
3
4
5
git checkout existingbranch
git merge branchToMoveCommitFrom
git checkout branchToMoveCommitFrom
git reset --hard HEAD~3 # 回退 3 个提交。你会丢失未提交的工作。
git checkout existingbranch

移动到新分支

若要将提交移动到一个新分支,可以使用以下步骤:

1
2
3
4
5
# 注意:任何未提交的更改都将丢失。
git branch newbranch # 创建一个新分支,保存所需的提交
git checkout master # 切换到 master 分支,这是你要回退的地方
git reset --hard HEAD~3 # 将 master 分支回退 3 个提交(确保你知道需要回退多少个提交)
git checkout newbranch # 切换到仍然包含所需提交的新分支

也可以不使用 HEAD~3,而是直接提供你想“回退到”的提交的哈希值(或类似 origin/master 的引用),例如:

1
git reset --hard a1b2c3d4

最后,可能需要强制将最新更改推送到主仓库:

1
git push origin master --force

使用 git cherry-pick 方法

这是一种通用的方法,步骤如下:

步骤 1:记录你想从 master 分支移动到 newbranch 的提交哈希值

1
2
git checkout master
git log

记录(比如 3 个)你想移动到 newbranch 的提交的哈希值。

步骤 2:将这些提交应用到 newbranch

1
2
3
4
git checkout newbranch
git cherry-pick 612ecb3
git cherry-pick 453ac3d
git cherry-pick 9aa1233

或者在 Git 1.7.2+ 版本中,使用范围:

1
2
git checkout newbranch
git cherry-pick 612ecb3~1..9aa1233

使用 git stash 的简单方法

1
2
3
4
git reset HEAD~3
git stash
git checkout newbranch
git stash pop

这种方法适用于以下场景:

  • 主要目的是回滚 master 分支。
  • 想保留文件更改。
  • 不关心错误提交的消息。
  • 尚未推送更改。
  • 希望操作容易记忆。
  • 不想处理临时/新分支、查找和复制提交哈希值等复杂问题。

不重写历史的方法

如果你已经推送了提交,可以使用以下方法:

1
2
3
4
git checkout master
git revert <commitID(s)>
git checkout -b new-branch
git cherry-pick <commitID(s)>

这样两个分支都可以正常推送,无需强制推送。

核心代码

移动单个最新提交到新分支

1
2
3
4
5
git branch newbranch
git checkout newbranch # 提交已经在这个分支
git checkout master
git reset --hard HEAD~1
git push --force

移动多个提交到新分支

1
2
3
4
5
6
7
8
9
git checkout branch_to_remove_commits
git reset --hard ${hash_of_new_tip}
git checkout -b branch_to_store_commits
# 移动提交(单个哈希、哈希列表或范围 ffaa..ffoo)
git cherry-pick ${commit_hash}
git push --set-upstream origin branch_to_store_commits
# 切换回上一个分支
git checkout -
git push -f

最佳实践

  • 在进行操作前,使用 git stash 存储未提交的编辑,操作完成后再使用 git stash pop 恢复。
  • 尽量使用提交哈希值来指定回退的位置,而不是简单地使用 HEAD~n,这样可以避免因误数提交数量而导致的错误。
  • 如果不确定操作的影响,可以先在本地仓库进行测试,或者创建备份分支。

常见问题

使用 git rebase 时丢失提交

如果使用了 git branch -t newbranchgit reset --hard HEAD~3git checkout newbranch 这样的操作,后续使用 git rebase 时可能会丢失之前移动的提交。这是因为 git rebase 默认启用了 --fork-point 选项,会根据本地引用日志来处理。解决方法是使用上述推荐的其他方法,确保引用日志处于正确状态。

推送时提示冲突

如果推送时提示冲突,可能是因为本地分支和远程分支的历史不一致。可以使用 git pull 先合并远程分支的更改,或者使用强制推送 git push -f,但强制推送可能会覆盖远程分支的更改,需要谨慎使用。


Move the most recent commit(s) to a new branch with Git
https://119291.xyz/posts/2025-05-07.move-the-most-recent-commits-to-a-new-branch-with-git/
作者
ww
发布于
2025年5月7日
许可协议