UDN-企业互联网技术人气社区

板块导航

浏览  : 3350
回复  : 0

[翻译] 《Git in Practice》翻译 技巧42 重置分支到之前提交:git reset

[复制链接]
zhaoyx的头像 楼主
发表于 2015-9-24 16:27:21 | 显示全部楼层 |阅读模式
本帖最后由 zhaoyx 于 2015-9-24 16:26 编辑

技巧42 重置分支到之前某次提交:git reset


在技巧39中你已经学习了如何使用git revert来回滚一次你想撤销修改的提交。我预先声明,通过回滚去改写已经公开推送的提交历史不是一个好的做法(这章后续部分我会更详细的解释)。但是如果提交还没有被推送出去呢?在这种情况下你可以使用你在技巧19中遇到的命令:git reset

在你之前使用git reset时,要么不带参数(默认使用 --mixed),要么使用 --hard 参数。请记住,--hard参数会重置缓冲区和工作区,--mixed参数只重置缓冲区,不重置工作区。一句话,--hard会丢弃所有未提交的工作,--mixed会丢弃缓冲部分(实际上回滚了git add操作)。

git reset同样也可以将一个引用作为参数使用。相比仅仅重置最后一次提交,这将允许你重置分支到版本库的任意其他提交。

让我们创建一次(没有被推送的)临时提交来实验重置:
  • 切换到版本库目录:比如,
    cd /Users/mike/GitInPracticeRedux/
  • 执行
    git checkout master
  • 编辑 00-Preface.asciidoc,对文件做些修改。
  • 执行
    git commit --message="Update preface." 00-Preface.asciidoc
    会产生类似下面的输出。

    在图示6.2中,你可以通过 GitX 看到执行git commit后的状态。

    本次,让我们试试重置到同一条分支内的前次提交;这也是git revert的一种替代用法。

问题
你希望撤销 master 分支上的最后一次提交。

解决方案
  • 切换到版本库目录:比如,
    cd /Users/mike/GitInPracticeRedux/
  • 执行
    git checkout master
  • 执行
    git reset HEAD^
    会产生类似下面的输出。

    在图示6.3中,你可以通过 GitX 看到执行git reset后的状态。之前通过git commit命令生成的提交已经消失了。

    你现在已经将 master 分支指针重置到了前一次提交。

讨论
还记得我在技巧41中提到的,git reflog对于避免提交丢失很有帮助吗?让我们想象一下,当你重置了前一次提交,但是稍后又意识到这是错误的。让我们执行git reflog来看看你是否可以从输出中得到什么有用的信息。

reflog保存了这次重置形成的记录,以及在整个过程中每个阶段状态的哈希值。让我们使用来自 reflog 的第二条输出中的(和之前gitcommit命令输出的哈希值一致的)哈希值来恢复这次提交:
  • 切换到版本库目录:比如,
    cd /Users/mike/GitInPracticeRedux/
  • 执行
    git checkout master
  • 执行
    git reset 4455fa9
    没有输出信息。
    如果现在查看图示6.4,你会发现本次提交已经被恢复,而且和它生成时的状态完全一样。现在仅有 reflog 记录了重置操作曾经发生过。

    现在可以执行git push将这次提交推送到远程仓库。

什么时候提交记录会被移出 reflog ? 90天前的和未被关联的提交对象会被git gc命令从 reflog 中移除。git gc可以手动执行,但是没有必要,因为它会定期地被其它例如git fetch命令执行。一句话来说,当你从全部分支中移除了一个提交对象之后,你还有90天的时间来恢复它,否则它就会被 Git 销毁。以我的经验,这个时间足足够用了;一般情况下,如果意外移除了一条提交,我在几天之内没有想起来的话,以后也不会想起来了。

Git reset和Git checkout有哪些不同?git reset会修改当前分支指针指向另外的提交对象。git checkout修改头指针(HEAD)使其指向其他的分支(或者,极少情况下,指向其他提交对象)。如果你正在 master 分支上,执行git reset --hard v0.1-release会将 master 分支指向 v0.1-release 分支顶部,反之,执行git checkout v0.1-release会切换当前(头指针 HEAD)分支到 v0.1-release 分支。

git reset还可以将一个文件路径作为最后一项参数使用。引用参数和路径参数之间可以使用--来区分。--是可选的,但是可以更清楚的将引用和路径区别开。毕竟,还是有可能重名的。举个例子,如果希望重置 00-Preface.asciidoc 文件内容为前一次提交,你可以执行git reset HEAD^ -- 00-Preface.asciidoc

除了--hard和--mixed参数外,git reset还可以使用--soft参数。和--mixed以及--hard参数相比,--soft参数更多的是早期状态的呈现。--hard参数会重置缓冲区和工作区(丢弃所有更改),--mixed参数会重置缓冲区,但不改变工作区(保留更改,但是会清除缓冲区内容),--soft参数则既不重置缓冲区,也不重置工作区,而仅仅是改变头指针使其指向之前的提交对象。这意味着,如果你在gitreset --soft HEAD^命令之后执行git commit命令(不带任何其他参数),缓冲区中的内容将和刚刚重置的那次提交的内容是一致的。

你也可以通过执行重置和提交的组合命令git commit --amend来修改上一次提交。git commit --amend命令会重置上一次提交然后创建一个新的提交,这个新的提交具有与被重置的提交相同的提交注释。它执行git reset --soft HEAD^后,接着执行git commit --reedit-message加前一次提交(现在被重置)作为参数,这样的命令组合来完成。这意味着它将上一次提交的修改全部添加到当前缓冲区,然后提示输入一个新的提交注释。我最经常使用它来调整上一次提交时的拼写错误或者是漏掉的有用信息。

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部