在git操作中,我们可以使用checkout命令检出某个状态下文件,也可以使用reset命令重置到某个状态,这里所说的“某个状态”其实对应的就是一个提交(commit).

我们可以把一个git仓库想象成一棵树,每个commit就是树上的一个节点。家家都有一本自己的祖谱。祖谱记录了一个家族的生命史,它不仅记录着该家族的来源、迁徙的轨迹,还包罗了该家族生息、繁衍、婚姻、文化、族规、家约等历史文化的全过程。类似的,每个git仓库都有一本自己的祖谱,仓库中commit ID的繁衍,HEAD指针的迁徙,分支的增加、更新,同样的记录着一个仓库从无到有的点点滴滴。

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

在git中,我们其实可以通过^和~来定位某个具体的commit,而不用每次都去敲繁琐的hash值。为了便于大家理解,先把结论放在前面:

  1. “^”代表父提交,当一个提交有多个父提交时,可以通过在”^”后面跟上一个数字,表示第几个父提交,”^”相当于”^1”.
  2. ~相当于连续的个”^”.
  3. checkout只会移动HEAD指针,reset会改变HEAD的引用值。

使用git log –graph 命令,可以查看自己仓库的当前分支提交ID的树状图,如下图所示。

使用git log –pretty=raw命令,可以查看commit之间的父子关系,如下图所示,需要注意的是最开始的commit是没有父提交的。

二. 困惑

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

在使用git的过程中,你也许会有很多的困惑。

在使用reset或checkout命令的时候,需要一个参数,但是每次都输入commit hash值是一件比较麻烦的事情。首先你得去查询下日志,然后再用键盘将前面几位hash值输入。有时候你一次还搞不定,突然开个小差,暗恋下女神,想一想基友,都容易把hash值遗忘或弄错。肿么办???

又话说突然间,一堆带有hash值的符号出现在生活中,HEAD^1~4,~3^2,我擦!这是TMD玩意儿?不懂啊,使用过程中,HEAD和引用各种乱窜,根本不听从我的指挥,哎呀,妈呀!我成了git的奴隶,从此生活不再美好。肿么办???

不,生活还要继续,要和git做朋友。做朋友当然先要摸清楚朋友的性情和脾气咯,有了好友,生活才会充满希望。

三. 解惑

古有“射人先射马,擒贼先擒王”,今有“git仓库顺藤摸瓜”。既然commit形成的树状图,表明了各个commit之间的关系,那么我们也可以顺着这棵树去查询commit的值。一般情况下,一个commit都会有一个父提交,那么通过^这个表达式,就可以访问到其父提交的ID值;使用~也可以达到同样的功效哦。

我们知道每提交一次,HEAD就会自动移到版本库中最近的一次提交。那么HEAD^就代表了最近一次提交的父提交,HEAD~也是同样的道理;但是如果你想当然的认为^和~的用法相同,那就错了,其实它们的区别还是蛮大的。

四. 详解

我们来通过一个具体的例子,来讲解一下^和~的用法区别,同时在checkout或reset的过程中,看看HEAD和引用的变化。

查看HEAD和引用的值

我们可以通过命令来查看HEAD和引用的值,也可以通过当前仓库下的.git目录去访问。当前分支为master时,我们查看HEAD的值,命令如下:

$ cat .git/HEAD

ref: refs/heads/master

然后,我们可以查看master引用的值

$ cat .git/refs/heads/master3b0370b....... # hash code

master分支上初始化,并提交一次

在master分支上新建一个提交”c1”,生成commit ID 973c,这时候master引用指向973c,HEAD指向master引用。

$ git initInitialized empty Git repository$ echo c1 >> a$ git add a$ git commit[master (root-commit) 973c5dd] c1 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 a$ git log --oneline 973c5dd c1

对应的图如下所示:

基于master新建br1分支,并提交两次

接下来在master分支基础上新建分支”br1”,并在”br1”上提交”c2”,commit ID为1c73,这时候HEAD指向br1,br1引用指向”c2”对应提交1c73.

$ git checkout -b br1Switched to a new branch 'br1'$ echo c2 >> b$ git add b$ git commit[br1 1c7383c] c2 1 file changed, 1 insertion(+) create mode 100644 b$ git log --oneline1c7383c c2973c5dd c1

对应的图如下所示:

在分支”br1”上,提交”c3”,commit ID为4927,此时HEAD指向br1,br1引用指向”c3”对应提交4927.

$ echo c3 >> b$ git commit -a -m "c3"[br1 4927c6c] c3 1 file changed, 1 insertion(+)$ git log --oneline4927c6c c31c7383c c2973c5dd c1

对应的图如下所示:

切换到master分支,基于master分支新建br2分支,并提交两次

我们先切回到master分支,然后新建分支br2,先后提交”c4”和”c5”,对应的ID分别是”86ba”和”063f”,这时候HEAD指向br2,br2引用指向”c5”的对应提交063f.git 命令如下:

$ git chechout masterSwitched to branch 'master'$ git checkout -b br2Switched to a new branch 'br2'$ echo c4 >> c$ git add c$ git commit -m "c4"[br2 86ba564] c4 1 file changed, 1 insertion(+) create mode 100644 c$ git log --oneline86ba564 c4973c5dd c1$ echo c5 >> c$ git commit -a -m "c5"[br2 063f6e6] c5 1 file changed, 1 insertion(+)$ git log --oneline063f6e6 c586ba564 c4973c5dd c1

对应的图如下所示:

切换到master分支,基于master分支创建br3分支,并提交两次

这个操作同分支br2上类似,先从br2分支切换到master分支,然后新建分支br3,分别提交”c6”和”c7”,对应的ID分别是”50f1”和”4f9c”,这时候HEAD指向br3,br2引用指向”c7”的对应提交4f9c,git 命令如下:

$ git chechout masterSwitched to branch 'master'$ git checkout -b br3Switched to a new branch 'br3'$ echo c6 >> d$ git add d$ git commit -m "c6"[br3 50f14f6] c6 1 file changed, 1 insertion(+) create mode 100644 d$ git log --oneline50f14f6 c6973c5dd c1$ echo c7 >> c$ git commit -a -m "c7"[br2 4f9ca79] c7 1 file changed, 1 insertion(+)$ git log --oneline4f9ca79 c750f14f6 c6973c5dd c1

对应的图如下所示:

切换到master分支,合并br1,br2和br3分支

先切换到master分支,然后合并br1 br2 br3,会新生成一个提交3b03.

$ git checkout master$ git merge br1 br2 br3 3 files changed, 6 insertions(+) create mode 100644 b create mode 100644 c create mode 100644 d$ git log --oneline 3b0370b Merge braches 'br1', 'br2' and 'br3'4f9ca79 c750f14f6 c6063f6e6 c586ba564 c44927c6c c31c7383c c2973c5dd c1

这时候,运用git log –oneline –graph查看生成的树状图,如下所示.

从上图分析,在第1条红线上的commit顺序是: 3b03→4927→1c73→973c

第2条红线上的commit顺序是:3b03→063f→86ba→973c

第3条黄线上的commit顺序是:3b03→4f9c→50f1→973c

这3条线的从左至右的顺序非常重要,因为HEAD^1对应的就是第1条红线的提交4927,HEAD^2对应的是第2条绿线的063f提交,HEAD^3对应的是第3条黄线的4f9c提交。3b03没有第4个父提交,因此也没有第4条线,这时候访问HEAD^n(n>3)都会报错。

因此从任何一条线上,我们都可以追溯到”c1”的commit,但是每条线上的中间节点,只能通过这条线上的节点去访问。

操作同上类似,最后的状态如下,这时候HEAD指向master,master引用指向”c8”的对应提交3b03.

对应的图如下所示:

我们再来看看3b03对应节点的父提交,如下图所示:

从图得知,3b03一共有三个父提交,分别是4927,063f,4f9c.

reset与checkou的区别

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

在master分支上,当前提交为3b03,使用git reset –hard HEAD^,将master重置到HEAD的父提交;该命令也可以写成git reset –hard HEAD^1

$ git reset --hard HEAD^HEAD is now at 4927c6c c3

对应的图如下所示:

这时候,HEAD还是指向master分支,但是master引用的commit值已经变成了4927,即3b03的第一个父提交的ID.

然后,我们再重置到”c8”的commit”3b03”,git reset –hard 3b03,然后使用命令git checkout HEAD~ ,git 操作如下:

$ git reset --hard 3b03HEAD is now at 3b0370b Merge branches 'br1', 'br2' and 'br3'$ git checkout HEAD~HEAD is now at 4927c6c... c3

对应的图如下所示:

这时候,HEAD指向了commit 4927,即3b03的第一个父提交ID,但是master引用还是对应的3b03.

从上面的测试,我们可以得出以下结论:

  1. HEAD^,HEAD^1和HEAD~三个表达式都是代表了HEAD的父提交
  2. reset 的时候,HEAD不变,但是HEAD指向的引用值会变成相应的值;checkout 的时候,HEAD直接变成值,但原来引用中保存的值不变。

^n和~n的区别

(|HEAD)^n,指的是HEAD的第n个父提交(HEAD有多个父提交的情况下),如果HEAD有N个父提交,那么n取值为n < = N.

(|HEAD)~n,指的是HEAD的第n个祖先提交,用一个等式来说明就是:(|HEAD)~n = (|HEAD)^^^….(^的个数为n).我们通过例子来验证一下吧。

我们沿用上面演示用的仓库,先检出到master分支,再使用git checkout HEAD^2,看看我们检出了哪个commit

$ git checkout master$ git checkout HEAD^2HEAD is now at 063f6e6... c5

我们发现”c5”对应的commit值063f正是3b03第二个父提交的commit 对应的图如下所示:

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

现在再切回master分支,git checkout master

然后使用git checkout HEAD^3,那么按照规律,就应该检出3b03的第三个父提交的commit,即”c7”的commit值4f9c.$ git checkout masterPrevious HEAD position was 063f6e6... c5Switched to branch 'master'$ git checkout HEAD^3HEAD is now at 4f9ca79... c7

对应的图如下所示:

果然没错,一切都在我们的预料之中!

现在验证下HEAD~的用法,切换到master分支,然后git checkout HEAD~2

$ git checkout master$ git checkout HEAD~2HEAD is now at 1c7383c... c2

这时候HEAD悄然来到了”c2”的commit 1c73,因此,HEAD~2 相当于HEAD的第一个父提交的第一个父提交。即HEAD~2 = HEAD^^ = HEAD^1^1, 符合预期!好开心的哟!

五.总结

  1. “^”代表父提交,当一个提交有多个父提交时,可以通过在”^”后面跟上一个数字,表示第几个父提交,”^”相当于”^1”.
  2. ~相当于连续的个”^”.
  3. checkout只会移动HEAD指针,reset会改变HEAD的引用值。

现在看到^和~两个符号,再也不会彷徨和害怕了,因为我们知道了它们之间的关系及区别

如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级交流:854630135,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家。

git切换分支出现head is now at_git寻根——^和~的区别相关推荐

  1. git切换分支时,如何干净的切换到另一个分支上?

    git切换分支时,如何干净的切换到另一个分支上? 代码热修时,组长说要切一个新分支给我们大家做bug修复使用,所以不能将当前分支的代码迁移污染到新分支 在网上找到了几种方法,做下记录 https:// ...

  2. git切换分支合并后再切回原来分支导致没有提交的代码丢失

    git切换分支合并后再切回原来分支导致没有提交的代码丢失 前言 在企业开发中,总会需要用远程仓库来管理整个团队的项目代码,git是我们常用的代码提交工具,虽然就我个人而言,在开发的过程中就只用到几个简 ...

  3. 解决git切换分支导致代码丢失的问题

    解决git切换分支导致代码丢失的问题 问题背景: ​ 因为本人手里有好几个不同的项目,当手里有正在做的项目,却被临时叫去修改另外一个项目,而此时又不想把现有的代码提交,于是就强制切换到了另外一个分支上 ...

  4. git切换分支遇到的小问题

    能在IDEA编辑器右下角的git分支显示里面看到一个新的分支,但是不能切换到: 各种pull更新操作都不管用,(后来想到可能是用了自己以前的git账户,只有几个分支某一次被管理员给了权限,其他的分支没 ...

  5. Git 切换分支,拉取分支代码指令操作

    git命令切换分支_ZHL's Blog-CSDN博客_git切换分支  git命令切换分支 https://www.jianshu.com/p/856ce249ed78 Git如何拉取指定远程分支 ...

  6. git 切换分支_简单git操作

    首先设置用户基本信息设置 设置用户名 git config - -global user.name 'Hazel6869' 设置用户名邮箱 git config - -global user.name ...

  7. git 切换分支

    git命令-切换分支 Git一般有很多分支,我们clone到本地的时候一般都是master分支,那么如何切换到其他分支呢?主要命令如下: 1. 查看远程分支 $ git branch -a  我在mx ...

  8. Android studio使用git切换分支开发的方法(图文教程)

    涉及到团队开发,所以有了分支开发概念,当我们第一次从仓库git下来的时候一般都是master主分支,因为涉及到权限问题,你无法在主分支master上面提交,你只能进行分支开发提交,但是如何切换主分支呢 ...

  9. git 切换分支_git 入门教程之分支总览

    分支就是一条独立的时间线,既有分支,必有主干,正如一棵树谈到树枝,必有树干一样的道理.我们先前对git 的全部操作默认都是在主干上进行的,这个主干也是一种特殊的分支,名为 master 分支. 无论是 ...

最新文章

  1. 人工智能预测AI系统的“心灵”与“行为”
  2. 这个机械装置真的能够分离彩色小球吗?
  3. 《浙江省推动数据中心能效提升行动方案(2021-2025年)》出炉
  4. IO-4(BufferedInputStream、BufferedInputStream、BufferedReader、BufferedWriter)
  5. [Everyday Mathematics]20150103
  6. python使用spark sql查询impala_如何使用JDBC将Impala表直接加载到Spark?
  7. airpods2突然变得很小声_11岁女孩胸部发育被同学取笑,穿束胸衣上课突然晕倒...
  8. 2017.9.9 幸运数字 失败总结
  9. AI已火,宗教当生,硅谷出了个“洪秀全”
  10. 国际C 语言乱码大赛(IOCCC )
  11. 基于RFID的图书馆管理
  12. Java基础教程——字符流
  13. Access-Control-Allow- 跨域CORS 的使用
  14. gpu浮点计算能力floaps_认识GPU浮点计算精度
  15. 在php中插入表格,word怎么插入表格
  16. 动态规划-背包问题求解过程【代码 from eason】
  17. 大一c语言课设之图书管理系统
  18. 2021-08-31 multisim14 电感电容滤波器的的幅频特性,输入方波,输出正弦波
  19. 多智能体中的图论——图论中的定义(一)
  20. java obervable_了解Java的Observable和JavaFX的Observable

热门文章

  1. 51nod 1256 扩展欧几里得
  2. Silverlight中动画的性能浅析
  3. Android音视频【十二】使用opensles和audiotrack进行播放pcm
  4. dolphin.php 视频,DolphinPHP V1.0.4发布
  5. Android Studio第一个NDK程序
  6. Ubuntu 12.04忘记登录密码及修改密码
  7. Wpf之无法添加wpf窗体
  8. 安装Tensorflow-gpu版本
  9. linux从青铜到王者学习好文
  10. XUbuntu20.04开机logo定制,主题修改启动背景