4.3 KiB
4.3 KiB
id, title, type, domain, stack, tags, level, prerequisites, est_hours, related, week, order
| id | title | type | domain | stack | tags | level | prerequisites | est_hours | related | week | order | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| devops.git.merge-rebase-recovery | 合并、变基和撤销:merge / rebase / cherry-pick、revert / reset、reflog 找回 | lesson | devops |
|
|
intermediate |
|
2 |
|
|
2 |
合并、变基和撤销:merge / rebase / cherry-pick、revert / reset、reflog 找回
解释说明
merge vs rebase
git merge feat:把两个分支的历史合在一起,可能产生一个合并提交;历史真实反映“并行开发”,但图形会交错。--no-ff强制生成合并提交,记录“这里合入了一个功能”;--squash把功能分支压成一个提交。git rebase main:把当前分支的提交“搬到” main 最新提交之后重新应用,历史是一条直线;但会生成新的提交(哈希变了)。- 原则:只 rebase 自己的、还没被别人基于它工作的分支;公共分支(main、已共享的分支)不要 rebase。
git rebase -i:交互式整理提交(合并、改信息、删除、调整顺序),合并请求提交前整理用。
cherry-pick:把某个提交复制到当前分支,常用于把热修复同时带到 release 和 main。
撤销
| 场景 | 命令 | 说明 |
|---|---|---|
| 工作区改乱了 | git restore 文件 |
丢弃未暂存的修改 |
误 add 了 |
git restore --staged 文件 |
取消暂存,修改保留 |
| 最后一次提交信息写错 / 漏文件(未推送) | git commit --amend |
改写最后一个提交 |
| 撤销本地提交(未推送) | git reset --soft HEAD~1(保留改动)/ --hard(丢弃改动) |
改写历史 |
| 撤销已推送的提交 | git revert 提交 |
生成一个反向提交,不改写历史,团队协作的安全做法 |
reflog:记录 HEAD 每次移动的位置(本地,默认保留约 90 天)。reset --hard、删分支、错误的 rebase 之后,都可以在 reflog 里找到原来的提交并恢复。只要提交过,就几乎丢不了。
stash:临时保存未提交的改动,git stash push -m "说明"、git stash pop。
案例
- 合并请求前,用
rebase -i把“WIP”“修正拼写”这类提交合并成两三个有意义的提交,再rebase main解决冲突,评审者看到的历史清晰。 - 上线后发现某个提交引入 bug,main 已经被多人拉取:用
git revert,不要 reset 后强推。 reset --hard后发现删掉了还需要的提交:git reflog找到哈希,git reset --hard 哈希或git branch rescue 哈希恢复。
代码示例
下面这些操作在 examples/git-lab/lab.py 里会在临时仓库中自动执行并验证:
# 功能分支同步最新 main(自己的分支,可以 rebase)
git switch feat/login
git fetch origin
git rebase origin/main # 有冲突:解决后 git add 文件 && git rebase --continue;放弃:git rebase --abort
git push --force-with-lease # 改写过历史的个人分支推送;比 --force 安全:远端有别人的新提交时会拒绝
# 撤销已推送的提交
git revert a1b2c3d
# 误 reset 之后找回
git reflog # 找到 “commit: feat: 重要改动” 那一行的哈希
git reset --hard 0ecd7f4
# 热修复带回 main
git switch main
git cherry-pick 9f8e7d6
易错点
- 对公共分支 rebase 后强推:别人的历史和你的对不上,提交会“重复”或丢失。
- 用
--force而不是--force-with-lease:可能覆盖同事刚推送的提交。 - 已推送的提交用 reset 撤销:其他人再推送时又把它带回来。用 revert。
- revert 一个合并提交:要用
-m 1指定保留哪一边;之后想再合入同一分支,需要先 revert 这个 revert。 - 以为 reflog 能找回从未提交过的改动:没提交(也没 stash)的工作区修改被
reset --hard后是真的没了。 - 解决冲突时直接全选“我的”或“他的”:可能丢掉对方的修改,冲突解决后要运行测试。
面试常问
见 Git 面试题:merge 和 rebase 的区别、revert 和 reset 的区别、误删提交怎么找回。