Git-基本概念
2014-05-30 00:00
190 查看
Git Object
git object,git 对象,用于存放信息,并且具有一定的结构.每一个 git object 都被 40 位的 SHA1 值唯一索引.即可以通过 40 位 SHA1 值来访问对应的 git object.
不同类型的 git object
commit object,用于保存一个提交相关的信息,如提交者,提交时间,提交的说明...,commit object 的结构如:$ git cat-file -p master # 显示 master 引用的提交对象的内容. tree b9335367560fcbb14669227c427d3020cb10362c # 该提交对象对应的 tree object. parent 11176be04831f5cd8c8947b4b0eaa182595ad069 # 该 commit object 的父提交对象 author WangXiaoWei <1258941862@qq.com> 1401371236 +0800 # 提交作者 committer WangXiaoWei <1258941862@qq.com> 1401428713 +0800 # 提交者 新增 protect 子命令 # 提交的注释信息.
tag object,标签对象,保存着标签相关信息,结构如:
$ git cat-file -t afa17d1 tag # afa17d1 指向着一个 tag object. $ git cat-file -p afa17d1 object 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 # 该 tag object 引用的 git object 的 SHA1 值. type commit # 用于表明上述 object 的类型,是一个 commit object. tag v3.8-rc7 # 该 tag object 的名称. tagger Linus Torvalds <torvalds@linux-foundation.org> 1360358456 +1100 # 创建该 tag object 的作者以及时间. Linux 3.8-rc7 # 该 tag object 的注释.
blob object,文件对象,保存着一个文件的完整内容.如:
$ git cat-file -t 6f109854c5d4 blob # 表明 6f109854c5d4 指向着一个 blob object $ git cat-file -p 6f109854c5d4 # 显示 blob object 的内容,就是文件内容. /** * @file . * Created on: 2014年5月28日 下午3:20:44 Author: WangXiaoWei * 包含了 main.cc 函数中可能会使用到的函数原型. */ #ifndef MMAP_MAIN_H_ #define MMAP_MAIN_H_ int parse_cmdline(char *cmdline,char **argv,int argv_len); int get_show_args(int argc,char **argv,int *off,int *len); int get_unmap_args(int argc,char **argv,int *off,int *len); int get_modify_args(int argc,char **argv,int *off,char **str); int get_protect_args(int argc,char **argv,int *off,int *len,int *prot); int str2int(const char *str,int *output); char* prot2str(int prot,char *buf); #endif /* MMAP_MAIN_H_ */
tree object,目录树信息,保存着在该目录下子目录,与文件的信息.其结构如下:
对于子目录,则存放着子目录名,子目录的状态信息,子目录对应的 tree object 的 SHA1 值.
对于文件,则存放着文件名,文件的状态信息(如: 文件的最后一次修改时间...),文件对应的 blob object 的 SHA1 值
$ git cat-file -t 4c58c57 tree # 表明 4c58c57 指向着一个 tree object. $ git cat-file -p 4c58c57 # 该 tree object 的内容 100644 blob 42fa0d5626a9560d74d16b2df5250b300543b67e .gitignore # 文件 100644 blob c596b74b29d532246b3646086c77381076ad3c15 MAINTAINERS # 文件 100644 blob 8a8440a3578e1d3b2fde55625fbc506a5d2979e4 Makefile # 文件 100644 blob a24ec89ba4420ad38e8848422ca5f69baa5ffe1c README # 文件 040000 tree f1ef1ece9e8b963629398f632f041a8e94ac536d arch # 子目录 040000 tree 0e2802a3add8c60f0d2f57b6662cdd2707a613d3 block # 子目录 040000 tree 62f2007ef4f418c65b33dec22f767ae7fd5ee7e2 crypto # 子目录
访问 git object
最基本,最底层的访问方式: 通过 40 位 SHA1 值来访问 git object.# 通过 40 位 SHA1 值来访问其对应的 git object $ git cat-file -t 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 # 指向的 git object 的类型. commit $ git cat-file -s 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 # 指向的 git object 的尺寸. 254 $ git cat-file -p 836dc9e3fbbab0c30aa6e664417225f5c1fb1c39 # 指向的 git object 的内容. tree 8d490c389d08035d6c1a926d9b89b3b07f0edf7d parent 39923134885759405e64cb9491a273a2bcd356ed author Linus Torvalds <torvalds@linux-foundation.org> 1360358439 +1100 committer Linus Torvalds <torvalds@linux-foundation.org> 1360358439 +1100 Linux 3.8-rc7
采用部分的 SHA1 值,不必将 40 位的哈希值写全.即只采用开头 n 位的哈希值(至少 4 位),如:
$ git cat-file -p 836dc9 # 使用开头 6 位 SHA1 值. tree 8d490c389d08035d6c1a926d9b89b3b07f0edf7d parent 39923134885759405e64cb9491a273a2bcd356ed author Linus Torvalds <torvalds@linux-foundation.org> 1360358439 +1100 committer Linus Torvalds <torvalds@linux-foundation.org> 1360358439 +1100 Linux 3.8-rc7
对于 commit object ,可以:
使用 ^ 访问该 commit object 的父提交.使用 ~n 访问该 commit object 的祖先提交,如:
# master~2 等同于 master^^ $ git rev-parse master^^ 68cb363a4ddc335fddf6e2ccb03e4a907ba7afbf $ git rev-parse master~2 68cb363a4ddc335fddf6e2ccb03e4a907ba7afbf
当一个 commit object 具有多个父提交时,使用 ^n 访问该 commit object 的第 n 个父提交.如:
$ git cat-file -p master # 使用 master 来访问其引用的 commit object. tree 4c58c5747529b74502352b185515af43e26c0666 parent 77d92784b46549e00f7b99794cd566045ded62ba parent cf01f4eef9fe367ec0d85b38dd7214e29e376cdb ... $ git rev-parse master^1 # 第 1 个父提交 77d92784b46549e00f7b99794cd566045ded62ba $ git rev-parse master^2 # 第 2 个父提交 cf01f4eef9fe367ec0d85b38dd7214e29e376cdb
使用 ^{tree} 来访问该 commit object 对应的 tree object.
$ git cat-file -p master tree b9335367560fcbb14669227c427d3020cb10362c parent 11176be04831f5cd8c8947b4b0eaa182595ad069 author WangXiaoWei <1258941862@qq.com> 1401371236 +0800 committer WangXiaoWei <1258941862@qq.com> 1401428713 +0800 新增 protect 子命令 $ git rev-parse master^{tree} b9335367560fcbb14669227c427d3020cb10362c
使用 :path 来访问路径为 path 的 blob object/tree object,此时 path 为相对路径,相对于工作区的路径.
# lib 为相对路径,其完整路径为:~/CCProject/linux/lib ~/CCProject/linux$ git cat-file -t master:lib tree # 其完整路径为: ~/CCProject/linux/crypto/cryptd.c ~/CCProject/linux$ git cat-file -t master:crypto/cryptd.c blob
对于 tag object,可以:
使用 ^{} 来访问标签 tag 对应的 commit objec,如:$ git cat-file -p v3.9 object c1be5a5b1b355d40e6cf79cc979eb66dafa24ad1 type commit tag v3.9 tagger Linus Torvalds <torvalds@linux-foundation.org> 1367195769 -0700 Linux 3.9 $ git rev-parse v3.9^{} # v3.9 对应的 commit object. c1be5a5b1b355d40e6cf79cc979eb66dafa24ad1
对于 tree object,可以:
使用 :path 来访问 tree object 中 path 对应的 blob object/tree object.此时 path 为相对路径,相当于 tree object 的路径.~/CCProject/linux$ git cat-file -p master^{tree} 040000 tree f1ef1ece9e8b963629398f632f041a8e94ac536d arch ... ~/CCProject/linux$ ls arch/ alpha arm avr32 c6x frv ia64 m32r metag mips openrisc powerpc score sparc um x86 arc arm64 blackfin cris hexagon Kconfig m68k microblaze mn10300 parisc s390 sh tile unicore32 xtensa #frv 是一个相对路径,相对于 f1ef1ece,其对应的完整路径为: ~/CCProject/linux/arch/frv. ~/CCProject/linux$ git cat-file -t f1ef1ece:frv tree ~/CCProject/linux$ git cat-file -t f1ef1ece:Kconfig blob
引用
引用,就是一个文件,文件内容为它引用的 git object 的 SHA1 值.# master 是一个引用,其对应的文件: .git/refs/heads/master $ cat .git/refs/heads/master 48549924cecf749cbfbf697f6ee34f06c6db26a1
可以通过引用的全名来访问引用,也可以在不引起歧义下仅使用引用名,如:
$ git rev-parse refs/heads/master # master 引用的全名 48549924cecf749cbfbf697f6ee34f06c6db26a1 $ git rev-parse master # 不引起歧义 48549924cecf749cbfbf697f6ee34f06c6db26a1 $ git tag -m"Test" master # 创建一个名为 master 的标签 $ git rev-parse refs/tags/master 85176002003cd5f11c349c61c9122e40c64d6578 $ git rev-parse master # 引起歧义,因为 master 既可以是 refs/heads/master,也可以是 refs/tags/master warning: refname 'master' is ambiguous. 85176002003cd5f11c349c61c9122e40c64d6578
常见引用
.git/refs/ 引用空间,该目录下所有文件都是引用.heads/ 该目录下所有文件都是对 commit object 的引用,又被称为分支.
tags/ 该目录下所有文件都是对 commit object/tag object 的引用,又被称为标签.
stash 该文件是对进度列表的引用(描述的不准确).
remotes/ 该目录下存放着对远程版本库上分支的引用.
远程版本库1 该目录下存放着引用文件,都是对远程版本库1的分支的引用.
远程版本库2 该目录下存放着引用文件,都是对远程版本库2的分支的引用.
...
.git/refs/remotes/origin: 总用量 24 -rw-r--r-- 1 root root 32 5月 2 23:58 HEAD -rw-r--r-- 1 root root 41 5月 30 18:41 maint # 对远程版本库 maint 分支的引用 -rw-r--r-- 1 root root 41 5月 30 18:41 master -rw-r--r-- 1 root root 41 5月 30 18:41 next -rw-r--r-- 1 root root 41 5月 30 18:41 pu -rw-r--r-- 1 root root 41 5月 30 18:41 todo
.git/HEAD 一个引用文件,若当前处于分离头指针的状态,则 HEAD 文件中记录着当前最后一次提交对应的提交 ID.否则指向着当前所处的分支.
$ cat .git/HEAD ref: refs/heads/master # 表明当前处于 master 分支. $ git checkout origin/next # 此时会进入分离头指针状态. $ cat .git/HEAD 5318336450357c9ecf6ffed2ca846e4c22dbfb7c # 表明当前处在分离头指针状态
分离头指针
进入分离头指针状态,就像处在一个无名分支上,此时可以进行在常规分支下进行的操作,如:检查,测试,提交.当进入分离头指针状态时,git 会进行提示,并且此时从 git status 的输出中也可以看的出来.
当使用 git checkout <branch> 切换到一个其他分支上时,在无名分支下所做的修改与提交会被丢弃.
使用 git checkout -b <branch> 创建一个新的分支来追踪当前提交,如:
$ git checkout 49a5d7 Note: checking out '49a5d7'. 你正在处于分离头指针的状态. 如果你要是想创建一个新的分支来追踪提交,你可以使用: git checkout -b new_branch_name HEAD 目前位于 49a5d7d... 新增 protect 子命令 $ git status HEAD detached at 49a5d7d # 表明此时处于分离头指针的状态 nothing to commit, working directory clean $ git checkout -b Test_Branch # 创建一个新的分支来追踪提交. 切换到一个新分支 'Test_Branch' $ git branch * Test_Branch master
文件忽略
文件忽略,对于 git 而言,忽略的文件就像从不存在一样!如:$ git status 位于分支 master Untracked files: .cproject .project Debug/ checksum.cc log mmap test.cc test.h write.cc nothing added to commit but untracked files present (use "git add" to track) $ kate .gitignore # 编辑 .gitignore 文件,输入以下内容: # Debug/ # .* $ git status 位于分支 master Untracked files: # 可以看出设置为忽略的文件,没有再出现 checksum.cc log mmap test.cc test.h write.cc nothing added to commit but untracked files present (use "git add" to track) # 被忽略的文件也不会被 add 到. $ git add -Av add 'checksum.cc' add 'log' add 'mmap' add 'test.cc' add 'test.h' add 'write.cc'
当文件已经添加到暂存区后,忽略将会无效.
实现文件忽略:
通过编写 .gitignore 文件.通过将 .gitignore 添加到版本库中,可以让文件忽略在他人的工作区也有效,即因为 .gitignore 位于版本库中,所以当他们 git clone 版本库时,也会将 .gitignore 下载下来,所以文件忽略生效.
也可以在 .gitignore 文件中忽略自身,如上.这样 .gitignore 就不会加入到版本库中,就成为了本地独享式忽略文件.
.gitignore 文件只对当前目录及其子目录有效.
$ git status 位于分支 master Untracked files: World a/World nothing added to commit but untracked files present (use "git add" to track) $ kate .gitignore # 输入: # .* # World $ git status 位于分支 master # 文件 World a/World 均被忽略 nothing to commit, working directory clean $ mv .gitignore a/ $ git status 位于分支 master Untracked files: # 仅 a/World 被忽略,即 .gitignore 只对当前目录及其子目录有效 World nothing added to commit but untracked files present (use "git add" to track)
通过编写 .git/info/exclude 文件.
只能是独享式忽略,并且仅局限在一个版本库中.
~/Gi$ cat .git/info/exclude .* World ~$ git clone Gi/ Gi1 正克隆到 'Gi1'... 完成。 Checking connectivity... done # 并没有将 Gi 版本库中的 .git/info/exclude 内容下载下来 Gi1$ cat .git/info/exclude git ls-files --others --exclude-from=.git/info/exclude ...
通过设置 core.excludesfile 属性.
只能是独享式忽略,不过可以通过 git config --system core.excludesfile 来作用于本地所有的版本库中.
.gitignore 忽略文件的编写
以'#'开头的行为注释行.每行放置一个模式,满足模式的文件/目录将被忽略.可用的通配符:
* 表示任意多的任意字符; ? 表示任意一个字符;
如果模式最后面是'/',则表明满足模式的目录,而不忽略满足模式的文件.
如果模式的最前面是'!',则表示不忽略匹配该模式的文件/目录.
如果模式的最前面是'/',则表明仅忽略当前目录下满足模式的文件/目录,而不忽略子目录下满足模式文件/目录.