在日常的git操作中,git checkout——检出,是我们的常用命令。最为常用的两种情形是创建分支和切换分支。
在下面的命令中,使用了一些简写,在这里说明一下:
1
2
3
4
5
6
|
git st # git status git ci # git commit git br # git branch git co # git checkout git mg # git merge git line # git log --oneline |
当然,你也可以直接在git中敲命令,将这些简写添加到git配置中
1
|
git config --global -e |
然后,可以插入下面的配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[alias] st = status co = checkout br = branch mg = merge ci = commit md = commit --amend dt = difftool mt = mergetool last = log -1 head cf = config line = log --oneline latest = for-each-ref --sort=-committerdate --format='%(committerdate:short) %(refname:short) [%(committername)]' ls = log --pretty=format:\"%c(yellow)%h %c(blue)%ad %c(red)%d %c(reset)%s %c(green)[%cn]\" --decorate --date=short hist = log --pretty=format:\"%c(yellow)%h %c(red)%d %c(reset)%s %c(green)[%an] %c(blue)%ad\" --topo-order --graph --date=short type = cat-file -t dump = cat-file -p |
这样,你也就可以使用这些简写的命令咯。下面步入正题啊。
(一)基础——千里之行,始于切糕(checkout)
先熟悉下常用操作,创建分支和切换分支,也可以称为检出分支。
首先我们新建一个仓库gittest,然后新建文件a,为什么要用a命名呢,这里是故意为之,后面为大家揭晓分支。呵呵。或许下面的介绍会有些枯燥乏味,因为您已经对这些命令烂熟于胸,而且运用得相当熟练,那么您可以直接跳过这一步。
在master分支上,做一次提交c1,然后现在新建一个分支a,并切换到a分支。
这个操作主要会用到两个命令:
创建新分支:git branch branchname
切换到新分支:git checkout branchname
然后,上面两个命令也可以合成为一个命令:
1
|
git checkout -b branchname |
新建远程分支
1
|
git push origin master:nggjc_project_xxxxxxx |
(二)真相——head是checkout的灵魂
其实,我们在切换分支,和新建分支的时候,有没有想过,这些操作操作背后的工作原理是怎样的呢?最大的功臣就是.git目录下的head引用,她宛如一个芭蕾舞者,从一个分支飘逸的跳到另一个分支,虽无声无息,却精准无比。
在我们身处master分支的时候,您一定很好奇,当前的head的内容是什么?不妨来看看吧。
我们看到c1的提交hash值和head对应分支master的当前hash值是一样的。也就是说,head指向的是当前分支名master,而master又对应了当前的最新的一次提交id.
好,那么我们再做一次提交,看看master对应的hash值有无变化。
从上图,我们可以不难看出,head对应的ref没有变化,还是master,但是master对应的commit id却变成了c2对应的commit id,即更新为最后一次提交的id咯。
现在,提交一次的原理,我们已然了解,那么切换分支的时候呢??
现在我们身处master分支,然后我们切换到a分支,看看会发生什么样的情况吧。
从上图分析,在master分支上的时候,head指向的是master,对应的是c2的commit id。而切换到a分支的时候,head也相应的指向了a,同时a对应的是a分支上的最新commit id。因此,我们可以得出结论,在切换分支的时候,head也会相应的指向对应的分支引用。
但是,使用checkout命令的时候,并不是每次都会改变head指针的指向哦。在什么情况下head一直坚定不移的拥护者他的女神呢?可谓衣带渐宽终不悔,长使英雄泪满襟啊!让我们接着往下看。
(三)进阶——head懂不懂,看你怎么用
checkout命令用法如下:
1. git checkout [-q] [<commit>] [--] <paths> ...
2. git checkout [<branch>]
3. git checkout [-m] [ [-b | -- orphan ] <new_branch>] [start_point]
用法2比用法1的区别在于,用法1包含了路径。为了避免路径和引用(或提交id)同名而发生冲突,可以在<paths>前用两个连续的连字符作为分隔。用法1的<commit>是可选项,如果省略,则相当于从暂存区进行检出。
来看个例子:
情景1,省略掉<commit>
现在我们处于master分支下,然后我们修改了文件a,输入“c3”文本到a中,这时候,暂存区中的内容是没有"c3"的,通过git diff可以比较。现在我们从当前分支暂存区中检出文件a。那么我们可以直接使用git checkout a。
这时候,提示检出失败,git以为我们想检出仓库a。还记得为什么在第一步中,我们曾新建的文件a吗?这里终于派上用场了,由于仓库中还存在分支a,同时当前分支中又存在文件a,于是git傻傻分不清楚了。这时候怎么办?有两个办法,第一,我们在命名分支的时候要注意语义性,分支名要具有一定的意义,不能使用简单的a,b,c来命名,这样很容易导致分支名和文件名重复;第二,参照用法1,使用两个连字符来分隔。在目前的情形中,我们使用第二种方法吧。
这时候,发现工作区的内容被暂存区的内容覆盖,"c3"文本也没有了,当然head指针也没有什么变化,一切又恢复了平静。
再看一个例子:
情景2,不省略<commit>
在不省略<commit>的时候,<commit>既可以是某一个具体的commit hash值,也可以是某个分支名称,tag名称。不论分支也好,tag也好,它们本质上对应的都是一个commit hash值。
在检出a分支下的a文件的时候,最好把两个连字符加上,不然git也会无法区分。整个过程中,head头指针没有发生改动。
总结:第1种用法(包含<paths>的用法)不会改变head头指针,主要使用于指定版本的文件覆盖工作区中对应的文件。如果省略<commit>,则会用暂存区的文件覆盖工作区中的文件,否则用指定提交中的文件覆盖暂存区和工作区中的对应文件。
接下来,我们看看用法2,在第一部分中,我们知道切换分支,会改变head的指向,那么如果我们是检出某个commit会怎样呢?同检出分支一样,会用该commit下的内容覆盖当前分支工作区和暂存区的内容,请看例子。
目前我们处于master分支上,且已经有了两次提交,分别是c1和c2,然后我们修改a,给a文件添加内容"c3",并add到暂存区,随即使用checkout到c1的commit 上。注意,刚开始checkout的时候,git不会允许你直接切换,因为你修改了暂存区的内容, 它会提醒你提交后再切换,这时候,你可以使用-f 强行切换。再查看状态的时候,git提示我们已经不在任何分支上,head指针也是指向具体的c1的commit值,进入了“分离头指针”状态。这个状态下,要回到master上面,只需要git checkout master即可,也可以在这个状态上新建分支。
如果,checkou后面不跟任何参数,则就是对工作区进行检查,请看例子。
我们身处master分支上,并且没有任何改动,这时候git checkout没有任何输出。然后,我们给a文件添加内容“c3”,然后再git checkout一下,git就会提示a文件有修改,是不是很简单?
总结:对于第2种用法,不是检出某个具体文件的的时候,即不指定<paths>的时候,单纯的检出某个commit或分支,是会改变head头指针的。而且只有当head切换到某个分支的时候才可以对提交进行跟踪,否则就会进入“分离头指针”的状态。如果省略用法2后面的<branch>,则默认对工作区进行状态检查。
(四)熟悉的checkout,陌生的用法,妈妈再也不用担心我的checkout啦!
1. git branch <branch> <start point>
以某个commit创建新分支。 在通常情况下,我们都会在当前分支的基础上,创建新分支。比如git branch new_branch
也许你不知道,我们还可以基于当前分支的某一次commit来创建分支。请看!
从上图可见,我们想基于master分支的c1 提交id创建新分支new_branch,创建成功后,切换到new_branch,查看log,只有c1,耶~~成功啦!
当然,也可以使用git checkout -b <new_branch> <start point>这个常用的命令。
2. git checkout --datch <branch>
切换到分支的游离状态,默认以该分支下的最后一次提交id,请看下面的例子。
当前分支为a,然后使用git checkout --detach master,那么head就会切换到master的最后一次commit值的状态下!
3. git checkout -b <branch>
这个命令,可以强制创建新的分支,为什么加-b呢?如果当前仓库中,已经存在一个跟你新建分支同名的分支,那么使用普通的git checkout -b <branch>这个命令,是会报错的,且同名分支无法创建。如果使用-b参数,那么就可以强制创建新的分支,并会覆盖掉原来的分支。请看具体操作。
当前分支为master,且仓库中已经存在分支a,我们先用git checkout -b a来创建a分支,必然会失败的,并提示我们仓库中已经有了一个a分支咯,仿佛在说“hi,哥们,你已经有了一个老婆了,一夫一妻制你的不懂?你以为这里是印度啊?”。随后,我们使用git checkout -b a,耶~~,it works!
4. git checkout --orphan <branch>
是的,假如你的某个分支上,积累了无数次的提交,你也懒得去打理,打印出的log也让你无力吐槽,那么这个命令将是你的神器,它会基于当前所在分支新建一个赤裸裸的分支,没有任何的提交历史,但是当前分支的内容一一俱全。新建的分支,严格意义上说,还不是一个分支,因为head指向的引用中没有commit值,只有在进行一次提交后,它才算得上真正的分支。还等什么呢?赶紧试试!
好了,现在我们终于找到组织了!
5. git checkout --merge <branch>
这个命令适用于在切换分支的时候,将当前分支修改的内容一起打包带走,同步到切换的分支下。
有两个需要注意的问题。
第一,如果当前分支和切换分支间的内容不同的话,容易造成冲突。
第二,切换到新分支后,当前分支修改过的内容就丢失了。
所以这个命令,慎用!
6. git checkout -p <branch>
这个命令可以用来打补丁。这个命令主要用来比较两个分支间的差异内容,并提供交互式的界面来选择进一步的操作。这个命令不仅可以比较两个分支间的差异,还可以比较单个文件的差异哦!
结束语:至此,关于git checkout命令暂告一段落,对于checkout命令,你也有所熟悉了吧。当然,git checkout还有一些其它用法,本文并没有讲到,你可以在git bash或终端中使用git checkout --help去进一步了解!
删除本地分支
1
|
git branch -d 分支名 |
删除远程分支
1
|
git push origin -delete 分支名 |
到此这篇关于git checkout 命令使用详解的文章就介绍到这了,更多相关git checkout内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://www.cnblogs.com/hutaoer/archive/2013/05/07/git_checkout.html