玩转 Git 三剑客 · 实操学习博客(真实数据版)
本文所有命令均已在真实的代码托管平台与云主机上执行,文中的仓库地址、commit 哈希、对象 ID、机器信息、部署日志全部来自真实运行结果,非示意。
实操时间:2026-07-20 · 环境:华为云 FlexusX ×4(Ubuntu 24.04.4 LTS)+ GitHub + Gitee
0. 实操环境总览(真实探测结果)
0.1 代码托管平台(通过 API 真实创建)
| 平台 | 账号 | 仓库 | 仓库 ID | 首个 commit |
|---|---|---|---|---|
| GitHub | cpyaxjq | https://github.com/cpyaxjq/git-three-musketeers-demo | 1306388540 | 0e40cc6 |
| Gitee | LiaCin(Lincoln) | https://gitee.com/LiaCin/git-three-musketeers-demo | 49228666 | 0e40cc6 |
两个仓库均由 API 创建(HTTP 201),随后本地
git push推入同一个 commit0e40cc6,实现「一套代码双平台镜像」。
0.2 云主机(4 台,SSH 逐台实测)
| 主机 | 公网 IP | 私网 IP | 系统 | 内核 | 规格 | Git |
|---|---|---|---|---|---|---|
| ecs-6ac4-0001 | 1.92.70.215 | 192.168.0.160 | Ubuntu 24.04.4 LTS | 6.8.0-106-generic | 8 vCPU / 14Gi | 2.43.0 |
| ecs-6ac4-0002 | 1.92.114.92 | 192.168.0.142 | Ubuntu 24.04.4 LTS | 6.8.0-106-generic | 8 vCPU / 14Gi | 2.43.0 |
| ecs-6ac4-0003 | 1.92.94.91 | 192.168.0.123 | Ubuntu 24.04.4 LTS | 6.8.0-106-generic | 8 vCPU / 14Gi | 2.43.0 |
| ecs-6ac4-0004 | 119.3.252.176 | 192.168.0.198 | Ubuntu 24.04.4 LTS | 6.8.0-106-generic | 8 vCPU / 14Gi | 2.43.0 |
四台均为全新实例(
uptime约 30 分钟、load average 0.00、内存占用约 500Mi/14Gi),非常适合做干净的实验。
1. 原理篇:commit / tree / blob 对象模型(ecs-0001 真实验证)
在 ecs-0001 上新建仓库并做 3 次提交,然后直接查看 Git 底层对象。以下全部是真实输出。
cd/root&&mkdirgit-demo&&cdgit-demo&&gitinitmkdir-psrcecho"# Demo">README.mdecho"int main(){return 0;}">src/main.cgitadd-A&&gitcommit-m"commit1: init"echo"v2">>README.md&&gitcommit-am"commit2: edit readme"echo"x">src/a.c&&gitadd-A&&gitcommit-m"commit3: add src/a.c"真实版本历史:
* 18877b0 commit3: add src/a.c * cc5d712 commit2: edit readme * 1d84fe2 commit1: initgit cat-file -t HEAD→commit;git cat-file -p HEAD真实内容:
tree 49e8fdc0ecfca7f6b112784e54ad92bc99606b76 parent cc5d71224223328b476c432a2c8b879919e3ebbf author demo <demo@local> 1784537390 +0800 committer demo <demo@local> 1784537390 +0800 commit3: add src/a.cfind .git/objects -type f | wc -l→ 12 个对象。逐个git cat-file -t得到真实类型分布:
18877b05... -> commit # commit3 (HEAD) cc5d7122... -> commit # commit2 1d84fe29... -> commit # commit1 49e8fdc0... -> tree # commit3 根树 9f097660... -> tree 60059c9f... -> tree 82c71cc0... -> tree cc6c297d... -> tree b2e50482... -> blob 2c99a527... -> blob 587be6b4... -> blob 0805455a... -> blob结论(用真实数据印证课程原理)
- 3 个 commit → 3 个 commit 对象,每个 commit 通过
parent串成链,通过tree指向一次完整快照。 - 12 个对象 = 3 commit + 5 tree + 4 blob。注意 tree 有 5 个而非 3 个:因为有
src/子目录,每次涉及目录变化都会生成新的目录 tree;而内容未变的 blob/tree 会被复用(内容寻址,相同内容只存一份)。 - 这正是课程第 10、11 讲「数一数 tree 的个数」的真实答案:对象数量取决于目录层级与内容变化,而非简单等于提交次数。
commit(18877b0) │ tree 49e8fdc ← commit3 快照 ├── blob README.md └── tree src/ ├── blob main.c └── blob a.c2. 远端同步篇:GitHub + Gitee 双平台真实推送
2.1 通过 API 真实创建仓库
# GitHub(返回 HTTP 201,仓库 id=1306388540)curl-H"Authorization: token <TOKEN>"\-d'{"name":"git-three-musketeers-demo","private":false}'\https://api.github.com/user/repos# Gitee(返回 HTTP 201,仓库 id=49228666)curl-d'{"access_token":"<TOKEN>","name":"git-three-musketeers-demo"}'\https://gitee.com/api/v5/user/repos2.2 本地提交并推送到两个平台
gitclone https://github.com/cpyaxjq/git-three-musketeers-demo.gitcdgit-three-musketeers-demo# 放入博客文件 + README,提交gitadd-Agitcommit-m"docs: 提交 Git 三剑客学习博客(MD+HTML)与 README"# → [main (root-commit) 0e40cc6] 3 files changed, 886 insertions(+)# 推 GitHubgitpush origin main# * [new branch] main -> main# 加 Gitee 远端并推送(镜像)gitremoteaddgitee https://LiaCin:<TOKEN>@gitee.com/LiaCin/git-three-musketeers-demo.gitgitpush gitee main# * [new branch] main -> main真实验证:Gitee API 查询分支 →branches= ['main'];两平台main分支均指向同一 commit0e40cc6。
💡 踩坑记录(真实遇到):Gitee 用
https://<token>@host会触发交互式密码提示导致失败,必须写成https://<用户名>:<token>@host并设GIT_TERMINAL_PROMPT=0。GitHub 则用https://<token>@host即可。
3. 冲突解决篇:同区域冲突真实复现(ecs-0001)
课程第 36 讲「不同人修改了同文件的同一区域」——在 ecs-0001 上用两个分支改同一行,真实制造冲突:
# base: line1 / common / line3gitcheckout-balice&&sed-i's/common/ALICE-change/'app.txt&&gitcommit-am"alice"gitcheckout main&&gitcheckout-bbob&&sed-i's/common/BOB-change/'app.txt&&gitcommit-am"bob"gitmerge alice真实输出:
Auto-merging app.txt CONFLICT (content): Merge conflict in app.txt Automatic merge failed; fix conflicts and then commit the result.冲突文件真实内容(原样):
line1 <<<<<<< HEAD BOB-change ======= ALICE-change >>>>>>> alice line3git status --short→UU app.txt(both modified)。
解决:手动编辑保留正确内容、删除<<<<<<< / ======= / >>>>>>>标记 →git add app.txt→git commit。
4. DevOps 篇一:自建 Git 服务器 + 迷你 CI/CD(多节点真实联动)
Docker Hub 拉 GitLab CE 镜像太大且默认被墙,本次先用最纯粹、零外网依赖的方式验证「自建 Git 服务 + 自动部署」——ecs-0001 当服务器,ecs-0002 当开发机,走私网 SSH。
4.1 服务端(ecs-0001):裸仓库 + post-receive 钩子
mkdir-p/srv/git&&cd/srv/gitgitinit--bareproject.gitcat>project.git/hooks/post-receive<<'HOOK' #!/bin/bash # 迷你 CI/CD:push 后自动检出到部署目录并记录版本 GIT_WORK_TREE=/srv/git/deploy git --git-dir=/srv/git/project.git checkout -f main echo "[$(date '+%F %T')] deployed $(git --git-dir=/srv/git/project.git rev-parse --short HEAD)" >> /srv/git/deploy.log HOOKchmod+x project.git/hooks/post-receive4.2 开发端(ecs-0002):生成密钥 → 授权 → clone → push
ssh-keygen-ted25519-N''-f~/.ssh/id_ed25519# 把公钥写入 ecs-0001 的 ~/.ssh/authorized_keys(真实公钥指纹 root@ecs-6ac4-0002)gitclone ssh://root@192.168.0.160/srv/git/project.git workcdwork&&gitcheckout-bmainecho"# Self-hosted Git server demo">README.mdecho"v1.0.0">VERSIONgitadd-A&&gitcommit-m"feat: 首次提交(多节点自建 Git 服务实测)"gitpush origin main真实结果:
warning: You appear to have cloned an empty repository. remote: Switched to branch 'main' To ssh://192.168.0.160/srv/git/project.git * [new branch] main -> main PUSHED_COMMIT=d73315b3770889422bcb45e82ee3f812ff5231ea4.3 服务端自动部署验证(钩子真实触发)
$ cat /srv/git/deploy.log [2026-07-20 16:58:14] deployed d73315b $ ls /srv/git/deploy README.md VERSION $ cat /srv/git/deploy/VERSION v1.0.0 $ git --git-dir=/srv/git/project.git log --oneline d73315b feat: 首次提交(多节点自建 Git 服务实测)✅一次git push自动触发部署:ecs-0002 推送的 commitd73315b被 ecs-0001 的 post-receive 钩子实时检出到/srv/git/deploy,并写入部署日志。这就是 CI/CD「push 即部署」的最小内核。
5. DevOps 篇二:Docker + Gitea 自建代码平台(真实部署成功)
GitLab CE 镜像约 2GB,5 Mbit/s 带宽下不现实;改用轻量的Gitea(同为自建代码平台,验证同样的 Docker/Web 平台流程)。
5.1 安装 Docker(真实版本)
apt-getinstall-ydocker.io# → Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2systemctlenable--nowdocker5.2 配置国内镜像加速(真实踩坑 → 解决)
首次docker pull直连 Docker Hub超时失败:
failed to resolve reference "docker.io/gitea/gitea": dial tcp 108.160.172.200:443: i/o timeout配置镜像加速器后成功:
cat>/etc/docker/daemon.json<<EOF {"registry-mirrors":["https://docker.m.daocloud.io","https://mirror.ccs.tencentyun.com"]} EOFsystemctl restartdockerdockerpull gitea/gitea:1.22# → Status: Downloaded newer image for gitea/gitea:1.225.3 启动 Gitea 并验证(真实运行中)
dockerrun-d--namegitea--restartalways\-p3000:3000-p2222:22\-v/var/lib/gitea:/data\gitea/gitea:1.22真实验证:
$ docker ps --format '{{.Names}} {{.Status}}' gitea Up 25 seconds $ curl -o /dev/null -w 'gitea_http=%{http_code}' http://127.0.0.1:3000/ gitea_http=200 # 外网访问同样返回 200: $ curl http://1.92.70.215:3000/ → ext_http=200✅ Gitea 已在 ecs-0001 真实运行,浏览器可直接访问 http://1.92.70.215:3000(首次访问需完成安装向导设置管理员)。
⚠️ 端口踩坑(真实):初次用
-p 22:22映射会与宿主机 SSH 的 22 端口冲突导致容器启动失败,改用-p 2222:22即可。
6. 实操总结:真实产出清单
| 类别 | 真实产出 | 凭证 |
|---|---|---|
| GitHub 仓库 | github.com/cpyaxjq/git-three-musketeers-demo | commit0e40cc6,id 1306388540 |
| Gitee 仓库 | gitee.com/LiaCin/git-three-musketeers-demo | commit0e40cc6,id 49228666 |
| Git 对象模型 | ecs-0001 真实 12 对象(3 commit/5 tree/4 blob) | HEAD tree49e8fdc |
| 合并冲突 | ecs-0001 真实同区域冲突 + 标记 | UU app.txt |
| 自建 Git 服务 | ecs-0001 裸仓库 + post-receive 自动部署 | commitd73315b,日志 16:58:14 |
| 多节点协作 | ecs-0002 → ecs-0001 私网 SSH push | ed25519 免密 |
| Docker 平台 | ecs-0001 Docker 29.1.3 + Gitea 1.22 | http://1.92.70.215:3000 (HTTP 200) |
对课程三大主线的真实印证
- Git 原理:commit/tree/blob 不是抽象概念——12 个真实对象、可
cat-file逐一验证,快照与内容寻址一目了然。 - 平台协作:同一 commit 真实推送到 GitHub + Gitee 双平台;踩了 Gitee token URL 格式的坑。
- GitLab/DevOps:用 post-receive 钩子实现了「push 即部署」的 CI/CD 最小内核;用 Docker + Gitea 真实搭起了 Web 代码平台(GitLab 的轻量替身,流程完全一致)。
安全说明:本文所有 token / 密码一律以
<TOKEN>占位,真实凭据未写入任何仓库或文档。自建服务默认仅演示,生产环境请开启 HTTPS、分支保护、最小权限。