# 起因

事情是这样的,我在旧项目上开发新需求的时候,我接到多个需求(一个简单需求,一个复杂需求),我直接拉取旧项目的代码就哗啦哗啦一顿造,然后每次下班前怕代码丢失就push 到远程分支 dev,突然,某一天,组长跟我说:你先把那个已经完成的简单需求push 一下,提个 mr(gitlab 的 merge request),之后他看完没问题再同意这个 mr 将远程分支 dev 合并到远程主分支 master。

因为我只是在同一个分支同时开发多个需求,这个时候我那个复杂需求还没完成,组长那边只要已经完成的简单需求,我两个需求的代码都混在一起了,而且还提交了一部分到远程了,我于是想办法能不能将远程分支 dev 回退到原始版本,同时保留我已经写好的文件,再将简单需求的代码提交,再 push 到远程分支 dev,再提 mr?

# 如何处理?

必知:git 分为:工作区,暂存区,版本库

工作区:就是你在电脑里能看到的目录。

暂存区:英文叫 stage 或 index。一般存放在 .git 目录下的 index 文件(.git/index)中,所以我们把暂存区有时也叫作索引(index)。

版本库:工作区有一个隐藏目录 .git,这个不算工作区,而是 Git 的版本库。

对应到常用开发的三个操作

git add . 将工作区修改的文件提交到暂存区

git commit -m '注释' 将暂存区的文件提交到本地版本库

git push 将本地版本库同步到远程版本库

怕后悔的话,新建一个分支进行操作

git checkout -b tmp
1

此时我们已经建立并切换到 tmp 分支,比如你之前在 dev 分支,此时你可以理解为复制了 dev 分支的所有文件,之后在 tmp 分支上的一切操作都不会影响到 dev 分支,这样一旦后悔了,直接切换到 dev 分支然后删除 tmp 分支即可

接下来,我在 tmp 分支上进行一系列的测试

我查了一下 git 回退版本的命令,分为回退本地版本和回退远程版本

git reset [--soft | --mixed | --hard] [HEAD]
1

--mixed 为默认,可以不用带该参数,用于重置暂存区的文件与上一次的提交(commit)保持一致,工作区文件内容保持不变。

--soft 参数用于回退到某个版本

--hard 参数撤销工作区中所有未提交的修改内容,将暂存区与工作区都回到上一次版本,并删除之前的所有信息提交:

我们需要的是不删除文件的前提下,撤销 commit,也就是--mixed模式,也就是默认模式

回退的时候,我们需要找到最原始的版本的对应的哈希值

git log #显示当前分支所有提交过的版本信息,不包括已经被删除的 commit 记录和reset的操作
git reflog #显示所有分支的所有操作记录信息(包括已经被删除的 commit 记录和 reset 的操作)
#提升阅读体验,加上参数 --pretty=oneline 只会显示版本号和提交时的备注信息
git log --pretty=oneline
git reflog --pretty=oneline
1
2
3
4
5

四个命令都能找到之前对应的版本库的哈希值,找到指定的哈希值后,我们执行下面命令

git reset 哈希值
1

image-20210820144024359

此时我们可以在工作区看到有很多已修改未提交的文件,此时我们只选择需要提交的文件提交到暂存区,再进行 commit 既可

image-20210820144154178

此时git log --pretty=oneline查看一下 commit 记录

image-20210820144742723

成功了,此时本地版本库已经回退到我们想要的结果了,下一步就是同步远程分支 dev 了

提醒:此时我们还在测试分支 tmp 上

如何强制同步远程仓库与本地仓库一致呢?

#git push origin 本地分支:远程分支 -f
#-f表示强制推送
git push origin tmp:dev -f
1
2
3

这样我们远程仓库就跟我们本地仓库一致了,此时再提 mr 既可

# 经验教训

那么经过此时有什么感悟呢?今后如何避免这些问题呢?有什么场景呢?

常规场景:我们在进行项目开发的时候,每天写完代码提交到暂存区,再根据自身情况写 commit 注释提交到本地,(有些公司 commit 会有规范的,这点要注意),千万不要 push 到远程,因为你很可能是在一个老项目开发新功能,假设你新功能没开发好但是已经 push 到远程了,这时候突然让你改另外一个 bug,而且是改完立马测试推到线上的,这时候就尴尬了,你就得回退远程代码的版本了

所以最好的做法就是,拿到一个旧项目(新项目就无所谓啦),在开发每一个新功能之前,先建立一个分支

比如我上面有两个需求,我拉取旧项目的最新代码到本地 master 分支后,我单独再建立两个新的分支,分别去写代码完成两个需求,每个需求完成后再单独的 push 到远程(注意要选择对应的本地分支和远程分支,因为远程分支可能没有你本地那么多)

bug 场景:你在开发一个需求时,组长突然让你改某一个 bug,此时你 master 分支是旧项目的代码,而且不包含新需求的代码,你额外需要建立一个 bug 分支,在该分支上进行 bug 的修复,然后可能是 push 到远程的 bug 分支,提个 mr,再经过组长查看无误后再合并到远程 master 分支(线上环境),也可能是你自己直接 merge 到 master 分支,在 push 到远程的 master

最近更新: 4 小时前