Git-少年,你想学回滚吗?想撤销文件修改吗?

本文详细介绍了Git中撤销提交及文件修改的方法,包括reset、revert和checkout命令的使用技巧,帮助读者掌握如何高效地撤销错误操作。

title: Git-少年,你想学回滚吗?想撤销文件修改吗?
date: 2018-03-11 22:40:01
tags:

哎呀呀,夏天,哪里凉快滚哪里,冬天,哪里暖和滚哪里

写在前面

林俊杰有首歌《可惜没如果》,道尽后悔的遗憾,但是万幸,在 Git 中你可以拥有如果,用 resetcheckoutrevert 可以用来撤销当年那些错误的决定。

带着 Git 三大区的概念去阅读

来,看下面这张图复习复习 Git 三大区的概念,这个概念即将贯穿今天这篇文章,理解很重要,不太理解的小伙伴可以先去我的另一篇博客 《 Git三大特色之Stage(暂存区)》学习下先,等你哦。

git 数据流程图示意图

吃第一颗栗子,理解一下什么叫做回滚

有一个Android 开发工程师,他叫小明,他正在 feature 分支上开发,他的 feature 分支历史如下图所示,一切都很正常,按照计划进行,这时他接到一个需求变更通知,说“用户积分模块,这个版本不要了”,这真是一个悲伤的消息,小明要赶紧改回来。

在这里插入图片描述

如果小明不会回滚历史,需要人肉操作去找有关 “用户积分模块” 的代码,然后一个个注或删除释掉,这个更悲伤了,我猜小明可能会哭。

在这里插入图片描述

如果小明用的是 Git,也知道怎么回滚,他只需要找到回滚的终点提交,然后一个命令就可以开始回滚操作。

如果小明是个老手,他会先新建个分支做备份,然后再回滚,那也只需要两条命令:

以上完美解决此时的需求变更,小明很开心。

拿起你的栗子,来认识 reset 的三种模式

上面的例子中,我们使用的命令是 git reset --hard <commit-id>,其实 reset 有三种模式:

  • –hard
  • –mixed(默认模式)
  • –soft

三个参数对应的是不同的作用范围,这个范围和开篇说的 Git 三大区息息相关,因为这个三个模式就是因为有三个分区才存在的。

在这里插入图片描述

实际使用中,你可能会遇到各种千奇百怪需求的的撤销操作,理解好这三种模式的区别,使用起来倍爽。下面列两三个你肯定会遇到的场景,然后用 reset 的不同模式。可以轻松解决问题。

小明写代码ing;
同事说“小明,你快拉取一下仓库的最新代码,blabla…” ;
小明开始“git pull” ;
git pull failed ,原因是暂存区有未提交的修改,这些修改可能会被覆盖;
小明确定不会被覆盖,不想创建一个新提交,还想保存修改内容 ;
请问:该怎么办?

//将暂存区的内容与提交历史同步
git reset

//然后再拉取                               
git pull xxx  

小明刚创建了一个 commit;
然后发现那个 commit 中有个小错误;
但是为了维护美好的分支历史,不想因为这个小修改再创建一个提交;
请问:该怎么办?

//将此提交撤销,但是不修改暂存区和工作区的内容
 git reset --soft HEAD^  

//修改好小问题

//重新提交                      
git add .
git commit -m 'xxx'

其实,这是使用 --soft的解决方案,还有一种更方便的方法,不用撤销也能完成,git commit --amend追加提交:


//修改好小问题

//重新提交                      
git add .
git commit --amend`

上面的例子,希望给帮你更加清楚的理解 reset 三种的模式的区别,在使用 reset --hard的时候,要小心一点,因为这个操作会彻底地重置工作区,放弃修改,使用之前,要十分确定未保存的修改要放弃,不然重置后有可能找不回来了哈。

下面给小伙伴们介绍另外一种撤销方式 revert,是一个神奇的命令。

revert 是一种抵消式撤销

revert,翻译是“反转”,一个比较难理解的词,快来解开非凡想象力的封印。

想象一下,提交中添加了一个A.txt, revert 创建了一个删除 A.txt 的新提交,两个提交同时存在,于是,A.txt 等于从来没有存在过,等于撤销了原来提交。

这像一个互为正负的关系 1+(-1)= 0

第一个例子,小明如果用 revert “撤销积分模块”,就要这样用了

//将 head^^^到head 范围内的提交反转
git revert head^^^..head

git log 看一下操作后的分支历史,不仅没少,反而多了,增加几个反转提交。

在这里插入图片描述

这是 revert 第一个例子中场景的使用表现,也许你会疑问:

有了 reset,为什么还要有 revert ?

这是因为,在下图情况下,分支顶端还有要保存的提交,reset 无法使用,只能用 revert 将中间的提交反转。

如果不想要新增的反转提交污染分支历史,你也可以选择发射你的黑魔法 rebase -i 将中间的提交施加 drop 操作,Git 真的无所不能,只要你会。

reset VS revert ,Ready? GO!

由于 resetrevert 的作用都是撤销提交,所以很多人很自然而然地将两者对比。我就是那很多人之一,而且我还特别无聊的,画了对比图,如下:

在这里插入图片描述

可以很明显的看出两者对分支历史改变区别:

  • reset 回退了历史
  • revert 创建反转提交,增加了历史

从数据安全上角度,revertreset安全,因为它的操作可以回溯,反转了还可以倒回来。reset比较彻底,是直接丢弃了,不过可以考虑想第一个例子中创建一个备份分支来保证安全。

从分支历史的长期维护角度,reset的历史比较干净,revert的反转提交没多大意义,毕竟很少有需求让你滚来滚去的。

在被撤销提交,不再分支顶端的场景上,reset 无法使用,revert可以做到,。

以上对两者的区别讨论结束,没有总结,看你个人喜好和需求场景使用。

撤销的不是提交,而是文件

上面给大家介绍的都是关于 commit history 提交历史的撤销,但是有时候会出现撤销单个文件修改的场景,例如,我就经常写了很多代码之后发现某个想法不可行,那个时候已经写了很多代码了,Command+Z都撤不完了,手动改太麻烦还容易出错,怎么办?

这个时候就需要撤销文件的修改了,下面就给大家介绍一下,如何进行文件撤销。

checkout 的第二命令格

checkout 这个命令,我们对它太熟悉了,切换分支,检出提交,检出 Tag 标签等等各种对 HEAD 指针花式操作,但是看下,git-checkout 官网文档的定义:

在这里插入图片描述

是不是很惊讶,还可以被用来还原工作区的文件!

其实这个命令就近在我们眼前,运行 git status,会看到工作区和暂存区的修改,如果工作区有修改存在,Git 就会提示,可以通过 git add <file> 来加入暂存区以备下次提交,如果放弃修改,就执行 git checkout -- <file>

git status中的 checkout

所以,要是哪次想撤回修改,恢复到上次 add 时内容 ,除了手动 Command+ZCtrl+Z ,还可以是使用 git checkout -- <file>,改动较多时,简直一步到位!

reset 的新操作

接着上面,工作区1.txt的修改我想下次提交,于是执行了 git add . 加入了暂存区,这个时候运行 git status,又发现 reset 命令的新操作 git reset HEAD <file>

git status 中的 reset

看注释,这个操作可以将某个文件的修改从暂存区拿出去。在错误 add 不想提交的文件时,这个命令还是很有用的。

写在后面

好了,以上是本博客的全部内容,希望能帮助大家理解和学会提交历史的撤销和文件文修改的撤销。

下篇博客会讲一个特别治愈的命令 reflog,和 reset 配合可以被用来恢复数据,包括已经撤销的,敬请期待,并欢迎关注我的专栏 《帅气的 Git 操作》,里面有开始学习 Git 到现在的全部文章。

see you next blog!

欢迎订阅我的Git系列文章


欢迎关注个人微信公众号「浅浅同学的开发笔记」,最新的博客,好玩的事情,都会在上面分享,期待与你共同成长。

在这里插入图片描述

<think>我们正在使用SourceTree进行版本控制,讨论已推送到远程仓库的提交是否还可以回滚回滚已推送到远程仓库的提交是可行的,但需要谨慎操作,因为它会影响其他协作者。 通常有两种方式: 1. 使用`git revert`创建新的提交来撤销之前的提交(推荐,因为不会改变历史) 2. 使用`git reset`回退到某个提交,然后强制推送(会改变历史,适用于个人分支或团队允许的情况) 下面分别说明两种方法在SourceTree中的操作步骤以及命令行方式(以备SourceTree操作不便时使用)。 注意:在协作开发中,如果提交已经被其他协作者拉取,通常建议使用`git revert`以避免历史冲突。 方法一:使用`git revert`(推荐) - 此方法会创建一个新的提交,该提交是原提交的反向操作(即撤销原提交的更改)。 - 因为不改变历史,所以可以直接推送到远程仓库,不会影响其他协作者。 方法二:使用`git reset`(谨慎使用) - 此方法将分支指针移动到某个提交,丢弃之后的提交。 - 由于改变了历史,需要强制推送(force push)到远程仓库。这会覆盖远程分支的历史,如果其他协作者已经基于该提交进行了工作,会导致他们同步困难。 由于SourceTree是图形化工具,下面分别介绍在SourceTree中如何操作,以及相应的命令行代码。 首先,假设我们回滚的提交是最近的一次提交(commit hash为abc123)。 方法一:使用SourceTree进行revert操作 步骤: 1. 在SourceTree的提交历史中,找到要回滚的提交(比如abc123)。 2. 右键点击该提交,选择“回滚提交”(或类似选项,不同版本可能略有不同,有些版本是“反向提交”)。 3. 在弹出的对话框中,确认操作(可能会提示你输入提交信息)。 4. 这将在当前分支上创建一个新的提交,该提交撤销了abc123的更改。 5. 然后推送这个新提交到远程分支。 方法一对应的命令行: ```bash git revert abc123 # 创建一个撤销abc123的提交 git push origin branch_name ``` 方法二:使用SourceTree进行reset操作(强制回退) 步骤: 1. 在SourceTree中,找到要回退到的提交(即abc123之前的提交,比如def456)。 2. 右键点击该提交,选择“重置当前分支到此次提交”(Reset current branch to this commit)。 3. 在重置类型中选择“硬合并”(Hard - discard all working copy changes),这将丢弃所有之后的更改。 4. 点击确定,此时本地分支已经回退到def456。 5. 由于远程分支仍然有abc123,所以需要强制推送:在SourceTree的顶部菜单中,点击“推送”(Push),然后勾选“强制推送”(Force push)选项(可能需要在设置中开启强制推送选项)。 6. 推送后,远程分支也会回退到def456。 方法二对应的命令行: ```bash git reset --hard def456 # 重置到def456,丢弃之后的所有提交 git push --force origin branch_name ``` 重要提示:强制推送会覆盖远程分支的历史,如果其他人已经拉取了被覆盖的提交,他们的分支将和远程分支不一致,需要他们重新设置分支跟踪(可能需要执行`git fetch`然后`git reset --hard origin/branch_name`),这可能会造成他们的工作丢失。因此,在共享分支上尽量避免使用强制推送。 总结: - 如果提交已经公开且可能被其他人使用,首选`git revert`。 - 如果分支是私有的或者团队允许重写历史,可以使用`git reset`并强制推送。 下面是一个简单的示例,展示如何通过命令行使用这两种方法。注意:实际使用时需要替换提交哈希和分支名。 示例1:使用revert ```bash # 假设要回滚的提交是 abc123 git revert abc123 # 解决可能出现的冲突(如果有冲突) git add . git commit -m "Revert 'abc123'" git push origin main ``` 示例2:使用reset(强制推送) ```bash # 回退到提交 def456(即abc123的前一个提交) git reset --hard def456 # 强制推送 git push --force origin main ``` 在SourceTree中操作时,图形界面会帮助简化部分步骤,但理解背后的命令有助于处理复杂情况。 §§相关问题§§: 1. 使用`git revert`回滚多个连续的提交应该怎么做? 2. 在SourceTree中如何查看已经被回滚的提交记录? 3. 强制推送后如何恢复被覆盖的提交? 4. 如何避免在团队协作中因回滚提交导致的代码冲突? </think># SourceTree中回滚已推送到远程仓库的提交 是的,SourceTree中已推送到远程仓库的提交仍然可以回滚,但需要谨慎操作,因为这会影响其他协作者。以下是两种主要方法及其详细说明: ## 方法1:使用`git revert`(推荐 - 安全) 这种方法创建一个新的提交来撤销之前的更改,不会修改历史记录,最适合团队协作环境。 ### SourceTree操作步骤: 1. 在提交历史中找到要撤销的提交 2. 右键点击该提交,选择"回滚提交" 3. 在弹出窗口中确认操作 4. 提交新生成的还原提交 5. 推送到远程仓库 ### 命令行等效操作: ```bash # 撤销指定提交(创建新的还原提交) git revert <commit-hash> # 解决可能出现的冲突(如果有) git add . git revert --continue # 推送还原提交到远程 git push origin <branch-name> ``` ### 示例: ```bash # 撤销提交 abc123 git revert abc123 # 推送更改 git push origin main ``` ## 方法2:使用`git reset`(危险 - 修改历史) 这种方法直接重置分支指针到之前的提交点,会修改历史记录。**只适合个人分支或团队明确允许的情况**。 ### SourceTree操作步骤: 1. 在提交历史中找到目标回滚点之前的提交 2. 右键点击,选择"将<分支名>重置到该提交" 3. 选择"硬合并"(完全丢弃后续更改) 4. 强制推送到远程仓库(需在推送选项中勾选"强制推送") ### 命令行等效操作: ```bash # 重置到目标提交(丢弃之后的所有提交) git reset --hard <commit-hash> # 强制推送到远程仓库 git push --force origin <branch-name> ``` ### 示例: ```bash # 重置到提交 def456(丢弃之后的所有提交) git reset --hard def456 # 强制推送覆盖远程历史 git push --force origin main ``` ## ⚠️ 重要注意事项 1. **协作影响**: - `git revert`:安全,不会破坏团队工作流程 - `git reset`:强制推送会覆盖远程历史,可能导致其他协作者出现问题 2. **最佳实践**: ```mermaid graph TD A[需要回滚已推送的提交] --> B{是否团队共享分支?} B -->|是| C[使用 git revert] B -->|否| D[可以使用 git reset] C --> E[创建还原提交] D --> F[强制推送] E --> G[安全推送] F --> H[提前通知团队成员] ``` 3. **替代方案**: - 使用`git revert -m`撤销合并提交 - 使用`git revert --no-commit <hash>`撤销多个提交 ## 结论 对于已推送到远程的提交: - **优先使用`git revert`** - 安全可靠,不会破坏团队工作流 - **谨慎使用`git reset`** - 仅在个人分支或团队明确同意时使用 - 操作前建议使用`git fetch`确保本地仓库是最新状态 - 强制推送后,通知团队成员重新克隆或重置本地分支
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值