Git重置

git reset命令改变分支引用文件的内容,即实现分支的重置
git reset --hard HEAD^将master重置到上一个老的提交上。使用了hard参数,会破坏工作区未提交的改动
使用重置命令很危险,会彻底的丢弃历史。那么,能不能通过浏览提交历史的方法找到丢弃的提交ID,就不能通过重置命令恢复历史。

使用git reflog挽救错误的重置

如果没有记下重置之前master分支指向的提交ID,想要重置会原来的提交似乎是件麻烦的事情(去对象库中一个一个找)。幸好Git提供了一种挽救的机制,通过.git/logs目录下的日志文件记录了分支的变更。默认的非裸版本库(带有工作区)都提供分支日志功能,这是因为带有工作区的版本库都有如下设置:
git config core.logAllRefUpdates ------------------------------>true

tail -5 .git/logs/refs/heads/master查看日志文件的前5行

9d9e84cbe161a004045c23848b12753823053717 eef995dc79c6e5717942a19494a2ad3e02fbf8a5 17305 <guoxi.zhang@hand-china.com> 1539960515 +0800 commit (amend): 配置文件中没有name的提交
eef995dc79c6e5717942a19494a2ad3e02fbf8a5 2443ae29d86ec5edd6fbb70e2a01f1902dd02a37 17305 <guoxi.zhang@hand-china.com> 1540029427 +0800 commit: which version checked in
2443ae29d86ec5edd6fbb70e2a01f1902dd02a37 b2a5a950d4633923b63d5873154e3215157bc26b 17305 <guoxi.zhang@hand-china.com> 1540094230 +0800 commit: does master follow this new commit
b2a5a950d4633923b63d5873154e3215157bc26b 2443ae29d86ec5edd6fbb70e2a01f1902dd02a37 17305 <guoxi.zhang@hand-china.com> 1540108418 +0800 reset: moving to HEAD^
2443ae29d86ec5edd6fbb70e2a01f1902dd02a37 7a368a3ab1cbe2aec6fec3c5e15e7c6283ddeb18 17305 <guoxi.zhang@hand-china.com> 1540108475 +0800 reset: moving to 7a368a3

Git提供了一个git reflog命令对这个文件进行操作。使用show子命令可以显示此文件内容
git reflog show master|head -5
结果

7a368a3 master@{0}: reset: moving to 7a368a3
2443ae2 master@{1}: reset: moving to HEAD^
b2a5a95 master@{2}: commit: does master follow this new commit
2443ae2 master@{3}: commit: which version checked in
eef995d master@{4}: commit (amend): 配置文件中没有name的提交

重置master为两次变更之前的值
git reset --hard master@{2}
重置之后,工作区的文件以及提交历史都回来了,而且恢复master的操作也记录在日志中了

深入理解git reset命令

git reset命令的用法
用法一:git reset [-q] [<commit>] [--] <paths>
用法二:git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
上面列出两个用法,其中[<commit>]都是可选项,可以使用引用或者提交ID,如果省略了<commit>,则相当于使用了HEAD的指向作为提交ID。两种方法的区别在于第一种用法在命令中包含路径<paths>。为了避免路径和引用(或者提交ID)同名而发生冲突,可以在<paths>前用两个连续的短线作为分隔。
第一种用法(包含了路径<paths>的用法)不会重置引用,更不会改变工作区,而是用指定提交状态(<commit>)下的文件(<paths>)替换掉暂存区的文件。例如命令git reset HEAD <paths>相当于取消之前执行git add <paths>命令时改变的暂存区
第二种用法(不使用路径<paths>的用法)则会重置引用。根据不同的选项,可以对暂存区或者工作区进行重置。参照下面的版本库模型来看下参数对第二种用法的影响

重置命令和版本库对应关系

  • 使用参数--hard,如git reset --hard <commit>会执行上图的1,2,3,即
    1:替换引用的指向。引用指向新的提交ID
    2:替换暂存区,替换后,暂存区的内容和引用指向的目录树一样。
    3:替换工作区。替换后,工作区的内容和暂存区的一样,也和HEAD指向的目录树的内容一样。
  • 使用参数--soft,如git reset --soft <commit>,会执行上图的1,即只更改引用的指向,不会更改暂存区和工作区
  • 使用参数--mixed或者不使用参数(默认就是--mixed),如git reset <commit>,会执行上图的1,2,即更改引用的指向和暂存区,但不改变工作区

下面通过一些示例,看一下重置命令的不同用法。

  • 命令:git reset
    仅用HEAD指向的目录树重置暂存区,工作区不会受到影响。相当于将之前用 git add命令更新到暂存区的内容撤出暂存区。引用也为改变,因为引用重置到HEAD相当于没有重置
  • 命令 git reset HEAD
    效果同上
  • 命令 git reset filename
    仅将文件filename的改动撤出暂存区,暂存区的其他文件不变,相当于命令git add filename的反向操作
  • 命令git reset HEAD filename
    效果同上
  • 命令git reset --soft HEAD^
    工作区和暂存区的内容不变,但是引用向前回退一次,当对最新提交的提交说明或者提交更改不满意时,撤销最新的提交以便重新提交。之前提到过一个git commit --amend命令用于对最新的提交进行重新提交以修补错误的提交说明或者错误的提交文件。提交修补命令实际上相当于执行下面两条命令
    git reset --soft HEAD^
    git commit -e -F .git/COMMIT_EDITMSG
    注:文件.git/COMMIT_EDITMSG保存了上次的提交日志
  • 命令git reset HEAD^
    工作区不变,暂存区回退到上一次提交,引用也会回退一次
  • 命令git reset --mixed HEAD^
    效果同上
    命令git reset --hard HEAD^
    彻底撤销最近的提交。引用回退到前一次,而且工作区和暂存区都会回退到上一次的提交状态。自上一次以来的提交全部丢失
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 以下笔记主要参考gitgot,大致了解git使用和原理。 第一部分我们从个人的视角去研究如何用好Git,并且揭示G...
    carolwhite阅读 7,061评论 0 1
  • 一、电脑本地初始化一个仓库 1. git init: 初始化一个电脑上本地仓库 终端进入项目目录,输入: 该命令将...
    dragon_li阅读 8,127评论 1 4
  • Git 基础 基本原理 客户端并不是只提取最新版本的文件快照,而是把代码仓库完整的镜像下来。这样一来,任何一处协同...
    __silhouette阅读 16,095评论 5 147
  • 好雨知时润地酥,长亭策马两踟蹰。 云霾渐远离人泪,半是痴情半是愚。 (平水韵·七虞)
    不惑而歌阅读 3,012评论 4 35
  • 喜欢上一个人的感觉真是好微妙。特别是,你偷偷喜欢一个人。 你每分每秒都在想念他。早上起床的时候,你会想,不知道那个...
    Momo_ng阅读 3,738评论 0 0

友情链接更多精彩内容