Git Reset VS Git Revert

本文介绍了Git中两种重要的版本回退命令:revert和reset。通过实例对比这两种命令的区别和应用场景,帮助开发者在遇到错误提交时选择合适的解决方法。

每天早上七点三十,准时推送干货

Hello,大家好,我是阿粉,之前给大家介绍过 Git 的几个超级实用的命令,没看过的朋友可以去看一下

那些你应该知道的,但是你一定不知道的 Git 骚操作 今天再给大家介绍一个不常用,但是关键时刻很好用的命令git revert

背景

日常工作中经常都是很多同事一起迭代开发,而且经常会有很多需求的开发在不同的代码分支上,如果出现不小心将某个未完成的功能提交了,并且已经 push 到分支上去了,那我们该怎么办呢?阿粉最近就遇到了这样的问题,之前提交的一个功能代码,虽然是一个完整的功能,但是由于种种原因这个功能被取消了,相关的代码也需要被撤销不能提交到生产上面去,但是在这个 commit 之后也有许多其他功能代码的提交。其他功能还是要正常上线的,不能被影响的。

这个时候很多小伙伴就会说:可以把对应需要撤销的功能代码重新修改掉不就可以了吗?这种方案当时是可以的,特别是如果我们改动的地方不多的情况下,直接将代码修改回来即可,方便又简单快速。但是如果对应要修改的文件很多,而且每个文件修改的地方又很多那就很麻烦了,如果对着提前的修改一行一行的修改就是个非常浪费时间的事情了。

Git Reset/Revert

遇到这种情况我们能想到的肯定是网上一定有相关的解决方案,并且 Git 一定提供了相应的命令可以帮到我们。通过查询 Git 手册我们发现 Git 提供了两个相关命令让我们回滚版本,分别是 reset 和 revert。那两个之间有什么区别呢?下面阿粉通过示例给大家演示一下这两个命令的使用和区别。

Git Reset

我们先分几次创建几个文件,然后依次commit 和 push ,形成多次提交,如下图所示,我们创建了四个文件,每个文件单独 commit 和 push,然后通过git log 命令我们可以查看的整个提交的日志信息,其中就包含了四次的文件提交记录。

现在我们突然发现 test3.txt 文件提交的有问题,我们需要回滚到 test2.txt 的版本,我们可以通过执行命令git reset --hard 15e32cd0cc909ef6791e4417f5572b5e7886f977 --hard 表示强制回到指定的版本,后面紧跟的是目标的版本号。

再通过git log 命令我们可以看到当前的版本已经变掉了,变成我们指定的版本了。

我们再通过git push -f origin branch 命令将重置的版本推送到远程服务器上,由于在推送到服务器前我们本地的代码已经落后服务器的代码了,所以我们需要增加-f 参数表示强制推送到远程服务器。

细心的朋友可能会发现,我们执行到这里,确实回退到需要的版本了,但是有问题的如果只是 test3.txt 文件,而 test4.txt 文件是没有问题的,我们是可以正常提交的,如果按照这种方式去操作,我们就会把 test4.txt 版本的修改给丢失了。当然我们可以重新再提交写一遍,但是如果这个版本的内容很多,我们是改不过来的。所以这种方式一般我们是不会使用的,只有确保后续所有的修改都不需要的时候我们才可以使用这种方式。

Git Revert

下面再看下 git revert 命令的使用方式,我们分两次创建两个文件,分别commit 和 push 到远程,然后通过 git log,我们可以看到下面内容,现在最新的版本已经是 test6.txt 了。同样的,这个时候我们发现 test5.txt 的版本有问题,但是 test6.txt 的版本是正确的,我们只想撤销掉 test5.txt 版本的提交。

这个时候我们执行命令git revert -n 50896fa7d9ba16b63a0fc539bb6620411e5dee4c 将 test5.txt 版本给撤销,并执行git commit -m xxx 进行提交然后在push 到远程。

再通过git log 我们可以看到,产生了一次新的提交将我们 test5.txt 版本的内容撤销掉了,并且 test6.txt 版本的提交还依旧保留在。

通过上面的演示,我们可以发现git reset 和 git revert 两个命令虽然都可以进行版本回退,但是在使用的时候还是有很多的差异的。在我们确认了在需要回退的版本之后的提交都可以不需要的时候,我们可以直接使用git reset 命令,但是当我们只是需要撤销某个版本的时候,我们就可以使用git revert 。

总结

今天阿粉通过示例给大家介绍了 git reset 和git revert 两个命令的使用和区别,在日常工作的难免会遇到需要使用的时候,如果不需要当然是最好,但是万一什么时候需要用了,对大家有帮助也是极好的,如果觉得有用,欢迎点赞转发,让更多的小伙伴看到。

< END >

如果大家喜欢我们的文章,欢迎大家转发,点击在看让更多的人看到。也欢迎大家热爱技术和学习的朋友加入的我们的知识星球当中,我们共同成长,进步。

往期精彩回顾

阿粉手把手教你在 CentOS7 下搭建 Jenkins

全网最全Log配置教程及框架性能比较,看这篇就够了!

这年头还有问Tomcat调优和JVM参数优化的,你还不知道怎么回答么?那么你一定需要看看这篇文章

<think>我们正在讨论Git中的两个撤销更改的命令:`git reset` 和 `git revert`。根据用户提供的引用,我将总结它们的区别、使用场景及作用。 ### 1. **核心区别** `git reset` 和 `git revert` 都是用于撤销更改的命令,但它们在实现方式和影响上存在本质差异: | **特性** | **`git reset`** | **`git revert`** | |------------------|---------------------------------------------------------------------------------|---------------------------------------------------------------------------------| | **操作对象** | 移动当前分支的HEAD指针到指定的提交(commit) | 创建一个新的提交,该提交会撤销指定提交的更改 | | **历史记录** | 会重写历史,删除目标提交之后的所有提交(如果目标提交不是最新提交) | 保留原始历史,通过新增提交来实现撤销,历史记录不会被修改 | | **适用场景** | 本地分支、私有分支(尚未推送的提交) | 公共分支(已推送的提交) | | **风险** | 高风险:会删除历史记录,可能导致协作问题(如强制推送覆盖他人工作) | 低风险:安全撤销,不影响他人工作 | | **工作区影响** | 可选:通过参数控制是否重置暂存区和工作目录(`--soft`、`--mixed`、`--hard`) | 不影响:只生成新提交,工作目录和暂存区不变(需手动处理冲突) | ### 2. **详细命令行为** #### (1) `git reset` - **核心作用**:将分支的HEAD指针移动到目标提交(`<commit>`),可选是否重置暂存区和工作目录。 - **参数控制**: - `--soft`:仅移动HEAD指针,不修改暂存区和工作目录。 *示例*:`git reset --soft HEAD~1` → 撤销最近一次提交,改动保留在暂存区。 - `--mixed`(默认):移动HEAD指针并重置暂存区,但不修改工作目录。 *示例*:`git reset HEAD~1` → 撤销提交且取消暂存,改动保留在工作目录。 - `--hard`:彻底回退,重置HEAD、暂存区和工作目录到目标提交状态。 *示例*:`git reset --hard a1b2c3d` → 丢弃所有未提交的更改和提交记录,慎用! - **适用场景**: - 本地撤销未推送的提交(如提交信息错误、临时调试代码)。 - 清理实验性分支的历史记录(例如:合并多个临时提交为一个整洁提交)。 #### (2) `git revert` - **核心作用**:生成一个新提交,该提交的内容是撤销指定提交的更改。 *示例*:`git revert HEAD` → 撤销最近一次提交,生成一个新提交记录这次撤销操作。 - **行为特点**: - 可撤销单个或多个提交(如`git revert commit1 commit2`)。 - 若撤销的更改与其他提交冲突,需手动解决冲突后完成`revert`(`git revert --continue`)。 - **适用场景**: - 撤销已推送到远程仓库的提交(如修复引入严重Bug的提交)。 - 需要保留完整历史记录的公共分支(团队协作时避免历史重写)。 ### 3. **关键使用场景对比** | **场景** | **推荐命令** | **原因** | |------------------------------|--------------------|--------------------------------------------------------------------------| | 本地撤销未推送的提交 | `git reset` | 彻底清理历史,避免无效提交污染记录[^1][^3] | | 撤销已推送的提交 | `git revert` | 安全撤销,不影响其他协作者的工作[^1][^3] | | 合并多个本地提交以简化历史 | `git reset --soft` | 灵活重组提交记录,便于代码审查[^4] | | 紧急修复生产环境Bug | `git revert` | 快速生成修复补丁,无需重写公共历史[^2][^5] | ### 4. **操作示例** #### 场景1:撤销未推送的本地提交(使用`reset`) ```bash # 查看提交历史(假设最新提交是123abc) git log --oneline # 输出:123abc (HEAD) Fix typo # 撤销提交(保留改动到工作目录) git reset --mixed HEAD~1 # 或直接 git reset HEAD~1(默认mixed) # 此时提交被移除,修改保留在工作目录 git status # 显示未暂存的修改 ``` #### 场景2:撤销已推送的提交(使用`revert`) ```bash # 撤销指定提交(如456def) git revert 456def # 解决可能的冲突并完成revert git add . git revert --continue # 推送修复提交 git push origin main ``` ### 5. **注意事项** - **`reset` 的风险**:重置已推送的历史后,再次推送需强制覆盖(`git push -f`),可能导致协作者的本地分支与远程不一致[^3]。 - **`revert` 的链式反应**:若撤销的提交是后续提交的基础(如功能提交A被撤销,但提交B依赖A),可能需要连续撤销多个提交或手动修复代码。 --- 通过以上分析可以看出,`git reset` 是历史重写工具,适合本地操作;`git revert` 是安全撤销工具,适用于公共分支[^4]。理解两者的差异能帮助您在版本控制中做出更安全高效的决策。 §§相关问题§§ 1. 如何撤销 `git reset --hard` 操作以恢复丢失的代码? 2. `git rebase` 和 `git reset` 在整理提交历史时有何异同? 3. 团队协作中如何规范使用 `git revert` 处理已发布的错误提交? </think>### Git ResetGit Revert 的核心区别与使用场景 基于引用内容,以下是两者对比的数学化总结($ \Delta H $ 表示历史记录变化,$ \mathcal{R} $ 表示风险等级): | **特性** | **`git reset`** | **`git revert`** | **数学表达** | |------------------|------------------------------------------------|------------------------------------------------|--------------------------------| | **本质** | 移动 HEAD 指针(历史重写) | 创建新提交(历史追加) | $ \Delta H_{\text{reset}} < 0 $ <br> $ \Delta H_{\text{revert}} > 0 $ | | **历史影响** | 删除后续提交(不可逆) | 保留原始提交(可追溯) | $ \text{reset} \Rightarrow \text{历史截断} $ <br> $ \text{revert} \Rightarrow \text{历史延续} $ | | **安全风险** | 高风险(公共分支禁用) | 低风险(协作友好) | $ \mathcal{R}_{\text{reset}} \gg \mathcal{R}_{\text{revert}} $ | | **工作区影响** | 通过参数控制:<br> `--soft`:保留改动<br> `--hard`:清除所有改动 | 不改动工作区(需手动解决冲突) | 设 $ W $ 为工作区状态:<br> $ \text{reset} \to W = f(\text{参数}) $ <br> $ \text{revert} \to \Delta W = 0 $ | | **适用场景** | 本地未推送的提交撤销 | 已推送提交的公共撤销 | | --- ### 一、核心机制详解 #### 1. **`git reset`(回退)** - **作用原理**: 移动分支指针到目标提交 $ C_{\text{target}} $,丢弃后续提交: $$ \text{HEAD} \xrightarrow{\text{reset}} C_{\text{target}} \quad \text{(删除 } C_{\text{target}+1} \text{ 至 } C_{\text{current}} \text{)} $$ - **参数控制**: - `--soft`:仅移动 HEAD(改动保留在 **暂存区**) $$ \text{HEAD} \downarrow, \quad \text{暂存区} = \text{未提交改动} $$ - `--mixed`(默认):移动 HEAD + 重置暂存区(改动保留在 **工作目录**) $$ \text{HEAD} \downarrow, \quad \text{暂存区} \to \emptyset $$ - `--hard`:彻底回退(丢弃所有未提交改动) $$ \text{HEAD} \downarrow, \quad \text{暂存区} \to \emptyset, \quad \text{工作目录} \to C_{\text{target}} $$ - **典型场景**: - 撤销本地未推送的临时提交 - 合并多个提交(`reset --soft` + 重新提交)[^4] ```bash # 撤销最近2次提交(保留改动到工作目录) git reset HEAD~2 ``` #### 2. **`git revert`(反做)** - **作用原理**: 为目标提交 $ C_{\text{target}} $ 生成一个 **逆向补丁**,创建新提交 $ C_{\text{new}} $: $$ C_{\text{new}} = -C_{\text{target}} \quad \text{(历史追加)} $$ 例如:原提交添加一行代码,revert 提交会删除该行[^3]。 - **冲突处理**: 若逆向补丁与当前代码冲突,需手动解决: $$ \text{revert} \xrightarrow{\text{冲突}} \text{手动修复} \xrightarrow{\text{continue}} C_{\text{new}} $$ - **典型场景**: - 撤销已推送到远程的提交(如修复生产环境 Bug) ```bash # 撤销指定提交(生成新提交) git revert a1b2c3d ``` --- ### 二、关键区别对比 | **维度** | **`git reset`** | **`git revert`** | |------------------|-------------------------------------------|------------------------------------------| | **历史记录** | 重写历史(原提交消失) | 追加历史(原提交保留) | | **协作影响** | 需强制推送(`git push -f`),破坏他人历史 | 直接推送(`git push`),安全协作 | | **撤销范围** | 可撤销连续提交(`HEAD~3`) | 可撤销任意提交(按需选择) | | **恢复难度** | 需 reflog 找回(复杂) | 直接再次 revert 逆转(简单) | --- ### 三、使用场景决策树 ```mermaid graph TD A[需要撤销提交] --> B{是否已推送?} B --> |未推送| C[使用 git reset] B --> |已推送| D{是否需要保留历史?} D --> |是| E[使用 git revert] D --> |否| F[禁用!强制重置会导致协作灾难] C --> G{需保留改动?} G --> |是| H[git reset --soft] G --> |暂存改动| I[git reset --mixed] G --> |彻底丢弃| J[git reset --hard] ``` --- ### 四、最佳实践建议 1. **私有分支**:优先用 `reset` 整理历史(如合并临时提交)[^4] $$ \small \text{优化:} \underbrace{C_1 + C_2 + \cdots + C_n}_{\text{临时提交}} \xrightarrow{\text{reset --soft}} C_{\text{clean}} $$ 2. **公共分支**:强制使用 `revert` 撤销错误(如修复线上 Bug)[^3] 3. **紧急回滚**: - 未推送:`reset --hard` - 已推送:`revert` + 立即推送 > 关键原则:**已共享的历史不可重写**(Golden Rule of Git)[^2][^4]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值