好慌,我代码没了!不会是变基变出问题了吧?
大家好,我是 Kagol,Vue DevUI 开源组件库和 EditorX 富文本编辑器创建者,专注于前端组件库建设和开源社区运营。
前两天检视代码时,发现PR里面有两个提交的描述信息一模一样,于是我提出应该将这两个提交合并成一个,保持提交树的清晰。
先储存起来!
而同事这时正在开发别的特性,工作区不是干净的,没法直接执行 git rebase 操作,于是很自然地执行
git stash
将正在修改的内容保存到一个栈中,并维持当前工作区干净。
这样就可以执行切换分支、变基等操作,这些操作能执行的前提是当前工作区是干净的。
使用 git rebase 合并两个提交
我们先执行 git log 命令,找到要合并的两个提交之前的那个提交:cdedd430
commit ec0218ff
feat: 增加国际化
commit 89f3d02c
feat: 增加国际化
commit cdedd430
refactor: pnpm工程改造
然后执行 git rebase 变基命令:
git rebase -i cdedd430
这时会进入一个交互式命令行界面:
pick 89f3d02 feat: 增加国际化
pick ec0218f feat: 增加国际化
# Rebase cdedd43..ec0218f onto cdedd43 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# . create a merge commit using the original merge commit's
# . message (or the oneline, if no original merge commit was
# . specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
"~/my-project/.git/rebase-merge/git-rebase-todo" 28L, 1232B
这时你可以移动光标,但是无法输入字符,因为这是个只读的界面,需要先输入 i 字符进入编辑态,此时界面底部会出现 -- INSERT --
标识。
...
# Note that empty commits are commented out
-- INSERT --
下面那些以 # 开头的都是注释,只有前面两行比较关键。
pick 89f3d02 feat: 增加国际化
pick ec0218f feat: 增加国际化
# ...
每一行都由三部分组成:
- Command:需要执行的命令
- Commit ID:提交 ID
- Commit message:提交的描述信息
我们需要将 ec0218f 合并到 89f3d02 上,因此需要将第二行的 pick 改成 squash(s) 或 fixup(f),这两个命令的区别在于:
- squash(s) 是将当前的提交合并到上一行的提交上,保留两个提交的描述信息,可以在下一步中进行提交信息的编辑
- fixup(f) 也是将当前的提交合并到上一行的提交上,但不保留当前提交的描述信息
由于我们两次提交信息完全一致,没必要保留,选择 fixup(f):
pick 89f3d02 feat: 增加国际化
f ec0218f feat: 增加国际化
修改好之后,先按 ESC 退出编辑态,然后按 :wq 保存,显示以下信息说明变基成功,两个提交已经合并在一起
Successfully rebased and updated refs/heads/kagol/test-rebase.
执行 git log 看下效果:
commit 86930d03
feat: 增加国际化
commit cdedd430
refactor: pnpm工程改造
可以看到两个提交已经合并在一起,并且生成了一个新的 Commit ID: 86930d03。
我代码没了!
1小时之后,同事慌慌张张地跟我说:
我代码没了!
我心里第一反应是:
刚才一顿变基猛如虎,不过变基变出问题来了吧?
作为一个成熟稳重的程序员,什么大风大浪没见过,于是轻轻地回了句:
少年,莫慌!你先讲下你刚才做了什么?
我没,没做什么...
没做什么代码怎么会自己丢了呢?
我就执行了一下 git stash pop,然后我之前写了一上午的代码就没...没了...
突然开始心里有点慌,把同事一上午代码搞没了,我怎么赔给人家??
但心里不能表现出来,不着急,稳住少年!
你先执行下 git stash list 看下储存栈里还有没有内容:
$ git stash list
stash@{0}: WIP on master: f90abfe Initial commit
看到之前储存的内容还在我立马不慌了!
不再执行下 git stash pop,我看下有没有报什么错?
执行完之后果然报了一个错:
$ git stash pop
error: Your local changes to the following files would be overwritten by merge:
main.ts
Please commit your changes or stash them before you merge.
Aborting
The stash entry is kept in case you need it again.
大意是:
你本地修改了文件,储存栈里的内容如果弹出会覆盖掉你本地的代码,所以导致操作失败。
然后建议你先提交你本地的修改或者将你本地的修改储存起来。
并且特意提示你你储存的内容给你保留下来了,方便你下次要用的时候可以用。
不得不说,这 Git 真是太贴心了,考虑得很周到,为 Git 点个赞👍
虽然我其实已经猜到是什么原因了,但是作为成熟稳重的程序员,我依然不动声色地问了句:git rebase 之后,git stash pop 之前,中间你是不是还改了什么东西?
哦,好像是改了 main.ts 文件,我想起来了!
你把你改的东西先撤销下,然后执行 git stash pop 试试?
破案!收工!
果然,执行 git stash pop 成功,之前的上百行代码都找回来了!
破案!收拾吃饭的家伙,准备收工!
哦,不行,还有两个小时才下班...
我是 Kagol,如果你喜欢我的文章,可以给我点个赞,关注我的掘金账号和公众号 Kagol
,一起交流前端技术、一起做开源!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步