Git杂记

12 补丁

  • 补丁大致可以分为两类,一种是patch文件,另一种是修改前和修改后的文件对比包,这个对比包能够快速查看修改点的同时看到修改的上下文
  • git diff > patch
  • git diff --cached > patch
  • git diff branchname --cached > patch
  • git format-patch nodeA nodeB 两个节点之间的提交
  • git format-patch -1 nodeA -n表示要生成几个节点的提交
  • git format-patch HEAD^ 最近一次的提交节点的patch
  • 有两种应用补丁的方式: git apply, git am
  • 如果收到的补丁是用git diff或者其它Unix的diff命令生成,就该用git apply命令应用补丁, git apply是一个事务性操作的命令,要么所有的补丁都打上去,要么全部放弃,使用patch的话,可能一部分打上了一部分没有
  • 在实际应用补丁之前,可以先用git apply --check 查看是否能够干净顺利的应用到当前分支中
  • 如果贡献者也用Git,并且擅于制作format-patch补丁,使用git am合并工作将会非常轻松,这些补丁中除了文件差异外,还包含了作者信息和提交信息,鼓励使用format-patch生成补丁,传统的diff命令生成的补丁,只能使用git apply 处理。
  • 使用git am时发生冲突后,先编辑文件消除冲突,然后暂存文件,最后运行git am --resolved提交修正结果
  • git diff和git format-patch生成的patch一个重要不同之处,git diff只会产生一个提交,git format-patch会根据提交的节点一个节点一个patch

15 Git 原理

  • 从根本上讲,Git是一套内容寻址文件系统。从内部来看,Git是简单的key-value数据存储,它允许插入任意类型的内容,返回一个键值,通过该键值可以在任何时候再取出该内容,可以通过底层命令hash-object来示范这点,传一些数据给命令,它会将数据保存在.git目录并返回表示这些数据的键值。
  • 底层命令(Plumbing):这些命令主要不是用来从命令行手工使用的,更多的是用来为其它工具和自定义服务的
  • git init后,会创建一个.git目录,几乎所有Git存储和操作的内容都位于该目录下,如果要备份或者复制一个库,基本上将这一目录拷贝到其它地方就可以了
  • config 文件包含了项目特有的配置选项
  • info目录保存了一份不希望在.gitignore文件中管理的忽略模式的全局可执行文件
  • hooks目录包含了客户端或者服务端钩子脚本
  • objects目录存储所有数据内容
  • refs目录存储指向数据的提交对象的指针
  • HEAD文件指向当前分支
  • index文件保存暂存区域信息

16 Blob对象

  • git init
  • find .git/objects git初始化了objects目录,创建了pack和info子目录
  • echo 'test content' | git hash-object -w --stdin 参数-w指示hash-object命令存储对象,如果不指定这个参数该命令仅仅返回键值,--stdin指定从标准输入设备来读取内容,如果不指定需要制定一个要存储文件的路径。该命令会输出40个字符的校验和,这是个SHA-1哈希值。
  • find .git/objects -type f 可以在objects目录下看到一个文件,这就是git存储数据内容的方式,为每份文件生成一个文件夹,取得该内容与头信息的SHA-1校验和,创建以该校验和前两个字符为名称的字目录,并以剩下38个字符为文件名
  • git cat-file -p d67046 通过cat-file命令可以将数据返回,这个命令是查看git对象的瑞士军刀,-p参数可以让该命令输出数据类容的类型
  • echo 'version 1' > test.txt; git hash-object -w test.txt 创建一个文件,并把文件内容存储到数据库中
  • echo 'version 2' > test.txt; git hash-object -w test.txt 修改文件再次保存
  • find .git/objects -type f 数据库已经将文件的两个新版本连同一开始的内容保存下来了
  • git cat-file -p 83baae > test.txt; cat test.txt 恢复到第一个版本
  • git cat-file -p 1f7a7a > test.txt; cat test.txt 恢复到第二个版本
  • 需要记住的是几个版本的文件SHA-1值,存储的并不是文件名二十文件内容,这种对象类型为blob
  • git cat-file -t 1f7a7a 查看文件类型

17 Tree对象

  • Tree对象可以存储文件名,同时也允许存储一组文件,Git以一种类似UNIX文件系统但更简单的方式来存储内容,所有内容以tree对象或者blob对象存储,其中tree对象先对于UNIX中的目录,blob对象大致相当于inodes或文件内容,一个单独的tree对象包含一条或多条tree记录,每一条记录含有一个指向blob对象的SHA-1指针,并附有该对象权限模式、类型和文件名信息
  • git cat-file -p master^{tree} master^{tree}表示master分支上最新提交指向的tree对象
  • 创建tree对象,git根据暂存区或index创建并写入一个tree,要创建一个tree首先要通过一些文件赞成创建一个index
  • git update-index --add --cacheinfo 100644 83baae61804e65cc73a7201a7252750c76066a30 test.txt 人为的将test.txt文件的首个版本加到一个新的暂存区中,由于该文件原先并不在暂存区中,必须传入--add参数,由于添加的文件并不在单前目录下而是在数据库中,必须传入 --cacheinfo参数,同时制定为难模式,SHA-1值和文件名,100644表明是一个普通文件(100755可执行文件,120000符号链接)
  • git write-tree 将暂存区的内容写到一个tree对象,无需-w参数, 如果目录tree不存在,调用write-tree会自动根据index状态创建一个tree对象
  • git cat-file -t d8329f 查看对象类型
  • echo 'new line' > new.txt; git update-index test.txt; git update-index --add new.txt 根据test.txt的第二个版本以及一个新文件创建一个新的tree对象
  • git write-tree
  • git cat-file -p 0155eb 该tree对象包含两个文件记录,test.txt是早先的第二版
  • git read-tree --prefix=bak d8329f 把一个tree对象作为一个字目录加到该tree中,read-tree命令将tree对象读到暂存区,通过传一个--prefix参数给read-tree,将一个已有的tree对象作为一个子tree读到暂存区中
  • git write-tree
  • git cat-file -p 3c4e9c

18 commit对象

  • 现在有两个三个tree对象,指向了要跟踪的项目的不同快照,先前的问题依旧存在,必须记住SHA-1的值来获取这些快照,也没有关于谁什么时候保存了这些快照的信息
  • echo 'first commit' | git commit-tree d8329f 指定一个tree的SHA-1,使用该命令创建一个commit对象,如果没有任何前继提交对象,也可以指定
  • git cat-file -p 320d67 查看commit对象
  • echo 'second commit' | git commit-tree 0155eb -p 320d67
  • echo 'third commit' | git commit-tree 3c4e9c -p f474a3
  • 每一个commit对象都指向了创建的对象快照,现在可以通过git log来查看历史
  • git log --stat ea9ce9
  • git将文件头与原始数据拼接起来,并计算拼接后的新内容的SHA-1校验和

19 Git References

- 如果需要查看历史,需要记住哈希值,可以通过一个简单的名字来记录这些SHA-1值,我们称之为引用,可以在.git/refs目录下面找到这些包含SHA-1值的文件

  • find .git/refs
  • echo 'ea9ce9f566cf0065a7d50cd20f6a12a0314ef167' > .git/refs/heads/master 创建一个新的引用记住最后一次提交
  • find .git/refs -type f
  • git log --pretty=oneline master
  • git update-ref refs/heads/master ea9ce9f566cf0065a7d50cd20f6a12a0314ef167 建议使用这种安全的命令创建引用
  • git update-ref refs/heads/test f474a35cc04941e0faa015fb033a9dd990d9f331 Git中的一个分支就是一个指向某个工作版本的一条HEAD记录的指针或引用。
  • 当我们使用git branch branch-name时,基本上就是执行update-ref命令,把现在都在分支中最后一次提交的SHA-1值,添加到创建的分支的引用

20 HEAD标记

  • Git通过HEAD文件知道最后一次提交的SHA-1值,HEAD文件是一个指向你当前所在分支的引用标志符
  • cat .git/HEAD
  • git checkout test; cat .git/HEAD
  • git symbolic-ref HEAD 读取HEAD的值
  • git symbolic-ref HEAD refs/heads/test 设置HEAD的值

21 Tags对象

  • Tags对象非常像一个commit对象,包含一个标签,一组数据,一个消息和一个指针。主要区别是tag对象指向一个commit而不是一个tree,不会发生变化,永远指向一个commit
  • git update-ref refs/tags/v1.0 sha-1 创建一个lightweight
  • git tag -a v1.1 sha-1 -m 'test tag' 创建annotated,先创建一个tag对象,然后写入一个指向它而不是直接指向commit的reference
  • cat .git/refs/tags/v1.1
  • git cat-file -p sha-1

22 Remotes

  • git把最后一次推送到这个remote的每个分支的值记录在refs/remotes目录下
  • git往磁盘保存对象时默认使用的格式叫松散对象格式,git时不时的将这些对象打包到一个叫packfile的二进制文件以节省空间并提高效率,当仓库中有太多的松散对象,或者时手工调用git gc命令,或推送到远程服务器时,都会这样做。会生成一个packfile文件以及一个索引,packfile文件中包含了从文件系统中移除的对象,索引文件包含packfile的偏移量,便于快速定位任意一个指定对象。git打包对象时,会查找命名及尺寸相近的文件,并只保存文件不同版本之间的差异内容

你可能感兴趣的:(Git杂记)