返回文章列表
·30 分钟阅读

Git 从入门到协作:原理、命令与安全工作流

从三棵树和内容寻址模型开始,掌握日常 Git 命令、分支协作、冲突处理、回退与发布。

"技术笔记""Git""GitHub""基础"

核心理念:AI 时代不再需要死背命令行参数,但理解 Git 底层机制比以往任何时候都更加关键。精准的原理认知能帮我们写出最精确的 AI 提示词,让 AI 成为你的 Git 协驾,而非盲目执行的隐患。

本指南以 「底盘原理 📘 + VS Code 视觉操作 💻 + AI 降维打击 🤖」 的卡片化形式,带你通关 Git 核心模型。


📋 基础命令速查表

以下是日常开发中最常用的 Git 基础命令,涵盖仓库初始化、状态查看、分支管理、远程协作等场景。本文后续章节会深入讲解进阶操作(stash、rebase、cherry-pick 等),此处先打好地基。

仓库初始化与克隆

命令作用示例
git init在当前目录初始化一个新的 Git 仓库git init my-project
git clone <url>克隆远程仓库到本地git clone https://github.com/user/repo.git
git clone <url> <dir>克隆到指定目录名git clone https://github.com/user/repo.git my-local

状态查看与信息浏览

命令作用示例
git status查看工作区和暂存区的状态git status
git status -s简洁模式输出状态git status -s
git log查看提交历史git log
git log --oneline单行简洁模式git log --oneline
git log --oneline -10只看最近 10 条git log --oneline -10
git log --graph图形化显示分支合并历史git log --oneline --graph --all
git diff查看工作区与暂存区的差异git diff
git diff --staged查看暂存区与上次 commit 的差异git diff --staged
git diff <branch1> <branch2>比较两个分支的差异git diff main feature/login
git show <commit>查看某次 commit 的详细内容git show a1b2c3d
git blame <file>逐行查看文件的最后修改者git blame src/app.py

分支管理

命令作用示例
git branch查看本地分支列表(* 标记当前分支)git branch
git branch -a查看所有分支(含远程分支)git branch -a
git branch -v查看各分支最后一次提交git branch -v
git branch <name>创建新分支(不切换)git branch feature/login
git branch -d <name>删除已合并的分支git branch -d feature/old
git branch -D <name>强制删除分支(即使未合并)git branch -D feature/abandoned
git branch -m <old> <new>重命名分支git branch -m feature/login feature/auth
git switch <branch>切换到指定分支(推荐,Git 2.23+)git switch main
git switch -c <name>创建并切换到新分支git switch -c feature/signup
git checkout <branch>切换分支(传统方式)git checkout main
git checkout -b <name>创建并切换分支(传统方式)git checkout -b feature/signup

💡 switch vs checkout:Git 2.23 引入了 git switchgit restore,将 checkout 的「切换分支」和「恢复文件」两个职责拆分开来,语义更清晰。新手推荐用 switch/restore,老手两者皆可。

暂存与提交

命令作用示例
git add <file>将指定文件加入暂存区git add src/app.py
git add .将当前目录所有修改加入暂存区git add .
git add -p交互式选择要暂存的代码块git add -p
git commit -m "msg"提交暂存区内容git commit -m "feat: add login"
git commit -am "msg"跳过 add,直接提交已跟踪文件的修改git commit -am "fix: typo"
git commit --amend修改最近一次 commit(message 或内容)git commit --amend -m "fix: typo"
git restore <file>丢弃工作区的修改(恢复到暂存区状态)git restore src/app.py
git restore --staged <file>取消暂存(将文件从暂存区移回工作区)git restore --staged src/app.py
git reset HEAD <file>取消暂存(传统方式,同上)git reset HEAD src/app.py

远程仓库操作

命令作用示例
git remote -v查看远程仓库地址git remote -v
git remote add <name> <url>添加远程仓库git remote add origin https://github.com/user/repo.git
git remote remove <name>移除远程仓库git remote remove upstream
git fetch <remote>拉取远程更新(不合并)git fetch origin
git fetch --all拉取所有远程仓库的更新git fetch --all
git pull拉取远程更新并合并到当前分支git pull origin main
git pull --rebase拉取并用 rebase 代替 merge 合并git pull --rebase origin main
git push推送本地提交到远程git push origin main
git push -u origin <branch>推送并设置上游跟踪关系git push -u origin feature/login
git push origin --delete <branch>删除远程分支git push origin --delete feature/old

标签管理

命令作用示例
git tag查看所有标签git tag
git tag <name>创建轻量标签git tag v1.0.0
git tag -a <name> -m "msg"创建附注标签(含描述信息)git tag -a v1.0.0 -m "首次正式发布"
git tag -d <name>删除本地标签git tag -d v1.0.0
git push origin <tag>推送标签到远程git push origin v1.0.0
git push origin --tags推送所有本地标签git push origin --tags

撤销与回退

命令作用示例
git reset --soft <commit>回退到指定 commit,保留修改在暂存区git reset --soft HEAD~1
git reset --mixed <commit>回退到指定 commit,保留修改在工作区(默认)git reset --mixed HEAD~1
git reset --hard <commit>回退到指定 commit,丢弃所有修改 ⚠️git reset --hard HEAD~1
git revert <commit>创建一个新 commit 来撤销指定 commit(安全)git revert a1b2c3d
git reflog查看 HEAD 的移动历史(后悔药)git reflog

⚠️ git reset --hard永久丢弃未提交的修改,谨慎使用!如果误操作了,git reflog 是你的后悔药 —— 它记录了 HEAD 的每一次移动,可以找回被 reset 掉的 commit。


📘 关于本速查表:以上命令覆盖了 Git 日常使用 90% 的场景。接下来的章节会深入讲解 Detached HEAD、Worktree、Stash、Rebase、Cherry-pick 等进阶操作的原理与 AI 协作范式。


0. 先理解 Git 的真正面目:内容寻址文件系统

🤖 AI 提示词要点:当你告诉 AI「帮我找回某个版本的文件」或「查找这个 blob 在哪些 commit 中出现过」,背后依赖的都是这套对象模型。

在深入操作之前,先把 Git 的底层世界观掰清楚。Git 本质上不是一个「版本管理工具」,而是一个 内容寻址文件系统(Content-Addressable Filesystem),版本管理只是构建在它之上的上层应用。

Git 内部只有 4 种对象,全部以 SHA-1 哈希命名,存储在 .git/objects/ 中:

对象类型核心职责类比
blob存储文件内容(不含文件名)一页手稿
tree存储目录结构,指向 blob 和子树文件夹
commit指向一棵 tree,记录作者、时间、父 commit一张快照照片
tag给某个 commit 打上可读标签便签条

一张图讲清楚它们的关系:

commit (SHA: a1b2c3...)
  ├── tree (根目录)
  │     ├── blob "README.md"
  │     ├── blob "main.py"
  │     └── tree "src/"
  │           └── blob "utils.py"
  ├── parent: commit (SHA: d4e5f6...)
  ├── author: "张三 <zhang@example.com>"
  └── message: "feat: add utils module"

几个关键推论:

  • 相同内容 = 相同哈希。两个文件内容一样,Git 只存一份 blob。这天然实现了去重。
  • commit 不存 diff,存完整快照。每个 commit 都指向一棵完整的 tree。Git 之所以省空间,靠的是对象压缩(packfile),不是存差异。
  • parent 指针形成 DAG(有向无环图)。你的提交历史本质上就是一条或分叉的哈希链。

📘 原理笔记:用 git cat-file -p <hash> 可以窥探任意对象的内部结构。这是理解 Git 最直接的实验手段 —— 随便拿个 commit hash,一层层往下追踪。


1. 把仓库回退到历史 —— 分离头指针(Detached HEAD)

有时需要回到某个历史提交看一眼代码 —— 不是回退,只是「穿越」。VS Code 给了两条路:

方案 A:分离头指针(不推荐)

右键某个 commit 记录,选择「分离头指针(Detached HEAD)」。

此时 HEAD 直接指向该 commit,而非指向分支名。在这种状态下:

  • 如果你 不做修改,随便切走就行,毫发无损。
  • 如果你做了新 commit,它们会挂在匿名指针上 —— 一旦切走就找不到了(虽然可以用 git reflog 救援,但没必要给自己添麻烦)。

⚠️ 不推荐在 detached HEAD 状态下直接改代码,容易搞丢。

方案 B:基于历史提交新建分支(推荐 ✅)

右键目标 commit → 创建分支。

它会从那个历史点分出一条新分支。此时 HEAD → 分支名 → commit,安全可靠。你可以随意在上面实验、提交,完成后合并回去或直接删掉。

🤖 AI 提示词范例:「基于 commit abc123 创建一个叫 hotfix-old-bug 的分支,我需要在那个历史节点修一个老问题。」


2. Worktree:同时活在多个分支里

传统痛点

正在 feature-a 上开发到一半,突然需要切到 main 修个紧急 bug。但工作区没清理干净(编译产物、中间文件),直接 git checkout main 会报错或带来混乱。

Worktree 解决一切

git worktree 允许你在同一仓库的 不同目录 中同时 checkout 多个分支。每个 worktree 有自己的工作区 + 暂存区 + HEAD,但共享同一个 .git/objects 数据库。

# 从当前仓库的 main 分支创建一个新 worktree
git worktree add ../hermes-hotfix main

# 列出所有 worktree
git worktree list

# 用完后删除(但分支还在)
git worktree remove ../hermes-hotfix

AI 工具的原生支持

部分 AI 编码工具已将 worktree 提升为一等公民:

  • Claude Code 支持 claude --worktree add-xxxx,一步创建独立 worktree 并在其中启动 AI 开发会话。
  • Codex 同样原生支持 worktree 隔离。

AI 会在独立的 worktree 里完成任务,完成后合并回主干并清理:

claude --worktree add-fix-bug-42   # AI 在隔离空间工作
# ... AI 完成修改并提交 ...
git checkout main && git merge add-fix-bug-42
git worktree remove ../add-fix-bug-42

🤖 AI 提示词范例:「用 worktree 隔离一个环境,在 fix-login-timeout 分支上修复超时问题,完成后再合并回 main 并删除 worktree。」


3. 修改同一个文件产生冲突 —— AI 来裁判

当两个人(或两个分支)修改了同一个文件的同一处代码,Git 无法自动选择,就会标记为冲突:

<<<<<<< HEAD
const TIMEOUT = 3000;           // 你的版本
=======
const TIMEOUT = 5000;           // 对方的版本
>>>>>>> feature/new-api

传统做法

手动判断保留哪一侧,或两者都保留后重新编排逻辑。VS Code 会在冲突处提供内联按钮:Accept Current / Accept Incoming / Accept Both。

AI 时代的做法

直接把冲突文件和上下文丢给 AI,让它判断:

🤖 AI 提示词范例:「这段代码发生了合并冲突,HEAD 把超时改成了 3000ms,incoming 分支改成了 5000ms 并且增加了重试逻辑。分析一下应该怎么合并,然后帮我解决冲突。」

AI 能做的事情远超「选左边还是右边」:

  • 理解双方的修改意图
  • 提出第三种整合方案
  • 检查合并后是否有逻辑矛盾

避免冲突的最佳实践

策略说明
小步提交commit 粒度越细,冲突概率越低
频繁 rebase在开发分支上 git rebase main,把冲突消解在前
模块化设计不同功能修改不同文件,天然避免碰撞
沟通知道队友在改什么,主动避让

4. Git 分区概念:三棵树模型

Git 的核心工作流可以抽象为 三棵树(或叫三个区域):

区域在哪里作用
工作区(Workspace)你硬盘上的文件修改、新增、删除 —— 干活的地方
暂存区(Staging / Index).git/index你决定哪些修改要纳入下一次 commit
本地仓库(Repository).git/objects/commit 后的历史存档

工作区 → (git add)→ 暂存区 → (git commit)→ 本地仓库

为什么现代工具淡化了暂存区

VS Code 默认行为是「提交全部更改」—— 相当于自动 git add -A && git commit,跳过了显式的暂存步骤。对 90% 的日常场景这完全够用,但有两类场景仍需要精确控制暂存区:

  1. 拆碎一次修改为多个逻辑 commit:比如改了 5 个文件,其中 3 个是功能实现、2 个是无关的代码格式化。用 git add -p(交互式补丁选择)就能把一次修改拆成两次语义清晰的 commit。
  2. 只提交文件的一部分:修改了一个大文件的多处,但只想先提交其中一处改动。

🤖 AI 提示词范例:「帮我把我当前未暂存的修改拆分:和功能相关的变更放到一个 commit,纯格式化的变更放到另一个 commit。」

冷知识 💡

在 GitHub 仓库页面按 ? 可以查看全部快捷键 —— 不少资深开发者都不知道这个。


5. 贡献:Fork → PR 的完整流程

GitHub 的开放性建立在 Fork + Pull Request 的工作流上。标准流程如下:

① Fork 原仓库到自己的账号下
       ↓
② git clone <你的 fork>
       ↓
③ git checkout -b feature/xxx    # 建立特性分支
       ↓
④ 修改代码 → commit → git push origin feature/xxx
       ↓
⑤ 在 GitHub 上发起 Pull Request(提出合并请求)
       ↓
⑥ 原仓库维护者 Review → 讨论 → 修改
       ↓
⑦ 维护者接受合并(Merge)

你有两个选择

方式 1:Fork 工作流(外部贡献者)

标准流程,适合没有原仓库写权限的贡献者。

方式 2:协作成员直推(内部团队 ✅)

如果你被邀请为原仓库的 Collaborator,就跳过了 Fork 这一步。可以直接在原仓库上建分支、推送,然后发起 PR。核心流程不变,但更轻量:

git checkout -b feature/my-work
# ... 写代码,提交 ...
git push origin feature/my-work
# → 在 GitHub 上发起 PR,等待 Review

🤖 AI 提示词范例:「我在协作仓库中,帮我从 main 创建一个 feature/refactor-auth 分支,把认证模块重构后提交,然后给我生成一段好的 PR 描述。」

PR 发生冲突怎么办

冲突不可怕,但需要正确处理:

# 1. 切换到你的 PR 分支
git checkout feature/my-work

# 2. 拉取最新的 main 并合并进来
git fetch origin
git merge origin/main

# 3. 手动解决冲突,mark as resolved
# 4. 提交并推送
git push origin feature/my-work

GitHub 会在 PR 页面自动更新状态,冲突标记消失后即可合并。

🤖 AI 提示词范例:「我的 PR 分支 feature/xxx 和 main 产生了冲突。帮我执行 git merge origin/main,把冲突文件列出来,然后逐个解决。」


6. Cherry-pick:精准摘樱桃 🍒

是什么

一个分支上有多个 commit,你只想把其中一两个「摘」到另一个分支上,而不是合并整个分支。

main:    A --- B --- C --- D
                       ↑ (你想把 C 摘过来)
fix:     A --- B --- C'

怎么用

# 在目标分支上执行
git cherry-pick <commit-hash>

# 一次摘多个
git cherry-pick abc123 def456

# 摘一个连续区间(abc 不包含,def 包含)
git cherry-pick abc123..def456

Cherry-pick 会在目标分支上 创建全新的 commit(哈希不同),即使改动内容完全一样。Git 拿原 commit 的 diff,应用到目标分支的当前状态上。

典型场景

场景示例
热修复回迁在 release 分支上修了个紧急 bug,需要把它单独摘回 main
跨分支复用feature-a 写了一个通用工具函数,想单独搬到 feature-b
错分支修正不小心在 main 上提交了,用 cherry-pick 搬到正确分支后,在原分支 git reset 撤销

🤖 AI 提示词范例:「把 commit f3a2b1(修复了空指针异常的那个)cherry-pick 到 release/v2.1 分支上。如果出现冲突,帮我分析为什么并解决。」

注意事项

  • Cherry-pick 会产生冲突,解决方式与 merge 一样。
  • 如果原始 commit 依赖了它之前的 commit,单独摘下来可能缺少上下文,需要手动补齐。
  • 不要对已经推送到公共仓库的 commit 做 cherry-pick 后再 rebase,会让协作混乱。

7. Stash:代码暂存,随时归位

是什么

写到一半被叫走处理紧急任务?在 A 分支修改了很多文件但不想提交?由 stash 出场:

# 保存当前所有未提交修改(包括已暂存和未暂存)
git stash push -m "WIP: 正在重构认证模块"

# 保存时包含未跟踪的新文件
git stash push -u -m "WIP: 含新增文件"

# 查看 stash 列表
git stash list
# 输出:stash@{0}: On main: WIP: 正在重构认证模块

# 取回最近一次 stash 的内容(保留 stash 记录)
git stash apply

# 取回并删除 stash 记录
git stash pop

# 取回指定的 stash
git stash apply stash@{2}

# 删除某个 stash
git stash drop stash@{0}

典型场景

🔄 场景流程示意:

正在 feature-a 上写代码(工作区一堆未保存修改)
    ↓ 老板/同事突然需要你切到 main 修 bug
git stash push -m "WIP: feature-a half done"
    ↓ 工作区瞬间干净
git checkout main → 修 bug → commit → push
    ↓ 回到原来的战场
git checkout feature-a
git stash pop
    ↓ 修改全部回来了,继续写

Stash 的本质

Stash 内部也是 commit —— Git 会创建两个临时 commit(一个存暂存区内容,一个存工作区内容),存储在一个特殊的 ref refs/stash 下。所以 stash 本质上是一个 没有关联任何分支的、特殊的 merge commit

🤖 AI 提示词范例:「我需要在 main 分支上临时修个 bug,帮我把当前 feature/new-ui 上的所有未提交改动 stash 起来,切到 main,修完后切回来再 pop。」


8. Rebase:重写历史,保持线性

是什么

Rebase 是 Git 中最强大也最容易误用的操作之一。它的本质是:把当前分支的提交,逐个「搬家」到目标分支的最新提交之后

Git Merge(产生分叉):

main:    A --- B --- C
              \       \
feature:       D --- E --- M (merge commit)

Git Rebase(线性历史):

main:    A --- B --- C
                       \
feature:                 D' --- E'

Rebase 之后,D' 和 E' 是全新的 commit(哈希不同),但包含相同的改动。

基础用法

# 在 feature 分支上,把当前分支 rebase 到 main
git checkout feature
git rebase main

# 等价于一个指令
git rebase main feature

交互式 Rebase(Interactive Rebase)⭐

这是 Git 最强大的历史整理工具:

# 整理最近 3 次提交
git rebase -i HEAD~3

打开编辑器后会看到:

pick a1b2c3d feat: 添加登录功能
pick e4f5g6h fix: 修复登录按钮样式
pick i7j8k9l chore: 移除调试日志

可用的操作命令:

命令作用使用时机
pick保留该 commit默认操作
reword保留但修改 commit message上一个人写的信息含糊不清
squash合并到上一个 commit,合并 messages多次提交其实是一个功能的迭代
fixup合并到上一个 commit,丢弃 message同 squash,但不需要保留那坨提交信息
drop删除该 commit我不小心提交了 API key 😱
edit暂停,让你修改这次提交的内容漏了一个文件没加

⚠️ 黄金法则

永远不要 rebase 已经推送到公共仓库的 commit。

Rebase 会重写哈希。如果你 rebase 了别人已经 pull 下来的分支,协作者的本地历史会和你产生分歧,强制推送(force push)会让其他人的工作陷入混乱。

可以 rebase不可以 rebase
本地的、未推送的分支 ✅已经 push 到共享仓库的分支 ❌
自己的 feature 分支(推送前整理)✅main / master / develop 等公共分支 ❌
PR 分支在 Review 过程中(团队协商后)⚠️已经被别人基于它开了新分支的分支 ❌

Rebase vs Merge:什么时候用什么?

维度MergeRebase
历史记录保留真实的分叉与合并轨迹线性、整洁
冲突解决一次性解决所有冲突可能每个 commit 都遇到冲突
安全性不改变历史,安全改变历史,需要 force push
适用场景公共分支合并、发布记录整理个人分支、保持主干线性

🤖 AI 提示词范例:「帮我把 feature/my-work 分支 rebase 到最新的 main 上。如果有冲突,在每次冲突时暂停让我确认。完成后,用 git rebase -i 把最后 4 个 commit squash 成 2 个语义清晰的 commit。」


9. 进阶融合:AI 时代的 Git 工作范式

9.1 AI 提示词怎么写才算好

把前面学到的原理套进去,你的 prompt 就会从「帮我用 git」变成「帮我做这件事」:

❌ 模糊 prompt:
"帮我把代码合并一下"

✅ 精准 prompt:
"我在 feature/payment 分支上,想用 rebase 的方式合并最新的 main,
过程中如果有冲突先让我手动确认。完成后帮我 squash 最近 5 个 commit
为 2 个:一个关于 API 对接,一个关于 UI 调整。"

区别在于:精确的 prompt 里包含了 操作对象、操作方法、冲突策略、整理策略。你不需要背命令,但需要知道这些概念叫什么名字、在什么场景下用。

9.2 一张速查表

我要做什么操作AI 关键词
回到历史看看代码checkout 到历史 hash / 分离头指针detached HEAD, checkout
基于老版本开新分支从 old commit 创建分支create branch from commit
同时干两个分支的活worktreeworktree add, 多工作树
保存现场,先去干别的stashstash push, stash pop
两个分支合并但有冲突merge + 解决冲突merge conflict, accept incoming
只想把某一个 commit 搬过来cherry-pickcherry-pick, 摘取提交
整理自己的提交历史interactive rebaserebase -i, squash, fixup
让自己的分支跟上 mainrebaserebase onto main
贡献给别人的仓库Fork → PRfork, pull request, PR
找人 Review 代码推送 + 发起 PRcreate PR, request review

📘 结尾的话:Git 真正的学习曲线不在命令,而在心智模型。一旦你内化了「内容寻址」「DAG」「三棵树」这几个概念,剩下的所有操作 —— 无论是 stash、rebase 还是 cherry-pick —— 都不过是这些基础模型的排列组合。AI 是你的操作员,你来做架构师。

Git 从入门到协作:原理、命令与安全工作流 — Aohs