🔥 Git 从零到精通:彻底搞懂核心概念与工作原理

0 阅读10分钟

🔥 Git 从零到精通:彻底搞懂核心概念与工作原理

摘要git push 报错看不懂?分支到底是啥?本地远程怎么关联的?本文用最通俗的比喻,带你彻底搞懂 Git 的核心概念和底层原理。


📌 前言

你有没有遇到过这些场景?

  • git push 报错 no upstream branch,完全不知道啥意思
  • 本地分支叫 master,远程叫 main,死活推不上去
  • git pullgit fetch 到底有啥区别?
  • 分支到底是文件夹还是什么?创建分支费空间吗?

如果你有过哪怕一个疑问,这篇文章就是为你写的。本文不只教你"怎么用",更要让你彻底明白"为什么"。


📚 一、Git 到底是什么?

Git 是一个分布式版本控制系统(DVCS),用于跟踪文件(尤其是源代码)随时间的变化。

通俗地说:Git = 代码的"时光机" + 团队协作的"中台"

它的三大核心能力:

能力说明
🕰️ 版本回退代码改崩了?一键回到任意历史版本
🌿 分支管理在副本里随便折腾,不影响主线
👥 多人协作自动合并多人修改,冲突时明确提示

Git ≠ GitHub:Git 是安装在你电脑上的工具,GitHub/Gitee 是远程托管平台(网站)。你完全可以在没有 GitHub 的情况下使用 Git,但有了 GitHub 可以方便协作和备份。


📚 二、提交(Commit)—— 一切的基础

Git 记录的不是"文件差异",而是"项目全貌的快照"。

每次 git commit,Git 都会:

  1. 把当前所有文件的状态拍一张"照片"(快照)
  2. 给这张照片一个唯一的 SHA-1 哈希值(如 a1b2c3d4
  3. 这张照片还带一个指针,指向上一次拍的照片(父提交

所有的"照片"通过指针串成一条单向时间链

AB ← C ← D  (HEAD)

🎮 就像玩单机游戏,每次 commit 就是存一次档。存档里记录了所有装备的状态,还记着"这个存档基于上一个存档"。

Git 中每个对象都有一个 SHA-1 哈希值作为唯一标识(40 个字符),内容相同则哈希相同,这就是为什么 Git 叫**"内容寻址文件系统"**。


📚 三、三棵树 —— Git 的核心工作区

你平时敲的每一条命令,本质上都是在这三个区域之间搬运数据。

┌─────────────┐    git add    ┌─────────────┐   git commit   ┌─────────────┐
│   工作区     │ ──────────→  │   暂存区     │ ──────────→   │  本地仓库    │
│ (Workspace) │              │  (Index/     │              │ (Repository) │
│             │ ←──────────  │   Stage)     │              │              │
└─────────────┘  git restore  └─────────────┘              └─────────────┘
     你看到的                    "购物车"                    "存档数据库"
     文件夹
区域是什么对应命令
工作区你电脑上看到的项目文件夹直接编辑文件
暂存区准备下次提交的"购物车"git add
本地仓库存储所有提交历史的数据库(.git/ 文件夹)git commit
echo "hello" > hello.txt    # 工作区变了,暂存区和仓库不知道
git add hello.txt            # 放进暂存区(购物车)
git commit -m "add hello"   # 拍成永久照片(存入仓库)

💡 修改必须经过暂存区才能进入仓库(commit -am 可跳过,但只对已 add 过的文件有效)。

.gitignore —— 告诉 Git "别管这些文件"

.gitignore 告诉 Git 哪些文件不需要被版本控制:

node_modules/    # 忽略目录
*.log            # 忽略所有 .log 文件
.env             # 忽略环境变量(含密码!)
/build           # 只忽略根目录下的 build
!README.md       # 取反,不忽略这个文件

💡 项目一开始就创建 .gitignore,而不是提交了垃圾文件后再补救。GitHub 提供了各种语言的模板


📚 四、分支(Branch)—— 最容易误解的概念

分支的本质:一个指向提交的轻量指针

分支不是文件夹,而是一个 40 字符的指针文件。

git branch dev
# Git 做了什么?仅仅创建了一个文件 .git/refs/heads/dev
# 文件内容就是某个提交的哈希值

🎯 你的时间线是一串珍珠。分支就是一根额外的针,串在某颗珍珠上。你在这根针上继续穿新珍珠(提交),完全不影响原来那根针的走向。

HEAD —— 你在哪?

HEAD 是一个特殊指针,指向你当前所在的分支

           HEAD
            ↓
          master
            ↓
AB ← C ← D

          dev
           ↓
AB ← C ← E
  • git switch dev → HEAD 从 master 移到 dev
  • git commit → dev 指针前移,master 不动
  • git reset --hard HEAD~1 → 当前分支指针后退

分支操作的本质

git branch feature     # 创建指针(不切换)
git switch feature     # HEAD → feature,工作区更新
git switch -c feature  # 创建并切换(上面两步合一)
git branch -d feature  # 删除指针(提交历史不受影响)
git merge feature      # 合并两个分支

merge vs rebase

操作效果安全性
merge生成合并提交,保留完整分支历史✅ 安全
rebase把提交"移植"到目标分支之上,线性历史⚠️ 改写历史,慎用
# merge:AB ← C ← F (main, F是合并提交)  ↗ D ← E (feature)
# rebase:AB ← C ← D' ← E' (main, 线性)

📚 五、远程仓库 —— 本地和远程如何关联

远程仓库是什么?

远程仓库是在 GitHub/Gitee 网页端点击"新建仓库"创建的,和你的本地仓库完全独立,直到你主动把它们"连上线"。

关联机制

git remote add origin https://gitee.com/xxx/repo.git

这条命令在 .git/config 中写入:

[remote "origin"]
    url = https://gitee.com/xxx/repo.git
    fetch = +refs/heads/*:refs/remotes/origin/*

📒 你在本地给远方的"云端书库"起了个外号叫 origin,并记下了它的门牌号(URL)。

关联 ≠ 实时连线:Git 是去中心化的,平时切分支、写代码完全不用联网,只有 git push/git pull 时才会通过地址去"敲门"交换数据。

远程跟踪分支 —— 最容易误解的概念

origin/master 不是远程的分支本身,而是"上次我从远程抓取时,远程 master 指向哪"的快照。

本地仓库                              远程仓库(Gitee)
┌─────────────────────┐              ┌─────────────────────┐
│ 本地分支:            │              │ 远程分支:            │
│   master → commit D  │  git push   │   master → commit D  │
│                      │ ─────────→  │                      │
│ 远程跟踪分支:        │  git fetch  │                      │
│   origin/master → D  │ ←─────────  │                      │
└─────────────────────┘              └─────────────────────┘

fetch vs pull

git fetch origin      # 只下载,不合并(工作区不变)
git pull origin main  # = fetch + merge(下载并合并)

💡 先 fetch 看看远程有什么变化,确认没问题再 merge,比直接 pull 更安全。

master 和 main

它们和 devfeature 没有任何区别,都是指向提交的指针,只是默认主分支的名字。

  • master:Git 早期默认名称
  • main:2020 年起 GitHub/Gitee 的新默认

本地分支名和远程分支名各自独立确定,完全不需要同名!

场景本地名远程名
git init读取 init.defaultBranch 配置不涉及
git clone跟随远程默认分支名(可改)网页端创建时确定
git push origin dev已确定推送瞬间创建同名分支
git push origin dev:release已确定推送瞬间创建名为 release 的分支

上游分支(Upstream)和 -u 参数

git push -u origin master 做了两件事:推送代码 + .git/config 中建立映射

[branch "master"]
    remote = origin
    merge = refs/heads/master

翻译:以后 master 分支的 push/pull,默认就找 origin 的 master。

没有这个配置,Git 不知道该推到哪,就会报错:

fatal: The current branch master has no upstream branch.

-u 就是给当前分支绑定一个"默认快递地址"。

--force vs --force-with-lease

参数行为安全性
--force不管远程有什么,直接覆盖❌ 会覆盖同事的代码
--force-with-lease先检查远程是否被别人动过,没动过才覆盖✅ 安全

📚 六、撤销与回退 —— Git 的"后悔药"

三种 reset

参数提交暂存区工作区
--soft❌ 回退✅ 保留✅ 保留
--mixed(默认)❌ 回退❌ 清空✅ 保留
--hard❌ 回退❌ 清空❌ 清空

revert vs reset

  • reset:移动指针,改写历史 → 适合本地还没推送的提交
  • revert:生成新提交来撤销,历史保留 → 适合已推送到远程的提交

reflog —— 终极后悔药

reset --hard 之后提交就丢了?并没有!

git reflog
# abc1234 HEAD@{0}: reset: moving to HEAD~1
# def5678 HEAD@{1}: commit: feat: 添加登录功能

即使你用 reset --hard 丢弃了提交,reflog 仍然记得它在哪:

git reset --hard def5678   # 找回被丢弃的提交
git branch recovery def5678 # 或创建新分支来恢复

🎯 reflog 就是 Git 的"行车记录仪",记录了 HEAD 的每一次移动。默认保留 90 天。


📚 七、常用命令速查表

# ===== 配置 =====
git config --global user.name "名字"
git config --global user.email "邮箱"
git config --list                                    # 查看所有配置

# ===== 基本操作 =====
git init                                             # 创建新仓库
git clone <URL>                                      # 克隆远程仓库
git status                                           # 查看状态
git add <文件>                                       # 添加到暂存区
git add .                                            # 添加所有修改
git commit -m "说明"                                  # 提交
git commit -am "说明"                                 # 跳过 add,直接提交已跟踪文件
git log --oneline --graph --all                      # 简洁图形化日志

# ===== 分支管理 =====
git branch                                           # 列出分支
git switch <分支名>                                   # 切换分支
git switch -c <新分支名>                              # 创建并切换
git merge <分支名>                                    # 合并分支
git branch -d <分支名>                                # 删除已合并分支

# ===== 远程仓库 =====
git remote -v                                        # 查看远程地址
git remote add origin <URL>                          # 添加远程仓库
git push -u origin <分支名>                           # 首次推送并关联上游
git push                                             # 推送
git pull                                             # 拉取并合并
git fetch                                            # 仅拉取,不合并

# ===== 撤销回退 =====
git restore --staged <文件>                           # 从暂存区撤出
git restore <文件>                                    # 丢弃工作区修改
git reset --soft HEAD~1                              # 撤销提交,保留到暂存区
git reset --hard HEAD~1                              # 彻底回退(谨慎!)
git revert <提交哈希>                                 # 安全撤销(生成新提交)
git reflog                                           # 查看所有操作记录

# ===== 实用技巧 =====
git stash                                            # 暂存未提交的修改
git stash pop                                        # 恢复并删除暂存
git cherry-pick <提交哈希>                            # 将指定提交应用到当前分支
git tag -a <标签名> -m "说明"                         # 创建附注标签

📚 八、实战场景

场景 1:初次提交到远程

git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/xxx/repo.git
git push -u origin main

场景 2:解决冲突

git pull origin main  # 有冲突时,Git 会在文件中插入标记:
<<<<<<< HEAD
// 你的代码
=======
// 同事的代码
>>>>>>> feature/login

解决步骤:找到 <<<<<<< → 决定保留哪部分 → 删除所有冲突标记 → git addgit commit

场景 3:临时保存工作

git stash                    # 暂存当前修改
git switch other-branch      # 切换分支干活
git switch original-branch   # 切回来
git stash pop                # 恢复之前暂存的修改

场景 4:误删文件恢复

rm important.js              # 哎呀,删错了
git restore important.js     # 从暂存区恢复

# 如果已经 commit 了删除操作:
git reflog                   # 找到删除前的提交哈希
git checkout abc123 -- important.js  # 恢复文件

💡 总结:记住这几句话

  1. Git 记录的是快照,不是差异
  2. 分支只是一个 40 字符的指针文件,创建分支几乎不费空间
  3. HEAD 指向分支,分支指向提交,提交指向父提交
  4. 本地仓库和远程仓库是两个独立个体,通过 URL 关联
  5. 本地分支名和远程分支名完全独立,可以不同
  6. -u 就是给当前分支绑定一个"默认快递地址"
  7. --force-with-lease--force 安全,因为它会检查远程是否被别人动过
  8. reflog 是终极后悔药,reset --hard 也能找回
概念本质类比
提交(Commit)项目快照 + 父指针游戏存档
分支(Branch)指向提交的轻量指针书签
HEAD指向当前分支的指针你手里拿着的书签
暂存区(Index)下次提交的准备区购物车
远程仓库另一台电脑上的完整仓库云端硬盘
origin/master上次看到的远程状态快照远端传真照片
上游分支本地和远程分支的映射关系默认快递地址

🔗 参考资料


觉得有用?点个赞👍收藏⭐关注👆,后续会更新更多 Git 高级用法(rebase -i、cherry-pick、submodule、Git Hooks 等)!