《git高手之路》读书笔记

目录

ch02 项目历史管理

2.1 有向无环图

2.1.1 提交整个工作目录

每个开发人员可以访问自己的版本库克隆中任意文件的历史记录,也可以选择只获取版本库的部分历史记录(浅克隆或者只克隆特定分支),也可以只签出特定文件(稀疏签出),但是无法根据日期获取版本库克隆中特定的文件历史记录。第9章会详细介绍如何获取版本库克隆的部分内容,例如处理大量的视频文件时,开发人员需要用到的部分只是其中很小的一个子集。

2.1.2 引用的全名(分支和标签)

  1. 存放位置
  • 分支和标签位于.git/refs/heads/.git/refs/tags/目录下。
  • HEAD指针(通常是一个符号引用,例如refs/heads/master)一般存放于.git/HEAD目录下。
  • master分支存放于.git/refs/heads/master/目录下,而且它的全名叫refs/heads/master(换句话说,分支的命名空间是refs/heads/
  • origin/master一般会存放于.git/refs/remotes/origin/master文件下,并将refs/remotes/origin/master作为其全名
  • 当前的Git系统可以将标签和分支的信息存放于.git/packed-refs文件中,以避免处理大量的小文件。不过,活动引用采用的元数据格式比较宽松——一个文件对应一个引用。
  1. 存放内容
  • 宽松格式内容一般是分支上当前修订的SHA-1标识符。
  • 类似origin/master这样的远程跟踪分支,会记录远程版本库上master分支用户最后编辑的位置。

2.2 内部修订查询

2.2.1 大部分情况下,Git命令需要使用参数,默认情况下使用HEAD

2.2.2 引用名称消除歧义的有限匹配原则

  1. 顶层的标识符名称,例如HEAD
  2. 标签名称
  3. 本地分支
  4. 远程跟踪分支
  5. 远程默认分支

2.2.4 父引用

  • HEAD~3 表示曾祖父提交
  • HEAD^3 表示合并提交的父提交中的第三个

2.2.5 修订声明

git describe会基于最近的带附注标签生成HEAD的版本号。例如v1.0.4-14-g2414721t

2.2.6 reflog的简称:@{n}语法

2.2.7 上游远程跟踪分支

用户无法在远程跟踪分支上创建新的提交

@{u}代表当前本地分支的上游

2.2.8 根据提交信息查询修订

  1. git log执行后的界面用/bugfix查找任意引用中符合模式的提交
  2. git log 'next^/{fix bug}'表示从next引用中查询包含fix bug的提交
  3. 也可以用git log --grep=<模式>来实现

2.3 修订区间查询

2.3.2 双点符号

A..B是指在B可达的提交中排除A可达的提交

2.3.3 包含和排除修订

A..BB ^A的快捷方式

2.3.4 单个修订的修订区间,对于章鱼合并提交A而言:

  • A^@ 代表A的所有父提交(A^1,A^2,……,A^n)
  • A^! 代表的集合会将其所有祖先提交排除,可当做A --not A^@

2.3.5 三点符号

A...B表示可以到A或者B,但不能同时达到两者的提交。结合git log --left-right会显示出每个提交属于哪一边

在diff命令中使用修订区间标识符:

  • git diff A..B等价于git diff A B
  • git diff A...B等价于git diff $(git merge-base A B) B
  • git diff A^!等价于git diff A^ A

2.4 历史记录查询

2.4.1 git log -2将会显示最近两天在当前分支上的工作提交记录

2.4.2 元数据查询

  1. 时间段查询:--since、--until、--before、--after
  • 例如:git log --since=2.week
  1. 提交内容查询
  • 查询指定作者或提交者:–author、–committer
  • 搜索提交描述:–grep、-i(大小写敏感)、-F(字符串匹配)
  • Git默认对多个选项找出的集合进行逻辑或操作,如果想执行逻辑与操作,需要使用–all-match
  1. 父提交
  • git log --first-parent会只显示主线分支的一系列历史提交记录
  • –merges只显示合并提交、–no-merges只显示非合并提交
  • git log --max-parents=0显示所有根提交

2.4.3 修订内部变更查询

git log -S<string>会查找给定字符串实例的引用或者移除产生的差异。

git log -G<string>会查找diff

git blame查看但个文件已经引入的变更记录

2.5 单个文件历史记录

2.5.1 路径约束

git log -- <路径名>显示给定路径下的所有修订历史记录。支持通配符*

查询单个文件的历史版本时,系统并不会自动进行重命名。用户需要使用git log --follow <文件>,但不是在任何场景都能奏效,有时用户需要使用blame命令

git log -L 起始行,结束行:文件查看单个文件内部的历史演变记录

2.5.2 历史简化

看不懂

2.5.3 blame与重命名

blame的选项:

  • -L 限制范围
  • -M 追踪内容从一个文件剪切到另一个文件的记录
  • -C 追踪文件之间的拷贝、粘贴操作
  • -w 在跟踪时忽略空格

Git跟踪重命名的注意事项:

  • Git系统基于文件内容和路径的启发式相似解析,极个别情况下可能会失败
  • git diff命令默认没有启用重命名检测
  • git blame不仅可以处理整个文件的重命名,而且单个文件内部和多个文件之间的代码移动和粘贴操作也能显示出来。

2.6 bisect

git bisect run可自动化问题查找。为此,用户需要提供一个脚本来测试变更记录是否存在问题。返回0表示正常,非0表示存在问题,125是特殊的返回代码,表示当前签出的变更记录无法测试。例如:

   
1  
2 git bitsect start v1.5 v1.4
git bisect run ./test-error.sh  

2.7 日志的查询和格式化输出

2.7.1 预定义和自定义输出格式

作者是创建变更得人,而提交者是在原作者创建的变更的基础上进一步优化该变更的人。

2.7.2 git show 提交查看单个修订记录以及提交的元数据

选项很多

2.7.3 git shortlog用于统计贡献

2.7.4 git show 提交:路径可以用来显示目录和文件内容,比checkout方便

ch03

3.1.3 查看已提交的变更

git status --short --ignore简化输出格式

符号 含义
M 已修改
A 已添加
D 已删除
R 已重命名
C 已拷贝
无变化
?? 未跟踪
!! 已忽略

Git的统一diff格式

| | | | ——————————————————— | ———————————————————————————————————————————————————————————————————— | | 1
2
3
4
5
6
7
8 | diff –git a/预映射 b/提交映射
扩展首部信息,描述重命名
index 预映射SHA1..提交映射SHA1 100644
+++ a/预映射
— b/提交映射
@@ -<源文件起点>,<源文件行数> +<目标文件起点><目标文件行数> @@ 差异描述 \ No newline at end of file |

3.1.4 可查询的提交

隔离变更集。一种做法是先创建提交,然后再修复它,具体的细节可以参考第八章。
不过有时候,其中某些变更急需马上上线,同时其余的变更还有待进一步完善。

文件提交查询

最简单的情形就是这些不相关的变更分布于若干文件中:git commit <file>会忽略暂存区的内容,取而代之的是提交当前给定文件或目录

变更的交互式查询

如果文件中的变更都集中到了一起,可以尝试--interactive选项;其中的pacth自命令会让系统弹出一个Update»对话框

提交创建入门

git stash save --keep-index储藏不在暂存区中的变更,用于对暂存区进行测试

git stash pop --index恢复未暂存的变更

3.1.5 –amend

StGit 一个基于Git的提交历史批量管理工具

3.2.2 孤儿分支:git checkout --orphan gh-pages

3.2.3 分支的查询和切换

git branch --mergegit checkout -m都会在新建分支时合并工作目录内容,可能会有合并冲突。

3.2.6 检查某分支是否已经和其他分支合并过:git branch --contains <branch>

ch04

4.1 忽略文件

4.1.1 将文件刻意标记为不跟踪的

  • *.o包括file.o和obj/file.o
  • auto/将会匹配顶层的auto目录以及src/auto目录,单不匹配auto文件或链接
  • /TODO将会忽略当前层级的TODO文件,但是不会忽略子目录中的src/TODO
  • doc/**/index.html匹配doc下的任意index.html

4.1.4 用底层命令做高级忽略

4.2 文件属性

识别二进制文件和尾行转换

不同操作系统表示新行的方式

  • UNIX:\n
  • Windows:\n\r
  • Mac OS:\r

Git系统能够在版本库的提交操作中自动将换行符同义转换成\n,同时可以在签出状态下的工作目录中将他们转换为\n\r形式。

用户甚至可以通过文本属性决定一个文件是否应该遵循换行符的约定。如果文件的文本属性未设置,Git系统会使用core.autocrlf的设置来决定是否将它们当作text=auto的情况来处理。

4.2.1 配置Diff和merge

通过diff属性来比较二进制文件,有两个选项,就是告诉Git:

  1. 如何将一个二进制文件转换为文本格式
  2. 如何从二进制数据提取文本信息(例如元数据)

用户可以使用诸如catdoc这类程序,将Word文档中的二进制数据转换成文本,使用exiftool从JPEG图片中提取EXIF元数据。因为转换过程可能会非常慢,Git系统提供了一种机制,通过布尔属性cachetextconv来让用户决定是否缓存输出结果。

用户可以使用git show或者git cat-file -p --textconv查看经过textconv属性过滤的输出结果

4.2.2 文件转换(内容过滤)

当签出的文件符合模式时,过滤命令会将该文件作为标准输入,然后将标准输出结果更新工作目录中对应的文件。当声明一个命令时,用户可以使用%f符号替换过滤器处理的文件名。示例如下

  1. 让ODF文档在签入时文本化(解压缩为XML),在签出时重新压缩
  2. 对代码格式进行强制重排版。例如indent:用空格替换制表符缩进
  3. 强制文件转换。例如配合git-media存储大型二进制文件
  • 内容过滤的另外一个用途是存储一些无法直接在版本库中使用的内容,然后在将它们签出时转换为可用格式。
  • 这样的示例就有诸如使用gitattributes存储大型的二进制文件。在Git版本库外部,开发人员只需要用到该文件中的一小部分;而在版本库内部,只需要提供一个标识符,方便用户获取外部存储内容即可。这就是git-media的工作原理。
  1. 加密敏感信息
  • 用占位符替换某个应用程序必须的本体配置信息
  • 还需考虑配置文件本身的安全性,或者将实际的密码存放在一个外部的混淆脚本中,
  • 最好也建立一个预提交、预拉取和更新的钩子。

4.2.3 关键字替换表达式

Git系统内部唯一支持的关键字表达式时$Id$。

用户还可以自己编写支持相应过滤器的关键字表达式。例如把$Date$替换为文件的最后一次修改日期:

| | | | —————– | —————————————————————————————————– | | 1
2
3 | [filter “dater”] clean = sed -e ‘s/\$Date[^\$] *\$/\$Date\$/’ smudge = expand_date %f |

其中expand_date是扩展日期脚本git log --pretty=format:"%ad" "$1"

可用$Format:<PLACEHOLDERS>$占位符告诉git archive进行不可逆的关键字替换

4.2.4 其他内置属性

  • encoding
  • whitespace
  • export-ignore

4.2.5 属性宏定义

4.4 隐藏暂存变更

git stash --include-untracked暂存未跟踪的文件

4.4.1 使用git stash

有时无法顺利执行git stash pop,可以使用git stash branch 分支名新建分支