前言java
这是介绍git的第二篇博客,第一篇博客 http://zhangfengzhe.blog.51cto.com/8855103/1720049 初步介绍了git,下面咱们来对git进行些深刻的介绍。git
COMMIT对象
bash
在git中有好多种对象,COMMIT就是其中一种。HISTORY完整的叫法,应该是COMMIT HISTORY。ide 咱们先来看一个图: HEAD如同游标似的,指向最新提交的COMMIT对象spa 那么这个COMMIT对象里面到底包含了什么东西呢?3d COMMIT对象包含了下面一些重要信息:版本控制
若是咱们想取得前一个COMMIT对象,那该怎么作呢? 当前COMMIT对象的前一个COMMIT 用HEAD~ OR HEAD~1表示 HEAD~~ 等价于 HEAD~2 [root@localhost hadoop]# git log commit 54cf628bf72462bc37804fcc5df3850eacf9cf7e Author: zhangfengzhe <zhangfengzhe1990@163.com> Date: Sat Dec 5 18:12:13 2015 -0800 bug fix commit b714e9882e287957061ce6a06bca26092a0eea48 Author: zhangfengzhe <zhangfengzhe1990@163.com> Date: Sat Dec 5 18:05:56 2015 -0800 commit log命令用于查看历史提交记录。 每个COMMIT都有一个编号,如同那个字符串54cf628bf72462bc37804fcc5df3850eacf9cf7e,其实就是一个HASH码。 [root@localhost hadoop]# git cat-file -t HEAD commit [root@localhost hadoop]# git cat-file -p HEAD tree 1aabc54505caf74bbe716649a974484cdc954438 parent b714e9882e287957061ce6a06bca26092a0eea48 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 bug fix [root@localhost hadoop]# git cat-file -p HEAD~ tree bffc7fb973539b5560cafbea421b65c7de5630ce parent 9ea1deaa2bafdf6061ff1dcffdf8ede25b3c0e73 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 commit [root@localhost hadoop]# git cat-file -p HEAD~~ tree ac2e6ed4de163a6fd92f88bd1516728fc1f7b9a9 parent b1a45f0a85ff0e720f240c978a31f7afc2a812b5 author zhangfengzhe <zhangfengzhe1990@163.com> 1449366049 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449366049 -0800 commit [root@localhost hadoop]# git cat-file -p HEAD~2 tree ac2e6ed4de163a6fd92f88bd1516728fc1f7b9a9 parent b1a45f0a85ff0e720f240c978a31f7afc2a812b5 author zhangfengzhe <zhangfengzhe1990@163.com> 1449366049 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449366049 -0800 commit [root@localhost hadoop]# 注意: git cat-file -p XXX eq git show XXX git cat-file -t XXX -p表示打印内容,-t表示取得类型,那么这个XXX,其实是一个标示,能够是HEAD,HEAD~N,或者HASM码什么的,甚至能够是不完整的HASH均可以。 [root@localhost hadoop]# git cat-file -t ac2e tree [root@localhost hadoop]# git cat-file -p ac2e 100644 blob 5e6618e52979f6f581ce848dda15a0bfc24bac24HelloWorld.java 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391delete.me 100644 blob 4ca70693ed50750b52b2a5d1c289adc554a251aflove.txt 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391t1.txt [root@localhost hadoop]# 经过上面的打印 ,其实也清楚了,文件其实也是一个BLOB对象,目录其实也就是一个TREE对象,也看到了他们的HASH码。 那么完整的示意图以下: |
tree-ish表达式
咱们先来看一下.git目录的结构: [root@localhost hadoop]# ll -A total 36 -rw-r--r-- 1 root root 26 Dec 5 18:12 delete.me drwxr-xr-x 8 root root 4096 Dec 5 18:12 .git -rw-r--r-- 1 root root 37 Dec 5 18:11 HelloWorld.java -rw-r--r-- 1 root root 31 Dec 5 06:42 love.txt -rw-r--r-- 1 root root 0 Dec 5 17:40 t1.txt [root@localhost hadoop]# [root@localhost .git]# ll total 96 drwxr-xr-x 2 root root 4096 Dec 4 19:41 branches -rw-r--r-- 1 root root 8 Dec 5 18:12 COMMIT_EDITMSG -rw-r--r-- 1 root root 92 Dec 4 19:41 config -rw-r--r-- 1 root root 73 Dec 4 19:41 description -rw-r--r-- 1 root root 23 Dec 4 19:41 HEAD drwxr-xr-x 2 root root 4096 Dec 4 19:41 hooks -rw-r--r-- 1 root root 361 Dec 5 18:12 index drwxr-xr-x 2 root root 4096 Dec 4 19:41 info drwxr-xr-x 3 root root 4096 Dec 5 03:47 logs drwxr-xr-x 50 root root 4096 Dec 5 18:12 objects -rw-r--r-- 1 root root 41 Dec 5 18:11 ORIG_HEAD drwxr-xr-x 4 root root 4096 Dec 5 18:12 refs [root@localhost .git]# cat HEAD ref: refs/heads/master [root@localhost .git]# cat refs/heads/master 54cf628bf72462bc37804fcc5df3850eacf9cf7e [root@localhost .git]# git cat-file -t 54cf6 commit [root@localhost .git]# 重点须要关注的就是HEAD,它连接到refs/heads/master,而master中存放的就是HASH码,其实就是一个COMMIT对象! 那么这个MASTER究竟是什么东西呢? [root@localhost .git]# git cat-file -p HEAD tree 1aabc54505caf74bbe716649a974484cdc954438 parent b714e9882e287957061ce6a06bca26092a0eea48 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 bug fix [root@localhost .git]# git cat-file -p master tree 1aabc54505caf74bbe716649a974484cdc954438 parent b714e9882e287957061ce6a06bca26092a0eea48 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367933 -0800 bug fix [root@localhost .git]# 经过上面的,咱们是否能够得出HEAD eq master ? 实际上在GIT里面,master就是一个分支,即branch,也就是一个文件,里面存放着HASH! 在GIT中,HEAD是能够发生指向变化的,稍后会介绍。 [root@localhost .git]# git cat-file -p HEAD~ tree bffc7fb973539b5560cafbea421b65c7de5630ce parent 9ea1deaa2bafdf6061ff1dcffdf8ede25b3c0e73 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 commit [root@localhost .git]# git cat-file -p master~ tree bffc7fb973539b5560cafbea421b65c7de5630ce parent 9ea1deaa2bafdf6061ff1dcffdf8ede25b3c0e73 author zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 committer zhangfengzhe <zhangfengzhe1990@163.com> 1449367556 -0800 commit [root@localhost .git]# [root@localhost .git]# git rev-parse HEAD 54cf628bf72462bc37804fcc5df3850eacf9cf7e [root@localhost .git]# git rev-parse master 54cf628bf72462bc37804fcc5df3850eacf9cf7e [root@localhost .git]# git rev-parse能够用于查看指向的HASH 那么问题来了,怎么定位到master~3的根目录呢? [root@localhost .git]# git cat-file -p master^{tree} 100644 blob d3aaea0fd831e7efc5751357d77afd3dde514b3fHelloWorld.java 100644 blob 01f9a2aac3e315c5caa00db4019f1d934171dba0delete.me 100644 blob 4ca70693ed50750b52b2a5d1c289adc554a251aflove.txt 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391t1.txt [root@localhost .git]# git cat-file -p master:love.txt i love you i hit you i eat you [root@localhost .git]# 其实,上面的例子,就是所谓的tree-ish表达式! tree-ish表达式,能够方便咱们快速定位到任何一个对象。 |
建立/删除/合并分支
git与其余的版本控制系统,差异仍是蛮大的,分支对于git而言,只是一个文件,里面存放HASH码而已。 [root@localhost hadoop]# git branch * master [root@localhost hadoop]# git branch 列出全部的branch 注意到master前面有一个*号,说明的是当前正在使用的branch [root@localhost hadoop]# git branch mybranch1 [root@localhost hadoop]# git branch * master mybranch1 [root@localhost hadoop]# 若是咱们不想在master分支上,想切换到mybranch1上,该如何操做呢? [root@localhost hadoop]# git checkout mybranch1 Switched to branch 'mybranch1' [root@localhost hadoop]# git branch master * mybranch1 [root@localhost hadoop]# 若是咱们想先建立一个分支,而后切换到这个分支的话,能够分步使用git branch + git checkout 来完成,固然也能够快捷完成:git checkout -b便可。 [root@localhost hadoop]# git checkout -b mybranch2 Switched to a new branch 'mybranch2' [root@localhost hadoop]# git branch master mybranch1 * mybranch2 [root@localhost hadoop]# 切换分支,是什么鬼? [root@localhost hadoop]# git branch master * mybranch1 [root@localhost hadoop]# cat .git/HEAD ref: refs/heads/mybranch1 [root@localhost hadoop]# git checkout master Mlove.txt Switched to branch 'master' [root@localhost hadoop]# cat .git/HEAD ref: refs/heads/master [root@localhost hadoop]# 切换分支,只是改变了HEAD文件指向而已! 其实这更加准确的说明了,HEAD指向的是当前的branch! 建立分支到底意味着什么? [root@localhost hadoop]# cd .git/refs/heads/ [root@localhost heads]# ll total 16 -rw-r--r-- 1 root root 41 Dec 12 00:10 master -rw-r--r-- 1 root root 41 Dec 12 00:24 mybranch1 [root@localhost heads]# cat * 51d60776dc4cbe9c07f65cee378874f232e198d8 51d60776dc4cbe9c07f65cee378874f232e198d8 [root@localhost heads]# 咱们清楚的看到了,mybranch1和master同样,以文件的形式存在,放的是HASH CODE。 此时此刻,其实mybranch1 和 master 同样都指向当前的COMMIT对象! 以下图所示: HEAD的指向就是经过git checkout在不一样的分支上来回切换。 下面,咱们来作几个小例子: [root@localhost hadoop]# git branch master * mybranch1 [root@localhost hadoop]# vi love.txt [root@localhost hadoop]# cat love.txt i love you i hit you i eat you changed ? add [root@localhost hadoop]# git cat-file -p HEAD:love.txt i love you i hit you i eat you changed ? 分支改变了,但没有提交,看看对其余分支的影响: [root@localhost hadoop]# git checkout master Mlove.txt Switched to branch 'master' [root@localhost hadoop]# git cat-file -p HEAD:love.txt i love you i hit you i eat you changed ? 分支提交后,这个分支就会变化,可是不会影响其余分支的,其余分支看不到这种变化!由于HEAD指针指向的问题。 [root@localhost hadoop]# git checkout mybranch1 Mlove.txt Switched to branch 'mybranch1' [root@localhost hadoop]# git branch master * mybranch1 [root@localhost hadoop]# git add love.txt [root@localhost hadoop]# git commit -m 'test branch' love.txt [mybranch1 8cf1339] test branch 1 file changed, 1 insertion(+) [root@localhost hadoop]# git branch master * mybranch1 [root@localhost hadoop]# git cat-file -p HEAD:love.txt i love you i hit you i eat you changed ? add [root@localhost hadoop]# git checkout master Switched to branch 'master' [root@localhost hadoop]# git branch * master mybranch1 [root@localhost hadoop]# git cat-file -p HEAD:love.txt i love you i hit you i eat you changed ? [root@localhost hadoop]# 若是此时此刻,咱们对mybranch1分支进行删除,会发生什么呢? [root@localhost hadoop]# git branch * master mybranch1 [root@localhost hadoop]# git branch -d mybranch1 error: The branch 'mybranch1' is not fully merged. If you are sure you want to delete it, run 'git branch -D mybranch1'. [root@localhost hadoop]# 画个图,来讲明: 若是咱们把mybranch1分支删除掉,那么commit-e对象将会找不到了,由于没有对象能够指向它,会成为“孤儿”,GIT不会容许出现这样的状况,此时咱们要作的就是合并! [root@localhost hadoop]# git branch * master mybranch1 [root@localhost hadoop]# git merge mybranch1 Updating 7d1ea72..8cf1339 Fast-forward love.txt | 1 + 1 file changed, 1 insertion(+) [root@localhost hadoop]# git cat-file -p HEAD:love.txt i love you i hit you i eat you changed ? add [root@localhost hadoop]# 其实,合并后,只是更新了master的指向,master会指向commit-e而已。 注意git merge执行后的提示“Fast-forward”,这是个什么意思? 其实说的就是,这种合并是一个比较简单的合并方式,由于仅仅只是改变了master的指向就达到了合并的目的。还有一种较为复杂的状况3-WAY MERGE: 若是master分支有新的COMMIT,而mybranch1有2个新的COMMIT,那么怎么合并呢? 此时此刻,就不能够将master指向commit-g那么简单了。 那么实际上,git会对于master以及mybranch1分支的共有部分commit-d、commit-e、commit-g进行比较处理,生成一个新的commit对象完成merge操做。但这对于咱们都是透明的,咱们其实无需关心,仍是直接使用git merge便可! |