天天看點

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

概述:在利用git進行管理的時候,除了對不同的分支進行merge以外,往往需要對同一個一個分支上的不同commit進行合并或者撤銷;或者對不同分支上的多次送出進行合并,形成一個線性的送出曆史,等等:這些都要用到git rebase,git reset和git log這三個指令。

1.commit的資訊查詢——git log

如果我們在同一個分支上進行了多次commit,要想查找每次commit的資訊,需要使用git log指令

$git log

commit daffbd39053d4f2e78f88955c2158de6092258a2

Author: hyk

Date:   Wed May 29 22:45:23 2013 +0800

this is a test

commit 38d58591fc0607bfd262fc8d363e52047fcf0e9c

Author: Eryu Guan

Date:   Wed May 29 08:12:44 2013 -0500

xfstests: fix typo in check

There is no $testname, should be $test_name

Signed-off-by: Eryu Guan

Reviewed-by: Rich Johnston

Signed-off-by: Rich Johnston

如上,commit按照時間的遠近排列,最新的修改在最前面

使用以下兩個指令,可以檢視commit的詳細資訊

$git log --graph

$git log -p

2.commit點的撤銷與分解——git reset

2.1指令概述:

1)指令解釋:

git reset:Reset current HEAD to the specified state

2)指令模式:

git reset [-q] [] [--] ...

git reset (--patch | -p) [] [--] [...]

git reset (--soft | --mixed | --hard | --merge | --keep) [-q] []

3)模式詳解:

上面的第一種和第二種形式中,直接從commit中copy條目到index,進而實作index的回滾。第三種形式中,将目前分支的HEAD設定到commit,同時可以選擇是否對working tree和stage作相應比對的更改。其中,在所有的指令形式中,預設是HEAD。

git reset -- []

This form resets the current branch head to and possibly updates the index (resetting it to the tree

of ) and the working tree depending on , which must be one of the following:

--soft:僅僅更改本地倉庫中的送出曆史,修改HEAD所指向的commit

--hard:重置index和working tree。任何在目前目錄下的tracked檔案,如果在commit之後,都會被廢棄。

注明:如果不指定mode的話,那麼index也将會同步進行更新。這個操作用于實作對index中檔案的撤銷和更改。

2.2指令使用情景:

1)commit 節點的移動

現在有如圖所示的版本情況:

---------(1.1)-----------(1.2)--------(1.3)------------(1.4)

其中HEAD指向1.4。此時想要生成patch,如果直接運作git format-patch的話,将生成1.3~1.4的patch,如果不想要1.2和1.3的送出記錄,直接從實作1.1到1.4的修改,此時需要運作以下指令:

$git reset 1.1

此時,目前工作目錄下位1.4版本的檔案,1.2 ,1.3這兩個版本的修改曆史被丢棄。然後可以繼續 add然後commit

注意,git reset的意義是: git-reset - Reset current HEAD to the specified state,它改變的本地倉庫中的檔案和index中的記錄,并沒有改變目前工作目錄之下的檔案。運作這個指令以後,你可能得到如下的結果:

[email protected]:/home/hyk/software/ltp# git reset  4bdda040bc045dd8d921d54d3b54db5dabeb9958

Unstaged changes after reset:

Mtestcases/kernel/mem/tunable/max_map_count.c

$git add file1

$git commit

$git add file2

$git commit

2)撤銷add到staged中的檔案

情景:add了兩個檔案到index,但是覺得沒有修改好,現在需要撤銷add這個操作。

$ edit                                     (1)

$ git add frotz.c filfre.c

$ mailx                                    (2)

$ git reset                                (3)

$ git pull git://info.example.com/ nitfol  (4)

3)撤銷一次送出,修改之後重做

相對于上個例子,更進一層,add完畢,而且已經commit,然後想要撤銷這次送出,重做以後再進行送出。

Undo a commit and redo

$ git commit ...

$ git reset --soft HEAD^      (1)

$ edit                        (2)

$ git commit -a -c ORIG_HEAD  (3)

3.git rebase:合并不同分支上的送出,形成線性送出曆史

git rebase的說明:git-rebase - Forward-port local commits to the updated upstream head

rebase,顧名思義,rebase的意思就是改變某一個分支的base。本例中,就是将mywork這個分支的base從C2改動到C4

假設你現在基于遠端倉庫"origin",建立一個叫"mywork"的分支。

$ git checkout -b mywork origin

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

現在我們在這個分支做一些修改,然後生成兩個送出(commit).

$ vi file.txt

$ git commit

$ vi otherfile.txt

$ git commit

...

但是與此同時,有些人也在"origin"分支上做了一些修改并且做了送出了. 這就意味着"origin"和"mywork"這兩個分支各自"前進"了,它們之間"分叉"了。

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

在這裡,你可以用"pull"指令把"origin"分支上的修改拉下來并且和你的修改合并; 結果看起來就像一個新的"合并的送出"(merge commit):

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

但是,如果你想讓"mywork"分支曆史看起來像沒有經過任何合并一樣,你也許可以用 git

rebase:

$ git checkout mywork

$ git rebase origin

這些指令會把你的"mywork"分支裡的每個送出(commit)取消掉,并且把它們臨時 儲存為更新檔(patch)(這些更新檔放到".git/rebase"目錄中),然後把"mywork"分支更新 到最新的"origin"分支,最後把儲存的這些更新檔應用到"mywork"分支上。

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

當'mywork'分支更新之後,它會指向這些新建立的送出(commit),而那些老的送出會被丢棄。 如果運作垃圾收集指令(pruning garbage collection), 這些被丢棄的送出就會删除. (請檢視 git

gc)

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

現在我們可以看一下用合并(merge)和用rebase所産生的曆史的差別:

commit節點号 git_git中各個commit節點的查詢 回溯 與 合并:git rebase與git reset | 學步園...

在rebase的過程中,也許會出現沖突(conflict). 在這種情況,Git會停止rebase并會讓你去解決 沖突;在解決完沖突後,用"git-add"指令去更新這些内容的索引(index), 然後,你無需執行 git-commit,隻要執行:

$ git rebase --continue

這樣git會繼續應用(apply)餘下的更新檔。

在任何時候,你可以用--abort參數來終止rebase的行動,并且"mywork" 分支會回到rebase開始前的狀态。

$ git rebase --abort

注意:如果C3 C5裡面改動的内容有沖突,那麼這個時候先要解決沖突,然後才能送出。