📖 导读:这篇文章面向第一次接触 Git 的新手小白。我会从"版本控制到底是什么"讲起,把每个命令的作用、参数和实际使用场景都讲清楚。对出现的专业名词用 💡 注 的形式补充通俗解释,命令都可以直接照抄使用。文末附一张速查表和几个实战场景——其中就包括用 Git 发布本博客的完整流程

Git 是目前世界上最流行的分布式版本控制系统,由 Linux 之父 Linus Torvalds 在 2005 年创建。无论你是写代码、写博客(比如这个 Hugo 博客就是用 Git 管理并发布到 Cloudflare Pages 的),还是协作写任何文本文件,Git 都能帮你记录每一次修改、随时回到历史版本、和他人协同而不互相覆盖。

💡 注(版本控制系统,Version Control System):你可以把它理解成一个"无限次后悔药 + 时光机"。普通方式改文件,改错了就回不去了;用版本控制,每一次改动都会被存成一个"快照",你随时能回到任何一个历史时刻,也能对比两个时刻之间的差异。

💡 注(分布式 distributed):早期的版本控制系统是"集中式"的——有一台中央服务器存着所有历史,大家改完都传给它。分布式则是每台电脑上都存着完整的版本历史,不依赖中央服务器也能工作,更安全也更灵活。Git 就是分布式的代表。


1. 什么是 Git?为什么需要它?

在没有 Git 之前,人们管理文件版本常常是这样的:

论文.doc
论文-改.doc
论文-最终版.doc
论文-最终版2.doc
论文-真的最终版.doc
论文-打死不改版.doc

这种方式的问题显而易见:文件越来越多、不知道哪个是最新、不知道改了什么、和别人合并修改时一团糟。

Git 解决的正是这些问题。它给你带来的能力是:

  • 记录历史:每一次提交(commit)都是一个存档点,能随时回到任意存档点。
  • 对比差异:能查看任意两个版本之间改了哪些行。
  • 分支并行:可以开一条"分支"去做实验性修改,不影响主干;实验成功再合并回来。
  • 协作协同:多人同时开发,各自在本地改,最后通过远程仓库同步合并。
  • 备份容灾:代码推送到 GitHub 等远程仓库后,本地丢了也能找回。

💡 注(提交 commit):commit 是 Git 里最核心的动作,意思是"把当前的一组改动正式记录成一个历史版本"。每个 commit 有一个唯一的 ID(一长串哈希字符),记录了谁、什么时候、改了什么、以及一句说明信息。

集中式 vs 分布式

类型 代表 历史存放 离线工作 服务器挂了
集中式 SVN、CVS 只在中央服务器 不行 全员瘫痪
分布式 Git 每台电脑都有完整历史 可以 只影响协作同步,本地照常用

2. 安装与初次配置

2.1 安装 Git

Windows:去官网下载安装包:https://git-scm.com/download/win,下载后一路"Next"默认安装即可。安装完成后会自带一个 Git Bash 终端(推荐在 Git Bash 里用 Git,体验最一致)。也可以直接用 PowerShell。

💡 注(GFW 访问提示):git-scm.com 官网在国内访问偶尔较慢,但通常能下到。如果实在打不开,可以用国内镜像站(如清华 TUNA 镜像、阿里云镜像)搜索 Git for Windows 安装包。

macOS:在终端输入 git --version,系统会自动提示安装 Xcode Command Line Tools,按提示装好即可。或用 Homebrew:brew install git

Linux (Debian/Ubuntu)

sudo apt update
sudo apt install git

安装完成后,验证:

git --version

能打印出版本号(如 git version 2.47.x)就说明安装成功。

2.2 初次配置(必须做一次)

Git 每次提交都会记录"是谁提交的",所以第一次使用前要先告诉 Git 你的名字和邮箱。这台电脑只需配置一次

git config --global user.name "EricZeng599"
git config --global user.email "EricZeng599@outlook.com"

💡 注(–global 参数)--global 表示"对当前用户的这台电脑上所有仓库生效",配置会写到 ~/.gitconfig 文件里。如果不加 --global(即 git config user.name "..."),则只对当前这一个仓库生效,会写到仓库里的 .git/config

验证配置:

git config --list

其他几个实用配置(可选):

# 设置默认分支名为 main(新版规范,旧版默认是 master)
git config --global init.defaultBranch main

# 让 git 输出带颜色,更易读
git config --global color.ui auto

# 设置默认文本编辑器(写提交说明时用),可选 nano / vim / "code --wait"
git config --global core.editor "code --wait"

💡 注(main vs master):旧版 Git 创建仓库时默认分支叫 master,2020 年后社区为了使用更中性的词,默认改成了 main。GitHub 现在默认也是 main。两者技术上一模一样,只是名字不同。本博客用的就是 main 分支。


3. 核心概念:三个区域(最重要的心智模型)

学 Git 最关键的就是搞懂"三个区域"。一旦理解了它,绝大多数命令都有迹可循。

┌──────────────┐   git add    ┌──────────────┐  git commit  ┌──────────────┐
│   工作区     │ ──────────▶  │   暂存区     │ ──────────▶  │   版本库     │
│ Working Dir  │              │ Staging Area │              │  Repository  │
└──────────────┘              └──────────────┘              └──────────────┘
   你正在编辑的                 下次要打包提交                已正式记录的
   文件(硬盘上)               的改动(草稿箱)             历史(存档点)
  • 工作区(Working Directory):你能在文件夹里直接看到、用编辑器直接改的文件。就是"正在干活的地方"。
  • 暂存区(Staging Area / Index):你用 git add 把工作区的改动"放进购物车"的地方。它像一个草稿箱,让你可以挑选"哪些改动要一起打包成一个提交"。
  • 版本库(Repository):你用 git commit 把暂存区的改动正式记录成历史存档的地方。存在隐藏的 .git 文件夹里。

💡 注(.git 文件夹):在一个用 Git 管理的文件夹里,会有一个隐藏的 .git 子文件夹,Git 把所有的版本历史、配置、分支信息都存在这里。千万别手动改或删这个文件夹,删了就等于把整个项目历史删了。

一个完整改动流程就是这三步:

  1. 在工作区改文件。
  2. git add 把改动放到暂存区(装进购物车)。
  3. git commit 把暂存区的改动存成版本库里的一个提交(结账存档)。

💡 注(为什么要有暂存区):有时候你一次改了好几个文件,但希望"文件 A 和 B 的改动算一个提交,文件 C 的改动算另一个提交"。暂存区就是让你有选择地分批提交,而不是一股脑全打包。这是 Git 比 SVN 优雅的地方之一。


4. 基础命令:从零记录一次修改

4.1 创建仓库:git init

把一个普通文件夹变成 Git 仓库:

cd my-project        # 先进入你的项目文件夹
git init             # 初始化,会生成 .git 隐藏文件夹

执行后会提示 Initialized empty Git repository in ...。从此这个文件夹就被 Git 管理了。

💡 注(仓库 repository):被 Git 管理的文件夹就叫"仓库"或"repo"。一个仓库 = 一个项目目录 + 它的 .git 历史目录。

4.2 查看状态:git status(最常用,随时敲)

git status

这是你用得最多的命令,随时敲它看看当前是什么情况:哪些文件改了、哪些进了暂存区、哪些还没被 Git 跟踪。它的输出会用颜色和文字明确告诉你下一步该做什么。

On branch main
No commits yet

Changes to be committed:        # 已在暂存区,等待 commit
  (use "git rm --cached <file>..." to unstage)
        new file:   README.md

Changes not staged for commit:  # 改了但还没 add
  (use "git add <file>..." to update what will be committed)
        modified:   index.html

Untracked files:                # Git 完全不认识的新文件
  (use "git add <file>..." to include in what will be committed)
        notes.txt

4.3 添加到暂存区:git add

git add README.md          # 只添加一个文件
git add index.html notes.txt   # 添加多个文件
git add .                  # 添加当前目录下所有改动(最常用)
git add *.md               # 按通配符添加所有 .md 文件
git add -p                 # 交互式逐块挑选(高级,见下注)

💡 注(git add . 的坑)git add . 会把当前目录下所有改动(新增、修改、删除)都加进暂存区,很方便但也可能误加。如果想精细控制,用 git add 文件名 一个个加,或用 git add -p 逐块挑选。

💡 注(git add -p 交互式暂存):一个文件里可能改了好几处,-p(patch 模式)会一处一处地问你要不要加进暂存区,适合"一个文件里的改动想拆成两个提交"的场景。新手先了解即可。

4.4 提交:git commit

git commit -m "本次提交的说明"

-m 后面跟一句提交说明(message)。如果不加 -m,Git 会打开编辑器让你写长一点的说明。

# 常见好习惯:一行简短说明
git commit -m "修复登录页面按钮错位 bug"

# 更规范:标题 + 空行 + 详细正文(用多个 -m)
git commit -m "修复登录页面按钮错位 bug" -m "原因是 CSS 的 flex 容器没设置 align-items,在 Safari 下会错位。已修复并补充测试。"

💡 注(提交说明怎么写):好的提交说明能让以后回溯历史时一眼看懂"这次改了啥"。推荐用祈使句,如"修复 XX"“添加 XX"“重构 XX”,而不是"改了点东西”。本博客的提交就是 git commit -m "发布新文章:Git 使用命令完全指南" 这种风格。

一步到位的快捷方式:把已跟踪文件的修改直接提交(跳过 add,但只对已跟踪文件有效,新文件还是要先 add):

git commit -am "说明"     # 等于 git add 已跟踪文件 + git commit

4.5 查看提交历史:git log

git log                 # 完整历史
git log --oneline       # 每个提交一行(最常用,简洁)
git log --oneline -5    # 只看最近 5 条
git log --graph --oneline --all   # 带分支图,看分支合并关系
git log --stat          # 额外显示每次提交改了哪些文件、增删几行
git log -p              # 额外显示每次提交的具体代码差异

--oneline 的输出大概长这样:

a1b2c3d (HEAD -> main, origin/main) 发布新文章:Git 使用命令完全指南
d4e5f6g 添加 SSH 完全指南
7h8i9j0 init hugo blog: PaperMod + 2 posts

💡 注(HEAD)HEAD 是一个特殊指针,指向"你当前所在的位置"(当前分支的最新提交)。可以理解成"光标"。HEAD -> main 表示你现在在 main 分支上、停在 main 的最新提交。

💡 注(commit ID):每个提交都有一个唯一 ID,如 a1b2c3d...(完整是 40 位哈希)。--oneline 里显示的是前 7 位缩写,日常足够用。

4.6 一个完整的最小流程

mkdir my-project && cd my-project    # 建文件夹并进入
git init                             # 初始化仓库
echo "# 我的项目" > README.md         # 创建一个文件
git status                           # 查看:README.md 是 Untracked
git add README.md                    # 加入暂存区
git status                           # 查看:已暂存,等待提交
git commit -m "初次提交:添加 README" # 正式提交
git log --oneline                    # 查看历史

5. 查看差异与历史详情

5.1 查看差异:git diff

git diff                 # 工作区 vs 暂存区:看还没 add 的改动
git diff --staged        # 暂存区 vs 版本库:看已 add 待 commit 的改动(也叫 --cached)
git diff HEAD            # 工作区 vs 版本库:看所有未提交的改动
git diff main feature    # 两个分支之间的差异
git diff a1b2c3d d4e5f6g # 两个提交之间的差异
git diff --stat          # 只看改了哪些文件、增删几行,不看具体内容

💡 注(diff 输出怎么读):diff 输出里,以 + 开头的绿行是新增的,以 - 开头的红行是删除的,@@ 行标注的是改动所在的行号位置。

5.2 查看某次提交的详情:git show

git show                # 查看最新一次提交的详情(改了什么)
git show a1b2c3d        # 查看指定提交的详情
git show --stat a1b2c3d # 只看该提交改了哪些文件

5.3 搜索历史:git log 进阶

git log --author="EricZeng"          # 只看某人提交的
git log --grep="修复"                 # 按提交说明关键词搜
git log --since="2 weeks ago"        # 最近两周的
git log -- path/to/file             # 只看改动过某文件的历史
git log -S "某个函数名"               # 搜索"某段代码被增加或删除"的提交

6. 撤销操作(后悔药)

这是新手最容易迷糊的部分。记住一个原则:改动越靠后(越接近版本库),撤销越要小心

6.1 撤销工作区的修改:git restore / git checkout --

git restore index.html          # 丢弃工作区里 index.html 的未暂存改动(新版推荐)
git checkout -- index.html      # 同样效果(旧版写法)
git restore .                   # 丢弃所有工作区未暂存改动(小心!)

💡 :这个命令会把文件恢复成暂存区或版本库里的样子,工作区里没提交的改动会永久丢失,不可恢复。用之前确认好。

6.2 把暂存区的改动退回工作区:git restore --staged

git restore --staged index.html   # 把 index.html 从暂存区撤回工作区(旧版:git reset HEAD index.html)
git restore --staged .            # 撤回所有暂存的改动

改动并不会丢,只是从"已暂存"变回"未暂存",还能继续改或重新 add。

6.3 修改最近一次提交:git commit --amend

# 刚 commit 完发现说明写错了,或漏了文件,不想新增一个提交:
git add 漏掉的文件.txt
git commit --amend -m "新的提交说明"   # 用新提交替换最近一次提交

💡 注(–amend 的风险)--amend 会改写历史。如果这个提交已经 push 到远程了,就别再 amend,否则会和远程冲突,需要强制推送,协作时很危险。只对"还没推送的本地提交"用 amend。

6.4 移动分支指针:git reset(谨慎)

git reset 可以把当前分支的指针往回挪到某个历史提交,有三种模式:

git reset --soft  a1b2c3d   # 指针回退,改动留在暂存区(可重新 commit)
git reset --mixed a1b2c3d   # 指针回退,改动退回工作区(默认模式,可省略 --mixed)
git reset --hard  a1b2c3d   # 指针回退,改动【全部丢弃】(危险!不可逆)
模式 版本库指针 暂存区 工作区
--soft 回退 保留 保留
--mixed(默认) 回退 清空(改动回工作区) 保留
--hard 回退 清空 清空

💡 注(–hard 是核武器)git reset --hard 会把工作区和暂存区的改动全部永久删除。用之前务必三思。但它不会删除"已经 commit 过"的历史——只要提交过,哪怕被 reset 掉了,也能通过 git reflog 找回(见 6.6)。

6.5 安全地"反向提交":git revert(推荐用于已推送的提交)

git revert a1b2c3d   # 生成一个新提交,内容是"撤销 a1b2c3d 的改动"

reset 不同,revert 不会改写历史,而是新增一个"反向操作"的提交。协作中、已推送的提交,用 revert 而不是 reset,更安全。

💡 注(reset vs revert 一句话)reset 是"穿越回去把历史抹掉重来"(改写历史,危险);revert 是"在现在这个时间点新增一个撤销操作"(保留历史,安全)。已推送的用 revert,没推送的用 reset。

6.6 救命稻草:git reflog

git reflog    # 记录所有 HEAD 的移动,包括被 reset 掉的提交

只要你 commit 过,哪怕后来 reset --hard 把它丢了,git reflog 里还能找到那个提交的 ID,再用 git reset --hard 那个ID 就能救回来。这是 Git 的"终极后悔药"。


7. 分支:并行开发的利器

分支是 Git 最强大的功能之一。它让你可以"不影响主干地去做实验性修改"。

💡 注(分支 branch):分支可以理解成"平行宇宙"。你在 main 分支上稳定开发,同时又开一条 feature-A 分支去做新功能实验,两条线互不影响。等 feature-A 做好了,再把它合并回 main。

7.1 查看分支:git branch

git branch              # 查看本地所有分支(* 标记当前所在分支)
git branch -a           # 查看所有分支(含远程)
git branch -v           # 额外显示每个分支最新提交

7.2 创建 / 切换分支

git branch feature-A            # 创建分支 feature-A(但不切换过去)
git switch feature-A            # 切换到 feature-A(新版推荐)
git checkout feature-A          # 切换分支(旧版写法,同样有效)
git switch -c feature-A         # 创建并切换到 feature-A(一步到位,新版)
git checkout -b feature-A       # 创建并切换(旧版写法)

💡 注(switch vs checkout)git checkout 是老命令,既能切分支又能恢复文件,容易混淆。Git 2.23 起新增了语义更清晰的 git switch(专管切换/创建分支)和 git restore(专管恢复文件)。新项目推荐用 switch / restore,但 checkout 仍然完全有效,老教程里全是它。

7.3 合并分支:git merge

git switch main          # 先切回要合并到的目标分支(通常是 main)
git merge feature-A      # 把 feature-A 合并进当前分支
git branch -d feature-A  # 合并完,删掉不再需要的分支(-d 是安全删除)

7.4 变基:git rebase(进阶)

git switch feature-A
git rebase main          # 把 feature-A 的提交"嫁接"到 main 最新提交之后

rebasemerge 都能合并分支,但方式不同:

  • merge:保留两条分支的真实历史,生成一个"合并提交",历史是网状的。
  • rebase:把当前分支的提交一个个"重放"到目标分支顶端,历史变成一条直线,更干净,但改写了提交历史

💡 注(黄金法则)永远不要 rebase 已经推送到公共分支的提交,否则会让协作者的历史混乱。rebase 只用于本地的、没推送过的提交整理。

7.5 解决合并冲突

当两条分支改了同一个文件的同一处,Git 无法自动合并,就会报"冲突(conflict)"。这时你需要手动解决:

git merge feature-A
# Auto-merging index.html
# CONFLICT (content): Merge conflict in index.html
# Automatic merge failed; fix conflicts and then commit the result.

打开冲突文件,会看到:

<<<<<<< HEAD
当前分支(main)的内容
=======
要合并进来分支(feature-A)的内容
>>>>>>> feature-A

你需要:编辑这个文件,决定保留哪部分(或合并两部分),删掉 <<<<<<<=======>>>>>>> 这些标记,保存。然后:

git add index.html       # 标记冲突已解决
git commit               # 完成合并提交

💡 注(冲突不可怕):冲突不是错误,是 Git 在说"这两处改动我拿不准,请你来决定"。解决冲突 = 手动编辑保留想要的内容 + 删标记 + add + commit,就这几步。也可以用编辑器或工具(VS Code 有可视化冲突解决)辅助。


8. 远程仓库:和 GitHub 同步

到目前为止都在本地操作。要和别人协作、或做云端备份,就需要远程仓库

💡 注(远程仓库 remote):远程仓库就是存放在服务器(如 GitHub、Gitee、GitLab)上的仓库副本。它的作用是"中转站 + 备份":你把本地改动 push 上去,别人从那里 pull 下来。本博客的远程仓库就在 GitHub。

8.1 查看远程:git remote

git remote -v            # 查看已配置的远程仓库地址
git remote add origin https://github.com/EricZeng599/my-blog.git   # 添加远程并起名 origin
git remote remove origin # 删除远程

💡 注(origin)origin 是远程仓库的默认别名,不是关键字。你可以起别的名字,但大家约定俗成用 origin 指代"主远程仓库"。

8.2 克隆仓库:git clone

把远程仓库整个下载到本地(含全部历史):

git clone https://github.com/EricZeng599/my-blog.git
git clone https://github.com/EricZeng599/my-blog.git my-folder   # 克隆到指定文件夹名

💡 注(HTTPS vs SSH 克隆地址):GitHub 仓库有两种克隆地址。HTTPS(https://github.com/...)每次推送要输用户名和令牌;SSH(git@github.com:...)配置好密钥后免密推送,更方便。新手先用 HTTPS,熟悉后可切 SSH(参考本博客的 SSH 指南配置密钥)。

8.3 推送:git push

把本地提交上传到远程:

git push origin main              # 把本地 main 推到远程 origin 的 main
git push -u origin main           # 首次推送:-u 设置"上游关联",之后只敲 git push 即可
git push                          # 已关联上游后,直接推送当前分支
git push origin feature-A         # 推送其他分支

💡 注(-u 是什么)-u--set-upstream)建立本地分支和远程分支的"绑定关系"。绑定一次后,以后在这个分支里直接 git push / git pull 不用再写远程名和分支名。首次推送一个分支时建议加 -u

8.4 拉取:git pullgit fetch

git pull             # 拉取远程更新并合并到当前分支(= fetch + merge,最常用)
git fetch            # 只拉取远程更新到本地,但不合并(让你先看看再决定)

两者区别:

  • git fetch:只下载远程的新提交到本地,不动你的工作区。下载后你可以 git log origin/main 看看远程发生了什么,再决定要不要合并。
  • git pull:相当于 git fetch + git merge,直接把远程更新合并进当前分支。

💡 注(什么时候要 pull):如果你在多台电脑上操作同一个仓库(比如公司电脑和家里电脑),或者和别人协作,开始干活前先 git pull 拉一下最新,能避免"本地落后远程导致 push 被拒绝"。本博客如果你在两台电脑上交替写文章,就要记得 push 之前先 pull。

8.5 推送被拒绝怎么办

如果远程有你本地没有的提交(比如别人推了、或你在另一台电脑推了),你的 push 会被拒绝:

! [rejected]    main -> main (fetch first)

解决办法:先 pull 再 push:

git pull          # 拉取并合并远程更新
# 如果有冲突,解决冲突后 git add + git commit
git push          # 再推送

9. 标签:git tag

标签用来给某个提交打"标记",通常用于标记发布版本(如 v1.0.0)。

git tag v1.0.0                  # 给当前提交打轻量标签
git tag -a v1.0.0 -m "正式版 1.0"  # 打带说明的附注标签(推荐)
git tag                         # 列出所有标签
git show v1.0.0                 # 查看标签详情
git tag v1.0.0 a1b2c3d          # 给指定历史提交打标签

git push origin v1.0.0          # 推送单个标签到远程(tag 不会随 push 自动上传)
git push origin --tags          # 推送所有标签
git tag -d v1.0.0               # 删除本地标签
git push origin :refs/tags/v1.0.0  # 删除远程标签

💡 注(轻量标签 vs 附注标签):轻量标签只是一个指向提交的"书签";附注标签(-a)是 Git 里的一个独立对象,带说明、打标签人、时间等信息,更正式。发布版本建议用附注标签。


10. 忽略文件:.gitignore

有些文件不想让 Git 跟踪(如编译产物、密码文件、系统垃圾文件),用一个 .gitignore 文件列出它们即可。

在仓库根目录创建 .gitignore,内容示例:

# 编译产物
*.exe
*.o
*.class

# 依赖目录
node_modules/
venv/
__pycache__/

# 日志和临时文件
*.log
*.tmp

# 环境变量 / 密钥(千万别提交!)
.env
*.pem
id_rsa

# 系统文件
.DS_Store
Thumbs.db

# 编辑器目录
.vscode/
.idea/

# Hugo 博客的构建输出(本博客就是这么配的)
/public/
/.hugo_build.lock

💡 注(.gitignore 的坑).gitignore 只对还没被 Git 跟踪的文件生效。如果文件已经被 add + commit 过了,再加进 .gitignore 不会让它停止跟踪。要先 git rm --cached 文件名(从版本库移除但保留本地文件)再提交,之后 .gitignore 才生效。

💡 注(千万别提交密钥):API key、密码、私钥(如 id_rsa.env)一旦提交并推送到公开仓库,就等于泄露了。GitHub 甚至有机器人实时扫描公开仓库窃取密钥。敏感信息一律写进 .gitignore


11. 实战场景

场景一:把一个现有项目纳入 Git 管理

cd existing-project
git init
git add .
git commit -m "初次提交:导入现有项目"
# 然后到 GitHub 建一个空仓库,复制它的地址,关联并推送:
git remote add origin https://github.com/你的名/项目名.git
git branch -M main        # 把当前分支改名为 main(如果原来是 master)
git push -u origin main

场景二:发布本博客(真实流程!)

这正是本博客的日常发布流程——写完一篇 Markdown 文章,推送到 GitHub,Cloudflare Pages 自动构建发布:

# 1. 在 content/posts/ 下写好文章,比如 git-commands-guide.md
cd C:\Users\EricZeng\Desktop\blog\my-blog

# 2. 查看改了什么
git status

# 3. 把新文章加入暂存区
git add content/posts/git-commands-guide.md

# 4. 提交
git commit -m "发布新文章:Git 使用命令完全指南"

# 5. 推送到 GitHub(main 分支),Cloudflare 会自动重新构建发布
git push

约一分钟后,blogvoyant.pages.dev 上就能看到新文章了。这就是 Git + Hugo + Cloudflare 的全自动发布链路。

场景三:误删了文件,想找回

git rm 重要文件.txt         # 误删并暂存了
git restore --staged 重要文件.txt   # 先撤出暂存区
git restore 重要文件.txt    # 再从版本库恢复到工作区

# 或者文件是被 reset --hard 干掉的(已提交过):
git reflog                  # 找到删除前的提交 ID
git reset --hard 那个ID     # 回到那个时间点

场景四:撤销已经 push 到远程的提交

# 不要用 reset --hard 然后强推!会搞乱协作者的历史。
# 用 revert 安全地"反向提交":
git revert 有问题的提交ID
git push                    # 推送这个撤销提交

场景五:只想暂存一部分改动,另一部分留到下次

git add -p                  # 交互式逐块选择要暂存的改动
git commit -m "第一批改动"
# 剩下的改动留在工作区,下次再 add + commit

场景六:临时切走去做别的事,手头改动先存起来

git stash                   # 把工作区改动"藏起来",工作区变干净
git switch main             # 切到别的分支干活
# ...干完别的活...
git switch 原分支
git stash pop               # 把刚才藏起来的改动恢复回来

💡 注(git stash):stash 像一个"临时抽屉",把没提交的改动塞进去,工作区就干净了,方便你切换上下文。git stash list 看抽屉里有几份,git stash pop 取出最近一份。


12. 常见坑与最佳实践

  1. 提交粒度要小而完整:一次 commit 只做一件事(修一个 bug、加一个功能),别把十件事揉在一个提交里。说明信息写清楚。
  2. 先 pull 再 push:多人协作或跨设备时,push 前先 git pull,避免冲突和被拒绝。
  3. 别提交敏感信息:密码、密钥、.env 写进 .gitignore。一旦推送到公开仓库,即使后续删除,历史里仍留有记录(需用 git filter-branch 或 BFG 工具清理)。
  4. 别用 push --force 对公共分支git push -f 会强推覆盖远程历史,会把别人的提交冲掉。只对自己的私有分支用,公共分支用 revert
  5. .gitignore 越早建越好:项目一初始化就建好,免得垃圾文件被跟踪后再清理。
  6. commit 前先 git statusgit diff --staged:看一眼要提交什么,避免误提交。
  7. 善用分支:主分支(main)保持稳定可用,新功能在 feature 分支上做,做完合并。
  8. 已推送的提交不要 amend / reset / rebase:会改写公共历史,用 revert 代替。

13. 命令速查表

命令 作用
git init 把当前文件夹初始化为 Git 仓库
git clone <url> 克隆远程仓库到本地
git status 查看工作区 / 暂存区状态
git add <file> / git add . 把改动加入暂存区
git commit -m "说明" 把暂存区改动提交成历史版本
git log --oneline 简洁查看提交历史
git diff 查看未暂存的改动
git diff --staged 查看已暂存待提交的改动
git show <id> 查看某次提交的详情
git restore <file> 丢弃工作区的未暂存改动
git restore --staged <file> 把文件从暂存区撤回工作区
git commit --amend -m "说明" 修改最近一次提交(未推送时用)
git reset --soft <id> 回退指针,改动留暂存区
git reset --mixed <id> 回退指针,改动回工作区(默认)
git reset --hard <id> 回退指针,改动全丢(危险)
git revert <id> 生成反向提交(安全撤销,已推送也能用)
git reflog 查看所有 HEAD 移动记录(救命稻草)
git branch 查看本地分支
git branch <名> 创建分支
git switch <名> / git switch -c <名> 切换 / 创建并切换分支
git merge <分支> 把指定分支合并到当前分支
git branch -d <名> 删除已合并的分支
git remote -v 查看远程仓库
git remote add origin <url> 添加远程仓库
git push -u origin main 首次推送并关联上游
git push 推送当前分支到远程
git pull 拉取并合并远程更新
git fetch 拉取远程更新但不合并
git tag -a v1.0 -m "说明" 打附注标签
git stash / git stash pop 临时藏起 / 恢复改动
git config --global user.name "..." 设置全局用户名
git config --global user.email "..." 设置全局邮箱

14. 学习建议

  • 先用起来再深究:掌握 init / status / add / commit / log / push / pull 这七个性命命令,就能应付 80% 的日常。其余的用到再查。
  • 每个命令加 --help:如 git commit --help 会打开该命令的完整手册。
  • 遇到冲突别慌:就是手动编辑保留想要的内容、删标记、add、commit。
  • 多用 git status:它是你的指南针,随时敲它看下一步该干嘛。
  • 图形化工具辅助:VS Code 自带 Git 支持、GitHub Desktop、Sourcetree、GitKraken 等可视化工具能降低心智负担,但底层还是这些命令,理解命令后用工具更得心应手。

💡 最后一句话:Git 的学习曲线前陡后平。三个区域、提交、分支、远程这几个概念吃透后,剩下的就是查参数。别怕犯错——只要你 commit 过,git reflog 都能救你回来。多在本地试验,很快就能上手。

祝版本控制愉快!🎉