代码回滚:Reset、Checkout、Revert的选择

Zhongyi Tong edited this page on Dec 8, 2015 · 5 revisions

BY 童仲毅(geeeeeeeeek@github)

这是一篇在原文(BY atlassian)基础上演绎的译文。除非另行注明,页面上所有内容采用知识共享-署名(CC BY 2.5 AU)协议共享。

git resetgit checkoutgit revert是你的Git工具箱中最有用的一些命令。它们都用来撤销代码仓库中的某些更改,而前两个命令不仅可以作用于提交,还可以作用于特定文件。

因为它们非常相似,所以我们经常会搞混,不知道什么场景下该用哪个命令。在这篇文章中,我们会比较git resetgit checkoutgit revert最常见的用法。希望你在看完后能游刃有余地使用这些命令来管理你的仓库。

Git仓库有三个主要组成——工作目录,缓存区和提交历史。这张图有助于理解每个命令到底产生了哪些影响。当你阅读的时候,牢记这张图。

提交层面的操作

你传给git resetgit checkout的参数决定了它们的作用域。如果你没有包含文件路径,这些操作对所有提交生效。我们这一节要探讨的就是提交层面的操作。注意,git revert没有文件层面的操作。

Reset

在提交层面上,reset将一个分支的末端指向另一个提交。这可以用来移除当前分支的一些提交。比如,下面这两条命令让hotfix分支向后回退了两个提交。

git checkout hotfix
git reset HEAD~2

hotfix分支末端的两个提交现在变成了悬挂提交。也就是说,下次Git执行垃圾回收的时候,这两个提交会被删除。换句话说,如果你想扔掉这两个提交,你可以这么做。reset操作如下图所示:

如果你的更改还没有共享给别人,git reset是撤销这些更改的简单方法。当你开发一个功能的时候发现『糟糕,我做了什么?我应该重新来过!』时,reset就像是go-to命令一样。

除了在当前分支上操作,你还可以通过传入这些标记来修改你的缓存区或工作目录:

  • --soft – 缓存区和工作目录都不会被改变
  • --mixed – 默认选项。缓存区和你指定的提交同步,但工作目录不受影响
  • --hard – 缓存区和工作目录都同步到你指定的提交

把这些标记想成定义git reset操作的作用域就容易理解多了。

这些标记往往和HEAD作为参数一起使用。比如,git reset --mixed HEAD 将你当前的改动从缓存区中移除,但是这些改动还留在工作目录中。另一方面,如果你想完全舍弃你没有提交的改动,你可以使用git reset --hard HEAD。这是git reset最常用的两种用法。

当你传入HEAD以外的其他提交的时候要格外小心,因为reset操作会重写当前分支的历史。正如Rebase黄金法则所说的,在公共分支上这样做可能会引起严重的后果。

Checkout

你应该已经非常熟悉提交层面的git checkout。当传入分支名时,可以切换到那个分支。

git checkout hotfix

上面这个命令做的不过是将HEAD移到一个新的分支,然后更新工作目录。因为这可能会覆盖本地的修改,Git强制你提交或者缓存工作目录中的所有更改,不然在checkout的时候这些更改都会丢失。和git reset不一样的是,git checkout没有移动这些分支。

除了分支之外,你还可以传入提交的引用来checkout到任意的提交。这和checkout到另一个分支是完全一样的:把HEAD移动到特定的提交。比如,下面这个命令会checkout到当前提交的祖父提交。

git checkout HEAD~2

这对于快速查看项目旧版本来说非常有用。但如果你当前的HEAD没有任何分支引用,那么这会造成HEAD分离。这是非常危险的,如果你接着添加新的提交,然后切换到别的分支之后就没办法回到之前添加的这些提交。因此,在为分离的HEAD添加新的提交的时候你应该创建一个新的分支。

Revert

Revert撤销一个提交的同时会创建一个新的提交。这是一个安全的方法,因为它不会重写提交历史。比如,下面的命令会找出倒数第二个提交,然后创建一个新的提交来撤销这些更改,然后把这个提交加入项目中。

git checkout hotfix
git revert HEAD~2

如下图所示:

相比git reset,它不会改变现在的提交历史。因此,git revert可以用在公共分支上,git reset应该用在私有分支上。

你也可以把git revert当作撤销已经提交的更改,而git reset HEAD用来撤销没有提交的更改。

就像git checkout 一样,git revert 也有可能会重写文件。所以,Git会在你执行revert之前要求你提交或者缓存你工作目录中的更改。

文件层面的操作

git resetgit checkout 命令也接受文件路径作为参数。这时它的行为就大为不同了。它不会作用于整份提交,参数将它限制于特定文件。

Reset

当检测到文件路径时,git reset 将缓存区同步到你指定的那个提交。比如,下面这个命令会将倒数第二个提交中的foo.py加入到缓存区中,供下一个提交使用。

git reset HEAD~2 foo.py

和提交层面的git reset一样,通常我们使用HEAD而不是某个特定的提交。运行git reset HEAD foo.py 会将当前的foo.py从缓存区中移除出去,而不会影响工作目录中对foo.py的更改。

--soft、--mixed和--hard对文件层面的git reset毫无作用,因为缓存区中的文件一定会变化,而工作目录中的文件一定不变。

Checkout

Checkout一个文件和带文件路径git reset 非常像,除了它更改的是工作目录而不是缓存区。不像提交层面的checkout命令,它不会移动HEAD引用,也就是你不会切换到别的分支上去。

比如,下面这个命令将工作目录中的foo.py同步到了倒数第二个提交中的foo.py。

git checkout HEAD~2 foo.py

和提交层面相同的是,它可以用来检查项目的旧版本,但作用域被限制到了特定文件。

如果你缓存并且提交了checkout的文件,它具备将某个文件回撤到之前版本的效果。注意它撤销了这个文件后面所有的更改,而git revert 命令只撤销某个特定提交的更改。

git reset 一样,这个命令通常和HEAD一起使用。比如git checkout HEAD foo.py等同于舍弃foo.py没有缓存的更改。这个行为和git reset HEAD --hard很像,但只影响特定文件。

总结

你现在已经掌握了Git仓库中撤销更改的所有工具。git resetgit checkout、和 git revert命令比较容易混淆,但当你想起它们对工作目录、缓存区和提交历史的不同影响,就会容易判断现在应该用哪个命令。

下面这个表格总结了这些命令最常用的使用场景。记得经常对照这个表格,因为你使用Git时一定会经常用到。

命令 作用域 常用情景
git reset 提交层面 在私有分支上舍弃一些没有提交的更改
git reset 文件层面 将文件从缓存区中移除
git checkout 提交层面 切换分支或查看旧版本
git checkout 文件层面 舍弃工作目录中的更改
git revert 提交层面 在公共分支上回滚更改
git revert 文件层面 (然而并没有)

这篇文章是『git-recipes』的一部分,点击目录查看所有章节。

如果你觉得文章对你有帮助,欢迎点击右上角的StarFork

如果你发现了错误,或是想要加入协作,请参阅Wiki协作说明

git代码回滚:Reset、Checkout、Revert的选择的更多相关文章

  1. 6.Git代码回滚

    1.代码修改并提交 我们已经成功地添加并提交了一个helloWorld.txt文件,现在,是时候继续工作了. 于是,我们继续修改helloWorld.txt文件,改成如下内容: $ vi helloW ...

  2. git代码回滚的两种选择

    回滚到指定commit,且保持该commit之前和之后的提交记录 使用git revert命令. git revert HEAD // 回滚到前一次 commit git revert HEAD^ / ...

  3. 转一篇Git代码回滚技巧

    转 https://github.com/geeeeeeeeek/git-recipes/wiki/5.2-代码回滚:Reset.Checkout.Revert的选择

  4. git代码回滚

    有时候我们用git提交代码后发生了错误,代码冲突了啊等等,我们需要将代码回到以前的某个版本 git代码回退有两种办法 一.git reset(推荐): 它是将最新的commit删除,用以前的某个版本的 ...

  5. git 代码回滚与爬坑 -- reset and revert

    本文通过MetaWeblog自动发布,原文及更新链接:https://extendswind.top/posts/technical/git_code_roll_back_revert_and_res ...

  6. 代码回滚:Reset、Checkout、Revert的选择

    代码回滚:Reset.Checkout.Revert的选择 Git仓库有三个主要组成——工作目录,缓存区和提交历史. 从图中我们可以看出,缓存区或者叫索引,其实是指一整套即将被下一个提交的文件集合.也 ...

  7. git的回滚与撤销【reset and revert】

    git的工作流程-- 3个区域 工作区:我们可以看到的文件内容 在操作 git add 之前的!! 缓存区:是不可见的  已经git add操作,还没git commit -m "" ...

  8. Git撤销&回滚操作(git reset 和 get revert)

    转自:https://blog.csdn.net/asoar/article/details/84111841 git的工作流 工作区:即自己当前分支所修改的代码,git add xx 之前的!不包括 ...

  9. Git如何回滚代码?

    摘要: 多年以后,你面对一个需要回滚的Git仓库,准会想起这篇博客. 某一天,用户跟我反馈,他不能分配任务了.我去看了一下Fundebug捕获的报错信息: 可知,出错原因是前端发送的请求参数有问题.这 ...

随机推荐

  1. unity渲染层级关系小结(转存)

    最近连续遇到了几个绘制图像之间相互遮挡关系不正确的问题,网上查找的信息比较凌乱,所以这里就把自己解决问题中总结的经验记录下来. Unity中的渲染顺序自上而下大致分为三层. 最高层为Camera层,可 ...

  2. 编码符_new

    begin#6BE3803ED5339EBA1028EF9FC2BBD85F196391DFC603EAE8B10BA25D0B69029667A9BD2D914CE59A26EF5ECF370D5C ...

  3. pthread——pthread_cleanup

    Pthread_cleanup用于注册线程清理函数,注册的清理函数将在线程被取消或者主动调用pthread_exit时被调用:     一个简单的示例: #include <pthread.h& ...

  4. Restful.Data v2.0发布,谢谢你们的支持和鼓励

    v1.0发布后,承蒙各位博友们的热心关注,也给我不少意见和建议,在此我真诚的感谢 @冰麟轻武 等朋友,你们的支持和鼓励,是这个开源项目最大的推动力. v2.0在除了细枝末节外,在功能上主要做了一下更新 ...

  5. 批量修改vss工作目录

    vss作为源代码版本控制工具,可以针对不同的文件夹设置不同的本地工作目录,这样可以方便我们不同的个性化需求.但是往往实际情况是,我们设置了不同的工作目录,后来却发现导致引用混乱,每个人每次获取项目文件 ...

  6. 创建动态WCF服务(无配置文件)

    public class WCFServer { ServiceHost host = null; public WCFServer(string addressurl, string tcpurl, ...

  7. 【TypeScript】如何在TypeScript中使用async/await,让你的代码更像C#。

    [TypeScript]如何在TypeScript中使用async/await,让你的代码更像C#. async/await 提到这个东西,大家应该都很熟悉.最出名的可能就是C#中的,但也有其它语言也 ...

  8. EasyDarwin不能保存HLS列表的解决方案

    官网: easydarwin.org 安装过程 http://doc.easydarwin.org/EasyDarwin/README/ 安装客户端,iVMS-4200 客户端,并运行. 在设备管理里 ...

  9. Unsafe与CAS

    Unsafe 简单讲一下这个类.Java无法直接访问底层操作系统,而是通过本地(native)方法来访问.不过尽管如此,JVM还是开了一个后门,JDK中有一个类Unsafe,它提供了硬件级别的原子操作 ...

  10. Ember.js实现单页面应用程序

    1.1.1 摘要 单页应用程序 (SPA) 是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序. SPA使用AJAX和HTML5创建流畅且响应迅速的Web应用程序,不会经常 ...