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

板块导航

浏览  : 1936
回复  : 0

[翻译] 《Git in Practice》翻译 第六章 & 技巧41 查看引用日志:git reflog

[复制链接]
zhaoyx的头像 楼主
发表于 2015-9-10 09:38:31 | 显示全部楼层 |阅读模式
本帖最后由 zhaoyx 于 2015-9-10 09:56 编辑

第六章 改写历史和灾难恢复


本章包括:
  • 浏览随着时间的推移,所有变更形成的历史记录
  • 将分支指针指向上一次提交(译者注:提交回滚)
  • 将某一次提交的父提交指向到其他提交(译者注:变基)
  • 强制改写远程仓库的历史记录
  • 重构某条分支的全部历史记录
  • 如何避免丢失工作成果



技巧4 中简要讨论了Git 改写版本库历史记录的能力。由于每个版本库都包含完整的历史记录,所以这种改写的能力从回滚单次提交一直延伸到改写版本库中每次提交的数据信息。我经常利用这种改写历史的方式,保证那些已经经过合并的分支在下次合并前仍具有一个清晰、易读的,由各个小提交组成的历史记录。你可以在13.2小节和第14章中得到更多相关信息。在探索如何改写历史记录之前,让我们从学习如何利用git reflog 来避免提交数据的丢失开始。


技巧41  查看包括改写在内的所有变化历史记录:git reflog

  回顾技巧3 我们知道,每个提交都会指向它的上一次提交(父提交),并且最终指向这条分支的初始提交。因此,分支的指针不仅可以用来引用当前提交,还可以引用之前的每一次提交。如果之前的提交发生了变化,无论以什么形式,它的哈希值都会随之改变。这个变化将依次影响它的每一个子孙提交。这为Git 提供了一种很好的保护来防止意外而改写历史记录,因为每个提交都有力的提供了一个校验值来保护截止到它之前的整条分支没有被修改。

  无论何时,只要提交指针(比如HEAD 指针或分支指针)发生了变化,Git 的reflog ( reference log 引用日志 ) 就会随之而更新。它包括你之前已经了解的那些没有涉及改写历史的操作,比如提交操作和变更分支操作。让我们来看看存放在版本库 reflog 里之前的那些操作记录。


问题
你希望查看HEAD 指针的引用日志。

解决
  • 切换到你的版本库目录:例如,
    cd /Users/mike/GitInPracticeRedux/
  • 执行 git checkout master
  • 执行 git reflog
应该产生类似如下输出:

清单 6.1 Reflog 输出

list6.1

list6.1




  • 显示你执行了git checkout 命令从v0.1-release 分支切换到了master 分支。这是最近一次引发HEAD 指针变化的动作。
  • 显示你执行力git commit命令在版本库中创建了一个新的提交,这个提交的说明是 Add release preface.
  • 显示你创建了一个新的提交用于恢复之前的一次提交,这次新提交的说明是 Revert "Advanced practice technique." 你会注意到这个记录的哈希值和记录1的哈希值一样,这是因为它们指向的都是master 分支的最后一次提交。

让我们和当前GitX 的输出做一下比较。你会发现图示6.1 中的哈希值和git reflog 的输出是相匹配的。
  • 在v0.1-release 分支上面的最后一次提交(a8200e1, HEAD@{1})
  • 在v0.1-release 分支上面倒数第二次提交(dfe2377, HEAD@{2})
  • 在master 分支上的最后一次提交(3e3c417, HEAD@{0}, HEAD@{3})

pic6.1

pic6.1



回顾1.7 小节 ,你已经了解到了 HEAD@{0} 是引用的另外一种形式,它可以被用作命令的参数,例如 git log ,来查看此次引用指向提交的状态。但我总是倾向于使用哈希值,因为哈希值总是对应着特定的提交,而绝不会发生变化(即使历史记录被改写也不会),但是例如像 HEAD@{0} 这样的形式,一旦任何动作影响了HEAD 指针的指向,它就会随之发生改变。

  还记的技巧23 介绍的 git stash 吗?当你使用git stash 命令的时候,他们是不会显示在git reflog 输出中的。因此,一旦你学习了本章节关于改写历史记录的内容以后,相对过分依赖git stash ,我还是愿意推荐你创建提交并在以后改写他们。

  至此你已经了解了如果通过查看 reflog 来了解 HEAD 指针的变化情况。


讨论

  命令 git refloggit log --walk-reflogs --abbrev-commit --pretty=oneline 的别名。因此 git reflog 同样可以使用 git log 的所有标记,例如 --max-count--patch .你可以通过技巧30 来了解 git log 规定格式的标记。

  像
git log , git reflog 这样可以将一条引用作为最终参数的命令。如果没有指定,参数的默认值将是 HEAD. 例如,如果你想查看 master 分支过去是如何演变的,你可以使用 git reflog master 命令。

版本库之间是否共享 reflog? reflog 是区分版本库的。当你执行git push 时并不会将它共享到其他版本库,执行 git fetch 时也不会抓取到其他版本库的 reflog .因此你只可以用它来查看在你本地版本库执行的动作。要记住,当你在改写历史记录时:你可以通过当前的机器轻松查看到之前的状态,但是通过其他机器是不能的。


6.1 避免发生灾难和灾难恢复
尽管本章自始至终讲述的都是“改写历史”,但命令 git reflog 可以轻松恢复的只是针对提交的操作(例如 git rebase)而且是90天之内发生的,而不是针对工作目录的操作(例如 git reset --hard 命令对未提交的修改造成的影响)。

  因此,避免数据丢失的主要规则是尽早提交频繁提交。既然你现在已经知道了如何改写历史记录,你就应该把提交操作当成类似其他软件的保存操作,而不再是一个合并内容的操作。无论何时,只要你写了任何有价值的内容,而你又不想丢失,你就应该提交它们,然后将来通过改写历史把它们分解成小的、具有可读性的提交。

  在使用Git 过程中最容易(也是最常见的)丢失数据的情况是,你还没有提交,却不小心执行了 git reset --hard 或 git checkout --force 命令,数据就这样被覆盖掉了。当然在你工作的时候规律性的备份你的版本库目录(例如在OS X平台上使用时光机这类软件)可以或多或少的避免一些类似事情发生,但是一般来讲,更频繁的提交你的改动是一个更好的选择。

  另外一种通过Git 保护你数据安全的方式是有规律的将你工作分支推送到远程版本库,当然这样做的前提是你们已经达成一致没有其他人会向这条分支进行提交。如果你们已经达成一致没有其他人会向这些工作分支进行提交的话,那么你也可以像在本地分支改写一样,在这些远程工作分支上进行改写和强制推送。这意味着这些改变将安全的保存在远程版本库里,并且可以被任何人使用git fetch 命令下载到各自本地版本库中。显然一旦你的硬件发生故障,这样的方式就会对你很有帮助;你可以在远程版本库的分支中找回你的数据。

  如果最坏的情况发生,你有一些重要的数据还没有推送提交到你的版本库,你的磁盘却已经发生损坏,那么你可以使用git fsck这个工具。它会验证你版本库的完整性,并且将所有它能发现的丢失和损坏的对象都显示出来。你可以删除并从你的备份中恢复这些损坏的对象,或者看看其他用户的版本库中是否包含同样的对象。希望这些损坏的恰恰不是那些你近期工作中想要恢复的对象。

相关帖子

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

本版积分规则

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