Git普通仓库和bare仓库
普通仓库(Non-bare Repository)
特点:
- 包含工作目录(Working Directory)
- 包含
.git子目录,存储版本历史 - 可以进行常规的 Git 操作:add、commit、pull、push 等
- 文件可以直接在文件系统中查看和编辑
结构:
project/
├── .git/ # Git 仓库数据
├── src/ # 工作目录中的文件
├── README.md
└── ... # 其他项目文件Bare 仓库(Bare Repository)
特点:
- 没有工作目录,只有 Git 仓库数据
- 通常用作中央仓库或远程仓库
- 不能直接编辑文件,只能接收 push 操作
- 文件名以
.git结尾(如project.git)
结构:
project.git/
├── HEAD
├── config
├── objects/
├── refs/
└── ... # 只有 Git 内部文件,没有项目源文件主要区别总结
| 特性 | 普通仓库 | Bare 仓库 |
|---|---|---|
| 工作目录 | ✅ 有 | ❌ 无 |
| 直接编辑文件 | ✅ 可以 | ❌ 不可以 |
| 用作远程仓库 | ❌ 不推荐 | ✅ 推荐 |
| 接收 push | ❌ 默认不行 | ✅ 可以 |
| 用途 | 本地开发 | 服务器/共享仓库 |
使用场景
普通仓库: 日常开发,在本地进行代码编写和版本控制
Bare 仓库:
- Git 服务器上的中央仓库
- 团队成员共享的远程仓库
- GitHub/GitLab 等平台的仓库结构
创建方式
# 普通仓库
git init
# Bare 仓库
git init --bareBare 仓库的设计主要是为了避免冲突:因为没有工作目录,就不会出现有人在服务器上直接修改文件而导致 push 失败的情况。
所以 Github 这些托码平台,实际上就是远端给你建立了一个 裸(bare)仓库,你 clone 下来之后,实际上是经历了 下载阶段(网络传输)和 重建阶段(本地恢复)。
clone 操作就是:
- 拿到图纸(下载bare数据)
- 按图纸盖房子(重建工作目录)
- 给你一套能住的房子(普通仓库)
额外
SSH
我们都知道 Github 上有 ssh 和 http 两种方式 clone 仓库,ssh 就和上面说的那样,Github 服务器上建立了对应的 bare 仓库给你,你能够根据 Github 给的 ssh 链接进行 clone:
git@github.com:<username>/<reposity_name>.git我们这里看出来,git@github.com 这部分其实就是 <主机名>@<网络IP/域名>。这意味着我们其实创建远端同步仓库,其实也不需要使用托码平台(这貌似是句废话,毕竟本身托码平台就是 Git 的 GUI 便利化操作平台)。
我们可以通过本地虚拟机 + 云服务器进行实现对应操作。我们先在本地虚拟机上创建 ssh 用的公钥和私钥:
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N ""然后把本地虚拟机生成的公钥复制给云服务,自己留有对应私钥,保证连接:
ssh-copy-id -i ~/.ssh/id_ed25519.pub ubuntu@cs.example.com之后 ssh 连接测试一下是否成功就可以了:
ssh ubuntu@cs.example.com之后我们在云服务器上建立一个 bare 仓库:
cd ~ && mkdir test
cd test
git init hello --bare创建好之后我们就可以用本地虚拟机克隆该仓库了:
git clone ubuntu@cs.example.com:~/test/hello运行完之后就会发现本地会多出一个名为 hello 的本地仓库了,这个仓库如之前说的,是遵循远端 bare 仓库生成的本地仓库,在这个仓库里面可以做正常的 Git 流程对应的操作,相当于建立了只供两个机子的单向小 Github。
其实早期没有 Github 这些托码平台的时候,或者本地无对外网络需要互相本地协作,就会使用这样的方法进行合作,这也是 Git 早期的用法了吧。只是现在太方便了都没见过(
HTTP
至于 HTTP 的方式,相对来说比较复杂一些。
客户端把 Git 专用的 want/have 和 pack 数据直接塞进 HTTP/HTTPS POST 请求里,Web 服务器调用 git-http-backend(或 GitLab/Gitea 等内置路由) 解包/打包,鉴权靠 HTTP 401 + Token/Basic/OAuth,加密靠 TLS,下行、上行各一次 POST,完成拉取和推送——和 SSH 完全同级,只是跑在 HTTP 协议上。
大概流程如下:
clone https://repo.git
│
├─→ GET info/refs?service=git-upload-pack (拿分支列表)
├─→ POST git-upload-pack (发 want/have → 收 pack)
│
push https://repo.git
│
├─→ GET info/refs?service=git-receive-pack (拿旧 ref)
└─→ POST git-receive-pack (发 pack + update → 收结果)
RoLingG | 博客
评论(0)