日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

git——^和~的区别(转)

發布時間:2024/4/17 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 git——^和~的区别(转) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文地址:?http://www.cnblogs.com/softidea/p/4967607.html

?

一. 引子

在git操作中,我們可以使用checkout命令檢出某個狀態下文件,也可以使用reset命令重置到某個狀態,這里所說的“某個狀態”其實對應的就是一個提交(commit).

我們可以把一個git倉庫想象成一棵樹,每個commit就是樹上的一個節點。家家都有一本自己的祖譜。祖譜記錄了一個家族的生命史,它不僅記錄著該家族的來源、遷徙的軌跡,還包羅了該家族生息、繁衍、婚姻、文化、族規、家約等歷史文化的全過程。類似的,每個git倉庫都有一本自己的祖譜,倉庫中commit ID的繁衍,HEAD指針的遷徙,分支的增加、更新,同樣的記錄著一個倉庫從無到有的點點滴滴。

在git中,我們其實可以通過^和~來定位某個具體的commit,而不用每次都去敲繁瑣的hash值。為了便于大家理解,先把結論放在前面:

  • “^”代表父提交,當一個提交有多個父提交時,可以通過在”^”后面跟上一個數字,表示第幾個父提交,”^”相當于”^1”.
  • ~<n>相當于連續的<n>個”^”.
  • checkout只會移動HEAD指針,reset會改變HEAD的引用值。
  • 使用git log –graph 命令,可以查看自己倉庫的當前分支提交ID的樹狀圖,如下圖所示。

    使用git log –pretty=raw命令,可以查看commit之間的父子關系,如下圖所示,需要注意的是最開始的commit是沒有父提交的。

    二. 困惑

    在使用git的過程中,你也許會有很多的困惑。

    在使用reset或checkout命令的時候,需要一個<commit>參數,但是每次都輸入commit hash值是一件比較麻煩的事情。首先你得去查詢下日志,然后再用鍵盤將前面幾位hash值輸入。有時候你一次還搞不定,突然開個小差,暗戀下女神,想一想基友,都容易把hash值遺忘或弄錯。腫么辦???

    又話說突然間,一堆帶有hash值的符號出現在生活中,HEAD^1~4,<commit>~3^2,我擦!這是TMD玩意兒?不懂啊,使用過程中,HEAD和引用各種亂竄,根本不聽從我的指揮,哎呀,媽呀!我成了git的奴隸,從此生活不再美好。腫么辦???

    不,生活還要繼續,要和git做朋友。做朋友當然先要摸清楚朋友的性情和脾氣咯,有了好友,生活才會充滿希望。

    三. 解惑

    古有“射人先射馬,擒賊先擒王”,今有“git倉庫順藤摸瓜”。既然commit形成的樹狀圖,表明了各個commit之間的關系,那么我們也可以順著這棵樹去查詢commit的值。一般情況下,一個commit都會有一個父提交,那么通過<commit>^這個表達式,就可以訪問到其父提交的ID值;使用<commit>~也可以達到同樣的功效哦。

    我們知道每提交一次,HEAD就會自動移到版本庫中最近的一次提交。那么HEAD^就代表了最近一次提交的父提交,HEAD~也是同樣的道理;但是如果你想當然的認為^和~的用法相同,那就錯了,其實它們的區別還是蠻大的。

    四. 詳解

    我們來通過一個具體的例子,來講解一下^和~的用法區別,同時在checkout或reset的過程中,看看HEAD和引用的變化。

    查看HEAD和引用的值

    我們可以通過命令來查看HEAD和引用的值,也可以通過當前倉庫下的.git目錄去訪問。當前分支為master時,我們查看HEAD的值,命令如下:

    $ cat .git/HEAD ref: refs/heads/master

    然后,我們可以查看master引用的值

    $ cat .git/refs/heads/master 3b0370b.......? # hash code

    master分支上初始化,并提交一次

    在master分支上新建一個提交”c1”,生成commit ID 973c,這時候master引用指向973c,HEAD指向master引用。

    $ git init Initialized empty Git repository $ echo c1 >> a $ git add a $ git commit [master (root-commit) 973c5dd] c1 1?files changed, 1?insertions(+), 0?deletions(-) create mode 100644?a $ git log --oneline 973c5dd c1

    對應的圖如下所示:

    基于master新建br1分支,并提交兩次

    接下來在master分支基礎上新建分支”br1”,并在”br1”上提交”c2”,commit ID為1c73,這時候HEAD指向br1,br1引用指向”c2”對應提交1c73.

    $ git checkout -b br1 Switched to a new?branch 'br1' $ echo c2 >> b $ git add b $ git commit [br1 1c7383c] c2 1?file changed, 1?insertion(+) create mode 100644?b $ git log --oneline 1c7383c c2 973c5dd c1

    對應的圖如下所示:

    在分支”br1”上,提交”c3”,commit ID為4927,此時HEAD指向br1,br1引用指向”c3”對應提交4927.

    $ echo c3 >> b $ git commit -a -m "c3" [br1 4927c6c] c3 1?file changed, 1?insertion(+) $ git log --oneline 4927c6c c3 1c7383c c2 973c5dd c1

    對應的圖如下所示:

      

     

    切換到master分支,基于master分支新建br2分支,并提交兩次

    我們先切回到master分支,然后新建分支br2,先后提交”c4”和”c5”,對應的ID分別是”86ba”和”063f”,這時候HEAD指向br2,br2引用指向”c5”的對應提交063f.git 命令如下:

    $ git chechout master Switched to branch 'master' $ git checkout -b br2 Switched to a new?branch 'br2' $ echo c4 >> c $ git add c $ git commit -m "c4" [br2 86ba564] c4 1?file changed, 1?insertion(+) create mode 100644?c $ git log --oneline 86ba564 c4 973c5dd c1 $ echo c5 >> c $ git commit -a -m "c5" [br2 063f6e6] c5 1?file changed, 1?insertion(+) $ git log --oneline 063f6e6 c5 86ba564 c4 973c5dd c1

    對應的圖如下所示:

      

     

    切換到master分支,基于master分支創建br3分支,并提交兩次

    這個操作同分支br2上類似,先從br2分支切換到master分支,然后新建分支br3,分別提交”c6”和”c7”,對應的ID分別是”50f1”和”4f9c”,這時候HEAD指向br3,br2引用指向”c7”的對應提交4f9c,git 命令如下:

    $ git chechout master Switched to branch 'master' $ git checkout -b br3 Switched to a new?branch 'br3' $ echo c6 >> d $ git add d $ git commit -m "c6" [br3 50f14f6] c6 1?file changed, 1?insertion(+) create mode 100644?d $ git log --oneline 50f14f6 c6 973c5dd c1 $ echo c7 >> c $ git commit -a -m "c7" [br2 4f9ca79] c7 1?file changed, 1?insertion(+) $ git log --oneline 4f9ca79 c7 50f14f6 c6 973c5dd c1

    對應的圖如下所示:

    切換到master分支,合并br1,br2和br3分支

    先切換到master分支,然后合并br1 br2 br3,會新生成一個提交3b03.

    $ git checkout master $ git merge br1 br2 br3 3?files changed, 6?insertions(+) create mode 100644?b create mode 100644?c create mode 100644?d $ git log --oneline 3b0370b Merge braches 'br1', 'br2'?and?'br3' 4f9ca79 c7 50f14f6 c6 063f6e6 c5 86ba564 c4 4927c6c c3 1c7383c c2 973c5dd c1

    這時候,運用git log –oneline –graph查看生成的樹狀圖,如下所示.

    從上圖分析,在第1條紅線上的commit順序是: 3b03→4927→1c73→973c

    第2條紅線上的commit順序是:3b03→063f→86ba→973c

    第3條黃線上的commit順序是:3b03→4f9c→50f1→973c

    這3條線的從左至右的順序非常重要,因為HEAD^1對應的就是第1條紅線的提交4927,HEAD^2對應的是第2條綠線的063f提交,HEAD^3對應的是第3條黃線的4f9c提交。3b03沒有第4個父提交,因此也沒有第4條線,這時候訪問HEAD^n(n>3)都會報錯。

    因此從任何一條線上,我們都可以追溯到”c1”的commit,但是每條線上的中間節點,只能通過這條線上的節點去訪問。

    操作同上類似,最后的狀態如下,這時候HEAD指向master,master引用指向”c8”的對應提交3b03.

    對應的圖如下所示:

    我們再來看看3b03對應節點的父提交,如下圖所示:

    ?

    從圖得知,3b03一共有三個父提交,分別是4927,063f,4f9c.

    reset與checkou的區別

    在master分支上,當前提交為3b03,使用git reset –hard HEAD^,將master重置到HEAD的父提交;該命令也可以寫成git reset –hard HEAD^1

    $ git reset --hard HEAD^ HEAD?is now at 4927c6c c3

    對應的圖如下所示:

    這時候,HEAD還是指向master分支,但是master引用的commit值已經變成了4927,即3b03的第一個父提交的ID.

    然后,我們再重置到”c8”的commit”3b03”,git reset –hard 3b03,然后使用命令git checkout HEAD~ ,git 操作如下:

    $ git reset --hard 3b03 HEAD?is now at 3b0370b Merge branches 'br1', 'br2'?and?'br3' $ git checkout HEAD~ HEAD?is now at 4927c6c... c3

    對應的圖如下所示:

    這時候,HEAD指向了commit 4927,即3b03的第一個父提交ID,但是master引用還是對應的3b03.

    從上面的測試,我們可以得出以下結論:

  • HEAD^,HEAD^1和HEAD~三個表達式都是代表了HEAD的父提交
  • reset <commit>的時候,HEAD不變,但是HEAD指向的引用值會變成相應的<commit>值;checkout <commit>的時候,HEAD直接變成<commit>值,但原來引用中保存的值不變。
  • ^n和~n的區別

    (<commit>|HEAD)^n,指的是HEAD的第n個父提交(HEAD有多個父提交的情況下),如果HEAD有N個父提交,那么n取值為n < = N.

    (<commit>|HEAD)~n,指的是HEAD的第n個祖先提交,用一個等式來說明就是:(<commit>|HEAD)~n = (<commit>|HEAD)^^^….(^的個數為n).我們通過例子來驗證一下吧。

    我們沿用上面演示用的倉庫,先檢出到master分支,再使用git checkout HEAD^2,看看我們檢出了哪個commit

    $ git checkout master $ git checkout HEAD^2 HEAD?is now at 063f6e6... c5

    我們發現”c5”對應的commit值063f正是3b03第二個父提交的commit 對應的圖如下所示:

    現在再切回master分支,git checkout master

    然后使用git checkout HEAD^3,那么按照規律,就應該檢出3b03的第三個父提交的commit,即”c7”的commit值4f9c.

    $ git checkout master Previous HEAD?position was 063f6e6... c5 Switched to branch 'master' $ git checkout HEAD^3 HEAD?is now at 4f9ca79... c7

    對應的圖如下所示:

    果然沒錯,一切都在我們的預料之中!

    現在驗證下HEAD~的用法,切換到master分支,然后git checkout HEAD~2

    $ git checkout master $ git checkout HEAD~2 HEAD?is now at 1c7383c... c2

    這時候HEAD悄然來到了”c2”的commit 1c73,因此,HEAD~2 相當于HEAD的第一個父提交的第一個父提交。即HEAD~2 = HEAD^^ = HEAD^1^1, 符合預期!好開心的喲!

    五.總結

  • “^”代表父提交,當一個提交有多個父提交時,可以通過在”^”后面跟上一個數字,表示第幾個父提交,”^”相當于”^1”.
  • ~<n>相當于連續的<n>個”^”.
  • checkout只會移動HEAD指針,reset會改變HEAD的引用值。
  • 現在看到^和~兩個符號,再也不會彷徨和害怕了,因為我們知道了它們之間的關系及區別,從此我們過上了幸福的生活。

    http://www.cnblogs.com/hutaoer/archive/2013/05/14/3078191.html

    總結

    以上是生活随笔為你收集整理的git——^和~的区别(转)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。