git原理解密

前言
近几年技术发展十分迅猛,让部分同学养成了一种学习知识停留在表面,只会调用一些指令的习惯。我们时常有一种“我会用这个技术、这个框架”的错觉,等到真正遇到问题,才发现事情没有那么简单。

而Git也是一个大部分人都知道如何去使用它,知道有哪些命令,却只有少部分人知道具体原理的东西。了解一些底层的东西,可以更好的帮你理清思路,知道你真正在操作什么,不会迷失在Git大量的指令和参数上面。

Git是怎么储存信息的

这里会用一个简单的例子让大家直观感受一下git是怎么储存信息的。

首先我们先创建两个文件

$ git init
$ echo '111' > a.txt
$ echo '222' > b.txt
$ git add *.txt

Git会将整个数据库储存在.git/目录下,如果你此时去查看.git/objects目录,你会发现仓库里面多了两个object。

$ tree .git/objects
.git/objects
├── 58
│   └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
├── c2
│   └── 00906efd24ec5e783bee7f23b5d7c941b0c12c
├── info
└── pack

好奇的我们来看一下里面存的是什么东西

$ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c
xKOR0a044K%

怎么是一串乱码?这是因为Git将信息压缩成二进制文件。但是不用担心,因为Git也提供了一个能够帮助你探索它的api git cat-file [-t] [-p], -t可以查看object的类型,-p可以查看object储存的具体内容。

$ git cat-file -t 58c9
blob
$ git cat-file -p 58c9
111

可以发现这个object是一个blob类型的节点,他的内容是111,也就是说这个object储存着a.txt文件的内容。

这里我们遇到第一种Git object,blob类型,它只储存的是一个文件的内容,不包括文件名等其他信息。然后将这些信息经过SHA1哈希算法得到对应的哈希值
58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c,作为这个object在Git仓库中的唯一身份证。

也就是说,我们此时的Git仓库是这样子的:
在这里插入图片描述
我们继续探索,我们创建一个commit。

$ git commit -am '[+] init'
$ tree .git/objects
.git/objects
├── 0c
│   └── 96bfc59d0f02317d002ebbf8318f46c7e47ab2
├── 4c
│   └── aaa1a9ae0b274fba9e3675f9ef071616e5b209
...

我们会发现当我们commit完成之后,Git仓库里面多出来两个object。同样使用cat-file命令,我们看看它们分别是什么类型以及具体的内容是什么。

$ git cat-file -t 4caaa1
tree
$ git cat-file -p 4caaa1
100644 blob 58c9bdf9d017fcd178dc8c0...     a.txt
100644 blob c200906efd24ec5e783bee7...    b.txt

这里我们遇到了第二种Git object类型——tree,它将当前的目录结构打了一个快照。从它储存的内容来看可以发现它储存了一个目录结构(类似于文件夹),以及每一个文件(或者子文件夹)的权限、类型、对应的身份证(SHA1值)、以及文件名。

此时的Git仓库是这样的:
在这里插入图片描述

$ git cat-file -t 0c96bf
commit
$ git cat-file -p 0c96bf
tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209
author lzane 李泽帆  1573302343 +0800
committer lzane 李泽帆  1573302343 +0800
[+] init

接着我们发现了第三种Git object类型——commit,它储存的是一个提交的信息,包括对应目录结构的快照tree的哈希值,上一个提交的哈希值(这里由于是第一个提交,所以没有父节点。在一个merge提交中还会出现多个父节点),提交的作者以及提交的具体时间,最后是该提交的信息。

此时我们去看Git仓库是这样的:
在这里插入图片描述
到这里我们就知道Git是怎么储存一个提交的信息的了,那有同学就会问,我们平常接触的分支信息储存在哪里呢?

$ cat .git/HEAD
ref: refs/heads/master
$ cat .git/refs/heads/master
0c96bfc59d0f02317d002ebbf8318f46c7e47ab2

在Git仓库里面,HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应commit的SHA1值。
在这里插入图片描述

其实还有第四种Git object,类型是tag,在添加含附注的tag(git tag -a)的时候会新建,这里不详细介绍,有兴趣的朋友按照上文中的方法可以深入探究。

至此我们知道了Git是什么储存一个文件的内容、目录结构、commit信息和分支的。其本质上是一个key-value的数据库加上默克尔树形成的有向无环图(DAG)。

接下来我们来看一下Git的三个分区(工作目录、Index 索引区域、Git仓库),以及Git变更记录是怎么形成的。了解这三个分区和Git链的内部原理之后可以对Git的众多指令有一个“可视化”的理解,不会再经常搞混。

接着上面的例子,目前的仓库状态如下:
在这里插入图片描述

这里有三个区域,他们所储存的信息分别是:

工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。
索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次commit被提交到Git仓库。
Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。
我们来看一下更新一个文件的内容这个过程会发生什么事。

在这里插入图片描述
运行echo “333” > a.txt将a.txt的内容从111修改成333,此时如上图可以看到,此时索引区域和git仓库没有任何变化。

在这里插入图片描述
运行git add a.txt将a.txt加入到索引区域,此时如上图所示,git在仓库里面新建了一个blob object,储存了新的文件内容。并且更新了索引将a.txt指向了新建的blob object。

在这里插入图片描述
运行git commit -m 'update’提交这次修改。如上图所示

Git首先根据当前的索引生产一个tree object,充当新提交的一个快照。
创建一个新的commit object,将这次commit的信息储存起来,并且parent指向上一个commit,组成一条链记录变更历史。
将master分支的指针移到新的commit结点。
至此我们知道了Git的三个分区分别是什么以及他们的作用,以及历史链是怎么被建立起来的。基本上Git的大部分指令就是在操作这三个分区以及这条链。

Git分支

Git基础 中介绍了Git提交时会保存一个提交对象,这个对象记录着提交版本的目录结构指针以及文件快照指针。

Git 的分支,其实本质上仅仅是指向提交对象的可变指针。 Git 的默认分支名字是 master。 在多次提交操作之后,你其实已经有一个指向最后那个提交对象的 master 分支。 它会在每次的提交操作中自动向前移动。
在这里插入图片描述

Git 的 “master” 分支并不是一个特殊分

<think>好的,用户想了解GitSSH密钥的工作原理及操作方法。首先我需要整理一下SSH密钥在Git中的作用流程。根据引用[2],Git使用SSH进行认证,主要步骤包括生成密钥对、添加公钥到托管平台、配置私钥到ssh-agent。用户可能想知道为什么需要这些步骤,以及背后的原理。接下来,要解释SSH密钥的工作原理。SSH基于非对称加密,私钥保存在本地,公钥上传到服务器。当用户连接时,服务器用公钥加密挑战消息,客户端用私钥解密验证身份。引用[1]和[4]提到SSH用于免密码登录,这也是Git使用SSH密钥的原因,避免每次操作输入密码。然后,操作方法部分需要详细步骤。生成密钥对使用ssh-keygen命令,默认保存在~/.ssh/id_rsa和.pub文件,如引用[2]所述。添加公钥到GitLab或GitHub的设置中,这部分引用[1]和[2]都有说明。然后启动ssh-agent并添加私钥,确保Git操作时自动使用密钥,引用[1]给出了具体的命令。可能还需要解决常见问题,比如密钥权限问题,或者不同算法的支持。引用[5]提到如果使用较旧的RSA算法,可能需要调整配置,尤其是OpenSSH版本较高时。这可以作为注意事项补充。用户可能还会遇到Hostkey验证失败的情况,如引用[4]中的例子,这时候需要确认服务器的指纹,输入yes接受。这属于SSH连接的正常流程,确保安全性。 最后,总结原理和步骤,确保用户能够按照教程操作。同时生成相关问题,帮助用户深入理解,比如不同加密算法的选择、多密钥管理或故障排除方法。这些相关问题可以基于引用中的内容扩展,比如引用[5]提到的算法问题,或者引用[3]中的Git基本使用。</think>### Git SSH密钥原理与配置教程 #### 一、SSH密钥工作原理 1. **非对称加密机制** SSH密钥基于非对称加密算法(如RSA、Ed25519),生成一对密钥: - **私钥**(如`~/.ssh/id_rsa`)保存在本地,需严格保密。 - **公钥**(如`~/.ssh/id_rsa.pub`)可公开上传到Git服务器(如GitHub/GitLab)[^2][^4]。 2. **认证流程** - 当用户通过SSH连接Git服务器时,服务器生成随机字符串并用公钥加密。 - 客户端用私钥解密并返回结果,服务器验证成功后允许访问[^2][^4]。 3. **免密码操作** 通过密钥认证可避免每次操作输入密码,提升效率与安全性[^1][^4]。 --- #### 二、配置步骤 ##### 1. 生成SSH密钥对 ```bash ssh-keygen -t ed25519 -C "[email protected]" ``` - `-t`指定算法(推荐`ed25519`,兼容性差时用`rsa`) - 默认保存路径:`~/.ssh/id_ed25519`(私钥)和`.pub`(公钥)[^2][^5]。 ##### 2. 添加公钥到Git服务器 1. 复制公钥内容: ```bash cat ~/.ssh/id_ed25519.pub ``` 2. 进入GitLab/GitHub设置页面的**SSH Keys**,粘贴并保存[^1][^2]。 ##### 3. 配置私钥到ssh-agent ```bash eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519 ``` - `ssh-agent`管理私钥,避免每次手动输入密码[^1][^2]。 ##### 4. 验证连接 ```bash ssh -T git@github.com # GitHub ssh -T git@gitlab.com # GitLab ``` 成功显示`You've successfully authenticated`即配置完成[^2][^4]。 --- #### 三、注意事项 1. **密钥权限** 确保私钥文件权限为`600`,目录权限为`700`: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/id_ed25519 ``` 2. **多密钥管理** 若需为不同平台配置独立密钥,在`~/.ssh/config`中指定: ```config Host gitlab.com IdentityFile ~/.ssh/gitlab_key Host github.com IdentityFile ~/.ssh/github_key ``` 3. **兼容性问题** 若使用旧版RSA密钥,需在`~/.ssh/config`添加: ```config Host * PubkeyAcceptedAlgorithms +ssh-rsa ``` 解决OpenSSH 8.8+默认禁用RSA的问题[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值