一、底层命令 (Plumbing) 和高层命令 (Porcelain)
1.由于 Git 一开始被设计成供 VCS 使用的工具集而不是一整套用户友好的 VCS,它还包含了许多底层命令,这些命令用于以 UNIX 风格使用或由脚本调用。这些命令一般被称为 "plumbing" 命令(底层命令),其他的更友好的命令则被称为 "porcelain" 命令(高层命令)。
2.当你在一个新目录或已有目录内执行 git init 时,Git 会创建一个 .git 目录,几乎所有 Git 存储和操作的内容都位于该目录下。如果你要备份或复制一个库,基本上将这一目录拷贝至其他地方就可以了。本章基本上都讨论该目录下的内容。该目录结构如下:
$ ls
   HEAD
   branches/
   config
   description
   hooks/
   index
   info/
   objects/
   refs/

二、Git 对象
1.首先初使化一个 Git 仓库并确认 objects 目录是空的:
$ mkdir test
   $ cd test
   $ git init
   Initialized empty Git repository in /tmp/test/.git/
   $ find .git/objects
   .git/objects
   .git/objects/info
   .git/objects/pack
   $ find .git/objects -type f
   $
2.我们往这个 Git 数据库里存储一些文本:
$ echo 'test content' | git hash-object -w --stdin
   d670460b4b4aece5915caf5c68d12f560a9fe3e4
3.现在可以查看到 Git 已经存储了数据:
$ find .git/objects -type f
   .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
4.通过 cat-file 命令可以将数据内容取回。该命令是查看 Git 对象的瑞士军刀。传入 -p 参数可以让该命令输出数据内容的类型:
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4
    test content
    5.tree (树) 对象
    $ git cat-file -p master^{tree}
   100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
   100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
   040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
6.commit (提交) 对象,通过 cat-file 查看新 commit 对象:
$ git cat-file -p fdf4fc3
7.对象存储

三、Git References
1.每当你执行 git branch (分支名称) 这样的命令,Git 基本上就是执行 update-ref 命令,把你现在所在分支中最后一次提交的 SHA-1 值,添加到你要创建的分支的引用
2.HEAD 标记
a.如果你看一下这个文件,通常你将会看到这样的内容:
$ cat .git/HEAD
   ref: refs/heads/master
b.如果你执行 git checkout test,Git 就会更新这个文件,看起来像这样:
$ cat .git/HEAD
   ref: refs/heads/test
c.当你再执行 git commit 命令,它就创建了一个 commit 对象,把这个 commit 对象的父级设置为 HEAD 指向的引用的 SHA-1 值。
d.你也可以手动编辑这个文件,但是同样有一个更安全的方法可以这样做:symbolic-ref。你可以用下面这条命令读取 HEAD 的值:
$ git symbolic-ref HEAD
   refs/heads/master
e.你也可以设置 HEAD 的值:
$ git symbolic-ref HEAD refs/heads/test
   $ cat .git/HEAD
   ref: refs/heads/test
f.但是你不能设置成 refs 以外的形式:
$ git symbolic-ref HEAD test
   fatal: Refusing to point HEAD outside of refs/
3.Tags
a.Tag 对象非常像一个 commit 对象——包含一个标签,一组数据,一个消息和一个指针。最主要的区别就是 Tag 对象指向一个 commit 而不是一个 tree。它就像是一个分支引用,但是不会变化——永远指向同一个 commit,仅仅是提供一个更加友好的名字。
b.Tag 有两种类型:annotated 和 lightweight 
c.在 Git 的源代码里,管理者添加了一个 GPG 公钥(这是一个 blob 对象)对它做了一个标签。你就可以运行:
$ git cat-file blob junio-gpg-pub
4.Remotes,是 remote reference(远程引用)
a.你可以添加一个叫做 origin 的 remote 然后把你的 master 分支推送上去:
$ git remote add origin git@github.com:schacon/simplegit-progit.git
   $ git push origin master
b.然后查看 refs/remotes/origin/master 这个文件,你就会发现 origin remote 中的 master 分支就是你最后一次和服务器的通信。
$ cat .git/refs/remotes/origin/master

四、Packfiles
1.Git 往磁盘保存对象时默认使用的格式叫松散对象 (loose object) 格式。Git 时不时地将这些对象打包至一个叫 packfile 的二进制文件以节省空间并提高效率。当仓库中有太多的松散对象,或是手工调用 git gc 命令,或推送至远程服务器时,Git 都会这样做。手工调用 git gc 命令让 Git 将库中对象打包并看会发生些什么:
$ git gc
2.git verify-pack 命令用于显示已打包的内容:
$ git verify-pack -v .git/objects/pack/pack-7a16e4488ae40c7d2bc56ea2bd43e25212a66c45.idx

五、The Refspec
1.Refspec 的格式是一个可选的 + 号,接着是 <src>:<dst> 的格式,这里 <src> 是远端上的引用格式, <dst> 是将要记录在本地的引用格式。可选的 + 号告诉 Git 在即使不能快速演进的情况下,也去强制更新它。
2.缺省情况下 refspec 会被 git remote add 命令所自动生成, Git 会获取远端上 refs/heads/ 下面的所有引用,并将它写入到本地的 refs/remotes/origin/.
3.推送 Refspec
a.如果QA组成员想把他们的 master 分支推送到远程的 qa/master 分支上,可以这样运行:
$ git push origin master:refs/heads/qa/master
b.如果他们想让 Git 每次运行 git push origin 时都这样自动推送,他们可以在配置文件中添加 push 值:
[remote "origin"]
   url = git@github.com:schacon/simplegit-progit.git
   fetch = +refs/heads/*:refs/remotes/origin/*
   push = refs/heads/master:refs/heads/qa/master
c.删除引用
$ git push origin :topic 

六、传输协议
1.哑协议:Git 基于HTTP之上传输通常被称为哑协议,这是因为它在服务端不需要有针对 Git 特有的代码。
2.智能协议
a.上传数据:为了上传数据至远端, Git 使用 send-pack 和 receive-pack 进程。这个 send-pack 进程运行在客户端上,它连接至远端运行的 receive-pack 进程。
b.下载数据:当你在下载数据时, fetch-pack 和 upload-pack 进程就起作用了。客户端启动 fetch-pack 进程,连接至远端的 upload-pack 进程,以协商后续数据传输过程。
c.如果你透过SSH使用获取功能, fetch-pack 会像这样运行:
$ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'"

七、维护及数据恢复
1.维护
a.Git 会不定时地自动运行称为 "auto gc" 的命令
b.可以手工运行 auto gc 命令:
$ git gc --auto
2.数据恢复
a.首先查看一下当前的仓库状态:
$ git log --pretty=oneline
b.接着将 master 分支移回至中间的一个 commit:
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
c.任何时间运行 git reflog 命令可以查看当前的状态:
$ git reflog
d.使用 git fsck 工具,该工具会检查仓库的数据完整性。如果指定 --ful 选项,该命令显示所有未被其他对象引用 (指向) 的所有对象:
$ git fsck --full
3.移除对象
a.如果运行 git gc,所有对象会存入一个 packfile 文件;运行另一个底层命令 git verify-pack 以识别出大对象,对输出的第三列信息即文件大小进行排序,还可以将输出定向到 tail 命令,因为你只关心排在最后的那几个最大的文件:
$ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3
b.若给 rev-list 命令传入 --objects 选项,它会列出所有 commit SHA 值,blob SHA 值及相应的文件路径。可以这样查看 blob 的文件名:
$ git rev-list --objects --all | grep 7a9eb2fb
c.接下来要将该文件从历史记录的所有 tree 中移除。很容易找出哪些 commit 修改了这个文件:
$ git log --pretty=oneline --branches -- git.tbz2
d.必须重写从 6df76 开始的所有 commit 才能将文件从 Git 历史中完全移除。这么做需要用到第 6 章中用过的 filter-branch 命令:
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^..
e.在进行 repack 前需要将所有对这些 commits 的引用去除:
$ rm -Rf .git/refs/original
   $ rm -Rf .git/logs/
   $ git gc
f.看一下节省了多少空间。
$ git count-objects -v
count: 8
   size: 2040
   in-pack: 19
   packs: 1
   size-pack: 7
   prune-packable: 0
   garbage: 0
g.如果真的要完全把这个对象删除,可以运行 git prune --expire 命令。
Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐