git HEAD理解和使用

git HEAD理解和使用

理解HEAD是迈入git高级的门槛,具有非常重要的意义。本文介绍了git中HEAD相关概念,然后从HEAD的角度出发,对一些常见的git指令进行了解读。

分支和HEAD和指针

  1. HEAD的本质 是指向某个commit对象的指针;
  2. 分支指针的本质 是指向某个commit对象的指针;
  3. 补充分支指针和分支的概念。分支是git库中众多commit对象的组织方式 ,所以分支又可以看成是commit对象链表 。而分支指针则指向这个链表的尾部。借用C语言中的知识,可以用分支指针完全表示这个commit链表,所以分支指针就是分支(正如int a[] = {1,2,3};中的a的含义一样)。
  4. 所以HEAD的本质和分支指针的本质是相同的。
  5. 那么它们之间有什么关系呢?分支指针指向的是所在分支最新提交 产生的commit对象;而HEAD指向的是某一个分支最新提交 产生的commit对象。也就是说HEAD肯定是 分支指针,而只有被激活的分支(或者称为"当前分支")的分支指针才可以被称为是HEAD。
  6. 用程序的方式来理解: // 创建三个分支a,b,c int a[] = {1,2,3}; int b[] = {4,5,6}; int c[] = {7,8,9}; // HEAD,也就是p,在a分支上,表示当前分支为a int *p = a; // 切换到了b分支上, HEAD指向b p = b; // HEAD切换到了c分支上, HEAD指向c p = c; // 分支指针是不可以移动的,但是HEAD可以 // c++ Error p++ // 表示HEAD指向了c分支上不同的commit对象
c++ 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    int a[] = {1,2,3};
    int b[] = {4,5,6};
    int c[] = {7,8,9};

    int* p = a; // 指向a分支的起始位置

    printf("%d\n", *p); // 输出a分支的第一个元素

    p = b; // 切换到b分支,将指针p指向b分支的起始位置
    printf("%d\n", *p); // 输出b分支的第一个元素

    p = c; // 切换到c分支,将指针p指向c分支的起始位置
    printf("%d\n", *p); // 输出c分支的第一个元素

    // 分支指针是不可以移动的,但是HEAD可以,这里涉及到指针运算
    // c++;
    p++; // HEAD指向了c分支上其他commit对象
    printf("%d\n", *p);
    getchar();
    return 0;
}

HEAD表达式

  • HEAD 指向当前分支最新的提交。
  • HEAD~ 等同于 HEAD^,表示当前提交的父提交。
  • HEAD^ 表示当前提交的第一个父提交。
  • HEAD~n 表示当前提交的第 n 代祖先提交。

HEAD相关操作

下面举一些常见的git操作,也许你已经对这些操作了如指掌,但是这次我们从HEAD的角度来理解一下这些操作的含义:

  • 查看当前 HEAD 的位置:使用 git rev-parse HEAD 命令可以查看 HEAD 所指向的提交的 SHA 值。

  • 切换到另一个分支:使用 git checkout branch-name 命令可以切换到另一个分支,并将 HEAD 指针移动到该分支。

  • 创建新分支并切换到该分支:通过 git checkout -b new-branch-name 命令可以在当前 HEAD 所在的提交上创建一个新分支,并立即切换到该分支,对应到上述代码,相当于是int* p = a;。

  • 撤销最新的提交:使用 git reset --hard HEAD^ 命令可以撤销最新的提交,并回退到上一个提交状态,之所以有这种效果,在于HEAD~或者HEAD^是HEAD的上一次提交,也就是倒数第二次提交。

  • 查看特定文件在 HEAD 版本的内容:使用 git show HEAD:path/to/file 命令可以查看 HEAD 版本中某个文件的具体内容,当然git show HEAD~n:path/to/file也是可以的。

  • 检出特定提交:使用 git checkout commit-hash 命令可以将 HEAD 指针移动到特定的提交,以查看该提交的内容或创建一个分离的 HEAD 状态(说人话就是打上tag),这种情况实际上就是上面代码中的p++,虽然分支指针不能移动(正如不能对数组变量进行运算),但是指向分支指针的HEAD可以移动。

  • 创建临时分支:通过 git checkout -b temporary-branch-name 命令可以在当前 HEAD 所在的提交上创建一个临时分支,一般来说修改bug的时候会创建临时分支,这种一般称为hotfixes分支。

  • 移动 HEAD 到指定分支的最新提交:使用 git checkout branch-name 和 git pull 命令可以将 HEAD 指针移动到某个特定分支的最新提交,就是上面代码中p从指向a数组变成了指向b或者c数组。

  • 查看 HEAD 所在分支的状态:使用 git status 命令可以查看当前 HEAD 所在分支的状态,包括已修改、已暂存和未跟踪的文件。

  • 执行交互式的 rebase 操作:使用 git rebase -i HEAD~n 命令可以执行交互式的变基操作,编辑、合并或重新排序提交;这个代码简单理解成对最近n次提交进行操作,不要和"变基"这么猥琐的词联系起来。

  • 创建轻量级标签:通过 git tag tag-name 命令可以创建一个轻量级标签,它只是指向当前 HEAD 指针所在的提交;简单来说就是给当前HEAD指向的commit对象起个别名,并将别名记录下来以便日后使用,一般对于有参考意义的重大commit进行此操作。

  • 查看 HEAD 所在分支的提交图形:使用 git log --graph 命令可以以图形化方式展示当前 HEAD 所在分支的提交历史。

  • 检查 HEAD 是否指向某个分支:使用 git symbolic-ref --short HEAD 命令可以确定 HEAD 是否指向一个分支,即返回当前所在的分支的分支名。

总结一下:

上述的命令可以大致分成下面几类:

  1. 查看状态类:
  • git rev-parse HEAD
  • git show HEAD:path/to/file
  • git status
  • git log --graph
  • git symbolic-ref --short HEAD
  1. 切换分支类:
  • git checkout branch-name
  • git checkout -b new-branch-name
  • git checkout -b temporary-branch-name
  1. 同分支内移动类:
  • git reset --hard HEAD^
  • git pull
  • git rebase -i HEAD~n
  1. 直接操作commit类:
  • git checkout commit-hash
  • git tag tag-name
相关推荐
栀椩1 分钟前
Electron 内嵌页面跨域问题(CORS/PNA)解决全记录
前端·javascript·electron
asaotomo7 分钟前
截图识题、AI 讲解、笔记沉淀:Chrome 扩展体验
前端·chrome·笔记
前端架构师-老李8 分钟前
HTML与CSS基础第五课—HTML的空格、换行、横线相关知识
前端·css·html
SEO_juper10 分钟前
Chrome 扩展一键查看当前页面 SEO 信息:不用切页面,点一下全出来
前端·javascript·chrome
Nymph_Zhu16 分钟前
vue3+element-plus 文件上传
前端·typescript·vue3·element-plus
echome88822 分钟前
CSS 布局:Flex 和 Grid 怎么选,附常见坑
前端·css·html
计算机魔术师28 分钟前
科技巨头砸7400亿押注AI,为什么苹果成了唯一赢家?
前端
QianhangQianping38 分钟前
撤销重做不是「存快照」:一个可视化编辑器的Operation 设计
java·前端·数据库·typescript·编辑器·前端架构·撤销重做
赵民勇1 小时前
Git命令详解
git
Nymph_Zhu1 小时前
pdf转换markdown预览及内容互相点击定位
前端·pdf·vue3·markdown·element-plus