前言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便可! |