《Git權威指南》讀書筆記 第八章 Git檢出(checkout)

重置命令(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的使用例子:

  • git checkout branch 檢出branch分支(HEAD指向branch分支);
  • git checkout/git checkout HEAD 彙總顯示工做區、暫存區與HEAD的差別;
  • git checkout -- filename 用暫存區中filename文件來覆蓋工做區的filename文件;
  • git checkout brach -- filename 維持HEAD的指向不變。用branch所指向的提交中的filename替換暫存區和工做區中相應的文件;
  • git checkout -- . 或 git checkout . 用暫存區的全部文件直接覆蓋本地文件。
相關文章
相關標籤/搜索