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
相关推荐
回眸&啤酒鸭42 分钟前
【回眸】OpenSwarm 多智能体协作系统实战指南
大数据·前端·人工智能
用户69371750013841 小时前
2026,程序员的时代拐点到了
android·前端·后端
大龄秃头程序员1 小时前
一次 iBeacon + BLE 无感解锁方案的实现记录
前端
小兔子1 小时前
Python 的 GIL 与 free-threading:3.13 之后「去 GIL」走到哪一步了
前端
IT_陈寒1 小时前
SpringBoot自动配置差点让我加班到凌晨
前端·人工智能·后端
guslegend2 小时前
脚手架原理与本地调试:从 bin 软链接到 npm link
前端·npm·node.js·脚手架·前端工程化
海码事务所3 小时前
Google Play 新个人开发者账号上架指南:12 人连续 14 天封闭测试怎么做?
前端
田威AI3 小时前
图片内文字翻译的规格:输入输出、保真、自动化、时间与费用
前端·计算机视觉
不可能片场3 小时前
命令行中文变问号 我用环境变量救了场
前端·electron
lerhxx3 小时前
AI 应用中的上下文管理 —— 从"上下文窗口"到"分层压缩"的工程实践
前端·javascript