Git 检出
标签(空格分隔): Git 学习笔记
仔细想想
git reset
命令的作用就是修改引用,如git reset HEAD^
就是将 master 的引用改变。可以发现,在git reset HEAD^
中并没有设置任何参数对所要重置的分支名进行设置,例如:我们并没有git reset master HEAD^
这样;这是因为重置命令实际上所针对的是头指针
。之所以重置命令没有改变头指针HEAD
的内容,是因为HEAD
指向了一个引用refs/heads/master
,所以重置命令体现为分支上游标
的变更,HEAD
本身一直指向的是refs/heads/master
,并没有在重置时改变。
这个地方比较绕,我的理解是HEAD
指向refs/heads/master
,而refs/heads/master
里又记录这个分支的提交链,使用reset
命令会改变refs/heads/master
这个文件里记录的提交 ID,并不会改变HEAD
指向refs/heads/master
这个事实,但是想改变HEAD
指向的内容(也就是想让HEAD
指向其它分支),就要使用git checkout
这个命令,这样就保证了reset
命令永远会作用在当前这个分支上。
1 HEAD 的重置既检出
HEAD
可以理解为 头指针
,是当前工作区的 基础版本
。
1.1 分离头指针
分离头指针
状态是指 HEAD
头指针指向了一个具体的提交 ID,而不是一个引用(一个分支)。处于分离头指针状态下时,我们可以检查、测试、提交,而不会影响任何分支。但是通过另外一个 checkout
检出指令会丢弃在此状态下的修改和提交。若想保留,使用 -b
参数调用 checkout
检出指令以创建新的跟踪分支。例如:git checkout -b newbranch_name
。
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat .git/HEAD
ref: refs/heads/master
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git branch -v
* master 3f39502 commit
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git checkout '3f39502^'
Note: checking out '3f39502^'.
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 ee76d8a... inset qwe
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat .git/HEAD
ee76d8a1bd776d7042c7054e5abf180b371550cf
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git branch -v
* (detached from ee76d8a) ee76d8a inset qwe
master 3f39502 commit
[root@izwz9f5nsv33jsmjcx0qw1z demo]#
通过查看 reflog
也可以看到当针对提价执行了检出指令时,HEAD
头指针被改变。如下:
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git reflog -1
ee76d8a HEAD@{0}: checkout: moving from master to 3f39502^
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git rev-parse HEAD master
ee76d8a1bd776d7042c7054e5abf180b371550cf
3f39502c130889248d8794f42a1cb784a785d402
##2 挽救分离头指针
在 分离头指针
模式下进行的提交只能通过提交 ID 进行访问,虽然这个提交确实存在于版本库中,但是这个提交没有被任何分支跟踪到。因此当 reflog
中含有该提交的日志过期后,这个提交随时会从版本库中彻底清除。
若想保留 分离头指针
状态下的提交到 master 分支,可以使用 git merge
命令进行合并,操作如下:
- 将分离头指针状态的下的修改进行提交,并记录提交 ID
- 切换到 master 分支,执行
git merge commitid
,这里的commitid
为分离头指针状态下的提交 ID
合并后查看最新的提交,会发现这个提交有两个父提交,这就是合并的奥秘。如下:
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git cat-file -p HEAD
tree 3c4aef196da70c04a2f1dcca3f07bd2432d3c884
parent 3f39502c130889248d8794f42a1cb784a785d402
parent 7b421dbc5d925a91e3d20d201cf7351addcc1f9f
author shiweichn <shiweichn@163.com> 1505356200 +0800
committer shiweichn <shiweichn@163.com> 1505356200 +0800
Merge commit '7b421db'
提交线也能体现这一点,如:
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git log --graph --pretty=oneline
* 5a6b4a4493b798c090aa7b314ab3359e4562b2b1 Merge commit '7b421db'
|\
| * 7b421dbc5d925a91e3d20d201cf7351addcc1f9f new commit
* | 3f39502c130889248d8794f42a1cb784a785d402 commit
|/
* ee76d8a1bd776d7042c7054e5abf180b371550cf inset qwe
* f325ad0df30feeaea3804ec7f3b895688dabd37d Initial demo666
3 深入了解 git checkout
git checkout
检出命令是 Git 常用的命令之一,但也很危险,因为会重写工作区。用法如下:
git checkout [-q] [-f] [-m] [<branch>]
git checkout [-q] [-f] [-m] [--detach] [<commit>]
git checkout [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]
git checkout [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...
git checkout [-p|--patch] [<tree-ish>] [--] [<paths>...]
-
git checkout branch
检出 branch 分支,执行了上图中的三个步骤,即改变HEAD
的指向,替换了暂存区,替换工作区。 -
git checkout
同git checkout HEAD
汇总显示工作区、暂存区与HEAD
的差异 -
git checkout -- filename
用暂存区的文件替换工作区的文件,慎用。一旦替换,无法找回。 -
git checkout branch --filename
用 branch 所指向提交中的文件替换当前分支暂存区和工作区中的文件。 -
git checkout .
用暂存区目录树覆盖工作区,工作区所有修改都会彻底丢失。慎用。
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于