重置命令(git reset)主要用於修改master引用指向的提交ID,修改過程當中HEAD的指向並無改變(一致指向/refs/heads/master,而這個master被git reset命令改變)。git
相對的Git檢出命令(git checkout)會改變HEAD自己的指向,而不會影響分支遊標(master)。測試
8.1 HEAD的重置就是檢出this
HEAD能夠理解爲「頭指針」。查看HEAD的指向:3d
$ cat .git/HEAD ref: refs/heads/master
能夠看出HEAD指向了分支master。執行git branch會看到當前處於master分支:指針
$ git branch -v * master 1ce417a does master follow this new commit?
使用git checkout 檢出該ID的父提交:日誌
$ git checkout 1ce417a^ Note: checking out '1ce417a^'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by performing another checkout. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -b with the checkout command again. Example: git checkout -b <new-branch-name> HEAD is now at 1ce417a... does master follow this new commit?
輸出的大概意思是:code
檢出後,處於「分離頭指針」狀態。能夠檢查、測試和提交,經過執行另一個checkout命令能夠丟棄這些修改而不影響任何分支。orm
若是想建立新的分支來保留此狀態下的修改和提交,使用-b參數調用git checkout命令。it
查看HEAD的內容:io
$ cat .git/HEAD 326f2370369566e4cacc4c149e612adaba378716
能夠看出「分離頭指針「狀態就是HEAD頭指針指向了一個具體的提交ID,而不是一個引用(分支)。
查看最新的reflog能夠看到對提交執行git checkout命令時,HEAD頭指針被更改了,由指向master分支變成指向一個提交ID:
$ git reflog -1 326f237 HEAD@{0}: checkout: moving from master to 1ce417^
注意git reflog不帶文件參數查看了HEAD頭指針的變遷記錄,而不是master分支(git reflog show master )。
查看HEAD和master對應的提交ID,會發現如今它們指向的是不同的:
$ git rev-parse HEAD master 326f2370369566e4cacc4c149e612adaba378716 1ce417a21fcd936e333db5f56a79a04ae2785a08
如今版本庫的HEAD是指向326f23提交的。下面查看再作一次提交,HEAD會如何變化:
(1)建立一個新文件並把它添加到暫存區裏:
$ touch detached-commit.txt $ git add detached-commit.txt
(2)查看狀態,會有分離頭指針狀態的提示:
$ git status HEAD detached at 326f237 Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: detached-commit.txt
(3)執行提交:
$ git commit -m "commit in detached HEAD mode." [detached HEAD 64cc272] commit in detached HEAD mode. 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 detached-commit.txt
(4)查看頭指針,指向了新的提交:
$ cat .git/HEAD 64cc27237267d702e31e34fe0b75db97f5171001
(5)查看日誌,能夠看出新的提交是創建在以前的提交基礎上的:
$ git log --graph --pretty=oneline * 64cc27237267d702e31e34fe0b75db97f5171001 commit in detached HEAD mode. * 326f2370369566e4cacc4c149e612adaba378716 which version checked in? * 32d79d5cf6e6eac8c95b7978588e4f9db3139a45 who does commit? * 4f804c3948640ce146e48f0ff7c4d4592693df87 initialized.
而後切換到master分支上操做:
(1)切換到master分支上:
$ git checkout master Warning: you are leaving 1 commit behind, not connected to any of your branches: 64cc272 commit in detached HEAD mode. If you want to keep it by creating a new branch, this may be a good time to do so with: git branch <new-branch-name> 64cc272 Switched to branch 'master'
(2)HEAD頭指針從新指向了分支,而不是處於分離頭指針狀態:
$ cat .git/HEAD ref: refs/heads/master
(3)切換以後,以前本地創建的新文件detached-commit.txt不見了:
$ ls new-commit.txt welcome.txt
(4)切換以後,剛纔的提交日誌也不見了:
* 1ce417a21fcd936e333db5f56a79a04ae2785a08 does master follow this new commit? * 326f2370369566e4cacc4c149e612adaba378716 which version checked in? * 32d79d5cf6e6eac8c95b7978588e4f9db3139a45 who does commit? * 4f804c3948640ce146e48f0ff7c4d4592693df87 initialized.
查看剛纔的提交是否還在版本庫中:
$ git show 64cc27237 commit 64cc27237267d702e31e34fe0b75db97f5171001 Author: jiangzhi <ivanjz93@163.com> Date: Mon Jul 18 13:33:50 2016 +0800 commit in detached HEAD mode. diff --git a/detached-commit.txt b/detached-commit.txt new file mode 100644 index 0000000..e69de29
能夠看出這個提交如今仍在版本庫中。因爲這個提交沒有被任何分支跟蹤到,所以並不能保證這個提交會永久存在。當reflog中含有該提交的日誌過時後,這個提交隨時都會從版本庫中完全清除。
8.2 挽救分離頭指針
若是想把剛纔在分離頭指針模式下的提交關聯的master分支,可使用git reset命令,可是這樣就會丟掉master分支原先的提交「1ce417」。使用合併操做能夠實現二者兼顧:
(1)確認當前處於master分支
$ git branch -v * master 1ce417a does master follow this new commit?
(2)執行合併操做,將64cc27237提交合併到當前分支:
$ git merge 64cc27237 Merge made by the 'recursive' strategy. detached-commit.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 detached-commit.txt
(3)工做區多了detached-commit.txt文件
$ ls detached-commit.txt new-commit.txt welcome.txt
(4)查看日誌
$ git log --graph --pretty=oneline * 0463e7ae492200b77525642fb77d8f8fa03913c1 Merge commit '64cc27237' |\ | * 64cc27237267d702e31e34fe0b75db97f5171001 commit in detached HEAD mode. * | 1ce417a21fcd936e333db5f56a79a04ae2785a08 does master follow this new commit? |/ * 326f2370369566e4cacc4c149e612adaba378716 which version checked in? * 32d79d5cf6e6eac8c95b7978588e4f9db3139a45 who does commit? * 4f804c3948640ce146e48f0ff7c4d4592693df87 initialized.
看到不同的分支圖。出現了分支,而分支在最新的提交發生了合併。
(5)查看最新提交,會看到兩個父提交:
$ git cat-file -p HEAD tree ad4eca82e587a477b91a4f7bbfef97c7921e52cc parent 1ce417a21fcd936e333db5f56a79a04ae2785a08 parent 64cc27237267d702e31e34fe0b75db97f5171001 author jiangzhi <ivanjz93@163.com> 1468822001 +0800 committer jiangzhi <ivanjz93@163.com> 1468822001 +0800 Merge commit '64cc27237'
8.3 git checkout命令詳解
git checkout用法以下:
用法一:git checkout [-g] [<commit>] [--] <path> ...
用法二:git checkout [<branch>]
用法三:git checkout [-m] [ [-b|--orphan] <new_branch>] [<start_point>]
第一種用法不會改變HEAD頭指針,主要是用指定版本的文件覆蓋工做區中對應的文件。若是省略<commit>,則會用暫存區的文件覆蓋工做區的文件,不然用指定提交中的文件覆蓋暫存區和工做區中對應的文件。
第二種用法則會改變HEAD頭指針。主要的做用是切換到分支,若是省略<branch>則至關於對工做區進行狀態檢查。
第三種用法主要是建立和切換到新的分支,新的分支從<start_point>指定的提交開始建立。新分支和master分支沒有實質的不一樣,都是在refs/heads命名空間下的引用。
一些git checkout的使用例子: