Git笔记(25) 选择修订版本

  • 1. 单个修订版本
    • 1.1. 简短的 SHA-1
    • 1.2. 分支引用
    • 1.3. 引用日志
    • 1.4. 祖先引用
  • 2. 提交区间
    • 2.1. 双点
    • 2.2. 多点
    • 2.3. 三点

1. 单个修订版本

可以通过 Git 给出的 SHA-1 值来获取一次提交
不过还有很多更人性化的方式来做同样的事情


1.1. 简短的 SHA-1

提供 SHA-1 的前几个字符就可以获得对应的那次提交
当然提供的 SHA-1 字符数量不得少于 4 个,并且没有歧义
也就是说,当前仓库中只有一个对象以这段 SHA-1 开头

例如查看一次指定的提交
假设执行 git log 命令来查看之前新增一个功能的那次提交:

$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Bruce <Bruce@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800fixed refs handling, added gc auto, updated testscommit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Bruce <Bruce@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800Merge commit 'phedders/rdocs'commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Bruce <Bruce@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800added some blame and merge stuff

假设这个提交是 1c002dd....,如果想 git show 这个提交
下面的命令是等价的(假设简短的版本没有歧义):

$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d

Git 可以为 SHA-1 值生成出简短且唯一的缩写

如果在 git log 后加上 --abbrev-commit 参数,输出结果里就会显示简短且唯一的值
默认使用七个字符,不过有时为了避免 SHA-1 的歧义,会增加字符数:

$ git log --abbrev-commit --pretty=oneline
ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit

通常 8 到 10 个字符就已经足够在一个项目中避免 SHA-1 的歧义

比如 Linux 内核这个相当大的 Git 项目
目前有超过 90 万个提交,包含几百万个对象,也只需要前 11 个字符就能保证唯一性


1.2. 分支引用

指明一次提交最直接的方法是有一个指向它的分支引用
这样就可以在任意一个 Git 命令中使用这个分支名来代替对应的提交对象或者 SHA-1 值

例如,想要查看一个分支的最后一次提交的对象
假设 topic1 分支指向 ca82a6d ,那么以下的命令是等价的:

$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1

如果想知道某个分支指向哪个特定的 SHA-1,或者想看任何一个例子中被简写的 SHA-1
可以使用一个叫做 rev-parse 的 Git 探测工具
rev-parse 是为了底层操作而不是日常操作设计的
不过,有时想看 Git 现在到底处于什么状态时,它可能会很有用
可以在分支上执行 rev-parse

$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949

1.3. 引用日志

当在工作时, Git 会在后台保存一个引用日志(reflog
引用日志记录了最近几个月你的 HEAD 和分支引用所指向的历史

可以使用 git reflog 来查看引用日志

$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD

每当 HEAD 所指向的位置发生了变化
Git 就会将这个信息存储到引用日志这个历史记录里

通过这些数据,可以很方便地获取之前的提交历史
如果想查看仓库中 HEAD 在五次前的所指向的提交
可以使用 @{n} 来引用 reflog 中输出的提交记录。

$ git show HEAD@{5}

同样可以使用这个语法来查看某个分支在一定时间前的位置
例如,查看你的 master 分支在昨天的时候指向了哪个提交,你可以输入

$ git show master@{yesterday}

就会显示昨天该分支的顶端指向了哪个提交

这个方法只对还在你引用日志里的数据有用
所以不能用来查好几个月之前的提交
可以运行 git log -g 来查看类似于 git log 输出格式的引用日志信息:

$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Bruce <Bruce@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Bruce <Bruce@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800fixed refs handling, added gc auto, updated testscommit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Bruce <Bruce@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Bruce <Bruce@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800Merge commit 'phedders/rdocs'

值得注意的是,引用日志 只存在于本地仓库
一个记录你在你自己的仓库里做过什么的日志
其他人拷贝的仓库里的引用日志不会和你的相同

而新克隆一个仓库的时候,引用日志是空的,因为在仓库里还没有操作
如果是五分钟前克隆的仓库,那么它将不会有结果返回

$ git show HEAD@{2.months.ago}

只有在克隆了一个项目至少两个月时才会有用


1.4. 祖先引用

祖先引用是另一种指明一个提交的方式
如果在引用的 尾部 加上一个 ^, Git 会将其解析为该引用的上一个提交

假设提交历史是:

$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
*   d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list

可以使用 HEAD^ 来查看上一个提交,也就是 “HEAD父提交”:

$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Bruce <Bruce@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800Merge commit 'phedders/rdocs'

也可以在 ^ 后面添加一个数字
例如 d921970^2 代表 “d921970 的第二父提交”
这个语法只适用于合并(merge)的提交,因为合并提交会有多个父提交

第一父提交是你合并时所在分支,而第二父提交是你所合并的分支:

$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Bruce <Bruce@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800added some blame and merge stuff$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Tony <Tony+git@mjr.org>
Date:   Wed Dec 10 22:22:03 2008 +0000Some rdoc changes

另一种指明祖先提交的方法是 ~
同样是指向第一父提交,因此 HEAD~HEAD^ 是等价的

而区别在于在后面加数字的时候
HEAD~2 代表“第一父提交的第一父提交”,也就是“祖父提交”
Git 会根据你指定的次数获取对应的第一父提交

例如,在之前的列出的提交历史中,HEAD~3 就是

$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Medivh <Medivh@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500ignore *.gem

也可以写成 HEAD^^^,也是第一父提交的第一父提交的第一父提交:

$ git show HEAD^^^
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Medivh <Medivh@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500ignore *.gem

也可以组合使用这两个语法
可以通过 HEAD~3^2 来取得之前引用的第二父提交(假设它是一个合并提交)


2. 提交区间

之前的都是单次的提交,现在来看看如何指明一定区间的提交

当有很多分支时,这对管理你的分支时十分有用
可以用提交区间来 解决“这个分支还有哪些提交尚未合并到主分支?”的问题


2.1. 双点

最常用的指明提交区间语法是双点
这种语法可以让 Git 选出在一个分支中而不在另一个分支中的提交
例如,有如下的提交历史:

想要查看 experiment 分支中还有哪些提交尚未被合并入 master 分支
可以使用 master..experiment 来让 Git 显示这些提交
也就是在 experiment 分支中而不在 master 分支中的提交

为了使例子简单明了,使用了示意图中提交对象的字母来代替真实日志的输出
所以会显示:

$ git log master..experiment
D
C

即指出了experiment中与master不同的提交

反过来,如果想查看在 master 分支中而不在 experiment 分支中的提交
只要交换分支名即可:

$ git log experiment..master
F
E

这可以保持 experiment 分支跟随最新的进度以及查看即将合并的内容

另一个常用的场景是查看你即将推送到远端的内容:

$ git log origin/master..HEAD

这个命令会输出 在当前分支中而不在远程 origin 中的提交

如果执行 git push 并且当前分支正在跟踪 origin/master
git log origin/master..HEAD 所输出的提交就是会被传输到远端服务器的提交

如果留空了其中的一边, Git 会默认为 HEAD
例如,

$ git log origin/master..

将会输出与之前例子相同的结果


2.2. 多点

双点语法很好用,但有时候可能需要两个以上的分支才能确定所需要的修订
比如查看哪些提交是被包含在某些分支中的一个,但是不在你当前的分支上

Git 允许在任意引用 加上 ^ 字符或者 --not 来指明不希望提交被包含其中的分支
因此下列3个命令是等价的:

$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA

这个语法很好用,因为可以在查询中指定超过两个的引用

比如,想查看所有被 refArefB 包含的但是不被 refC 包含的提交
可以输入下面中的任意一个命令

$ git log refA refB ^refC
$ git log refA refB --not refC

这就构成了一个十分强大的修订查询系统
可以通过它来查看你的分支里包含了哪些东西


2.3. 三点

最后一种主要的区间选择语法是三点
这个语法可以选择出被两个引用中的一个包含 但又不被两者同时包含 的提交

再看看之前双点例子中的提交历史
如果想看 master 或者 experiment 中包含的但不是两者共有的提交
可以执行

$ git log master...experiment
F
E
D
C

即指出了experimentmaster中不同的提交

这和通常 log 按日期排序的输出一样,仅仅给出了4个提交的信息
这种情形下,log 命令的一个常用参数是 --left-right
它会显示每个提交到底处于哪一侧的分支
这会让输出数据更加清晰

$ git log --left-right master...experiment
< F
< E
> D
> C

有了这些工具,就可以十分方便地查看 Git 仓库中的提交


参考: git
以上内容,均根据git官网介绍删减、添加和修改组成


相关推荐:

Git笔记(24) 维护项目
Git笔记(23) 不同角色的贡献
Git笔记(22) 项目贡献要点
Git笔记(21) 分布式工作流程
Git笔记(20) 配置服务器


谢谢

Git笔记(25) 选择修订版本相关推荐

  1. 7.1 Git 工具 - 选择修订版本

    现在,你已经学习了管理或者维护 Git 仓库.实现代码控制所需的大多数日常命令和工作流程. 你已经尝试了跟踪和提交文件的基本操作,并且发挥了暂存区和轻量级的分支及合并的威力. 接下来你将学习一些 Gi ...

  2. Git笔记(32) 高级合并

    Git笔记(32) 高级合并 1. 合并冲突 1.1. 中断一次合并 1.2. 忽略空白 1.3. 手动文件再合并 1.4. 检出冲突 1.5. 合并日志 1.6. 组合式差异格式 2. 撤消合并 2 ...

  3. Git笔记(29) 搜索

    Git笔记(29) 搜索 1. 浏览代码和提交 2. Git Grep 3. Git 日志搜索 4. 行日志搜索 1. 浏览代码和提交 无论仓库里的代码量有多少 经常需要查找一个函数是在哪里调用或者定 ...

  4. Git笔记(28) 签署工作

    Git笔记(28) 签署工作 1. 签署工作 2. GPG 介绍 3. 签署标签 4. 验证标签 5. 签署提交 6. 使用环境 1. 签署工作 Git 虽然是密码级安全的,但它不是万无一失的 如果从 ...

  5. Git笔记(27) 储藏与清理

    Git笔记(27) 储藏与清理 1. 混乱的状态 2. 储藏工作 3. 创造性的储藏 4. 从储藏创建一个分支 5. 清理工作目录 1. 混乱的状态 有时,当在项目的一部分上已经工作一段时间后,所有东 ...

  6. Git之深入解析如何选择修订的版本

    一.前言 了解了管理或者维护 Git 仓库.实现代码控制所需的大多数日常命令和工作流程,尝试跟了踪和提交文件的基本操作,并且掌握了暂存区和轻量级地分支及合并的威力.如果想进一步对 Git 深入学习,可 ...

  7. 【Git笔记2】必知习惯和如何版本回退

    良好的习惯会让工作和生活如鱼得水,在使用git的时候有些必知习惯和概念你要get一下,总有些许失误,如:已经提交了不合适的修改到版本库时还没有把自己的本地版本库推送到远程,想要撤销本次提交,或者已经p ...

  8. git笔记(廖雪峰版本)

    git diff #是工作区(work dict)和暂存区(stage)的比较 git diff --cached #是暂存区(stage)和分支(master)的比较 Git比其他版本控制系统设计得 ...

  9. Git笔记(23) 不同角色的贡献

    Git笔记(23) 不同角色的贡献 1. 私有小型团队 2. 私有管理团队 3. 派生的公开项目 4. 通过邮件的公开项目 1. 私有小型团队 可能会遇到的最简单的配置是有一两个开发者的私有(闭源)项 ...

最新文章

  1. 编程疑难杂症の怪诞的【黄色警告】
  2. 「高并发秒杀」mysql只修改字段名称
  3. python导包顺序_2019-03-21 python导入包以及Python程序执行顺序理解
  4. Scheme 语言概要
  5. python 形参 拷贝_Day124:python中的变量、引用、拷贝
  6. 【Chocolatey】安装python3
  7. linux创建新进程就分配空间,linux几种创建进程的方法
  8. Kafka 慌了!这个中间件,要火了?
  9. 卷积神经网络学习笔记与心得(2)数据集
  10. STM32笔记记录2
  11. 黑php的称呼,“黑”起母校都是把好手!这些高校别称你绝对想不到
  12. Xshell 外观配置
  13. Android打造自定义通用popWindow
  14. 网络设备的区分(自顶向下)
  15. armlinux开发板用户自动登录
  16. 使用PIL改变图像分辨率
  17. 一步一步从原理跟我学邮件收取及发送 7.读取一行命令的实现
  18. 手机端,跟pc 链接qq 客服
  19. eventscheduler mysql_Mysql 中的事件 事件调度器(Event Scheduler)
  20. 坦克大战(Tank Battalion)------Java代码实现

热门文章

  1. 使用nginx作为代理实现动静分离
  2. HDU-2525 Clone Wars 模拟
  3. metasploit-***测试工具
  4. 操作系统(3)-线程的六大状态、基于代码实战的线程创建及六个常用方法
  5. 算法高级(18)-Redis Cluster选举机制
  6. redis安装包_redis安装与调优部署文档(WinServer)
  7. linux编译内核后无法进入,编译linux内核,ubuntu,x86的环境出现warning,然后就出现无法启动ubuntu...
  8. 上交AI研究院副院长马利庄:基于大数据的人脸识别技术进展与展望
  9. WebService入门案例
  10. 写给对前途迷茫的朋友