《Git权威指南》读书笔记 第八章 Git检出(checkout)

重置命令(git reset)主要用于修改master引用指向的提交ID,修改过程中HEAD的指向并没有改变(一致指向/refs/heads/master,而这个master被git reset命令改变)。

相对的Git检出命令(git checkout)会改变HEAD本身的指向,而不会影响分支游标(master)。

8.1 HEAD的重置就是检出

HEAD可以理解为“头指针”。查看HEAD的指向:

$ 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?

输出的大概意思是:

    检出后,处于“分离头指针”状态。可以检查、测试和提交,通过执行另外一个checkout命令可以丢弃这些修改而不影响任何分支。

    如果想创建新的分支来保留此状态下的修改和提交,使用-b参数调用git checkout命令。

查看HEAD的内容:

$ 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 . 用暂存区的所有文件直接覆盖本地文件。

转载于:https://my.oschina.net/u/2453016/blog/713831

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值