写代码最大的噩梦是什么?不是写不出来,而是写崩了。昨天还能跑的代码,今天一顿乱改,全废了,想回到昨天?没门。Git 就是来解决这个问题的:它是代码的时光机,可以在任意时刻给代码拍一张"存档照",崩了随时读档。
它还是备份——代码不会因为电脑坏了而丢。它更是协作工具——以后多人一起开发一个项目,Git 负责把大家各自的改动合并起来。
还有一个现实原因:招聘时,GitHub 上(一个托管 Git 仓库的网站)的代码记录就是你的求职作品集,面试官会看。所以从现在开始,每写一点代码就提交一次,养成习惯。今天不要求你背 Git 原理,只要求:会存、会取、会看历史,听得懂"冲突"这个词。
Git 和普通备份有什么区别
普通备份 = 把文件复制一份存起来,像照片打印出来收在抽屉里。它的缺点很明显:占地方、分不清哪份最新、改了什么全靠自己回忆。
Git 备份更像拍电影而不是拍照片:它记录的是"每一次改动"和"改动了什么",每个版本都认识自己的爸爸,能随时跳到任意一版。
| 对比 | 手动复制备份 | Git |
|---|---|---|
| 记录了什么 | 某一时刻的全部文件 | 每一次的改动内容 |
| 能回到任意历史版本吗 | 难,分不清版本 | 能,一键跳转 |
| 能知道谁改了什么吗 | 不能 | 能(commit 记录) |
| 多人协作 | 没法合并 | 专门干这个 |
先确认电脑里装好了 Git(周四还会重点讲安装,今天先验证):
git --version
输出(版本号可能不同):
git version 2.43.0.windows.1
能输出版本号,说明 Git 可用。如果提示"不是内部或外部命令"或"command not found",先记住这个现象,周四安装环境时一起解决。
两条约定先立好:Git 命令都以 git 开头,后面跟子命令(git init、git add……),少写 git 前缀就变成普通命令,会报错;Git 只对"被它管理的文件夹"有效,第一次用必须先 git init,不然所有 git 命令都报"不是 git 仓库"。
三个区:工作区、暂存区、仓库
Git 把代码分成三个"区域",新手必懂,因为 git 命令全在三个区之间搬东西:
| 概念 | 怎么理解 | 命令操作 |
|---|---|---|
| 工作区 | 你正在编辑、看到的那堆文件,改动在这里发生 | 正常写代码就行 |
| 暂存区 | "准备保存"的缓冲区,像购物车,先挑好要买的再一起结账 | git add |
| 仓库 | 已经永久存档的版本,像仓库货架,放上去就带时间戳 | git commit |
流程就是:工作区改动 →(git add 放进购物车)→ 暂存区 →(git commit 结账入库)→ 仓库。
为什么中间要隔一个"暂存区"?因为一次改动可能包含多个文件,你想让它们作为一个整体一起存档,购物车就是帮你"挑好了再一起结账"。
用命令感受一下三个区的存在:
git status
第一次运行、还没提交过的话,输出:
On branch main
No commits yet
nothing to commit (create/copy files and use "git add" to track)
翻译成人话:你在 main 分支上,还没有任何存档,工作区目前是干净的。git status 是最常看的命令,每次不确定状态就敲它。
两个容易误会的地方:
git add只是"放进购物车",还没存档,这时后悔还来得及;真正存档是git commit。- 改了文件但没
git add就git commit,Git 会提示"没有要提交的改动",因为购物车是空的。所以看到nothing to commit不代表没干活,而是"购物车空了、或改动没放进去"。
git init:把文件夹变成仓库
git init(init = initialize,初始化)= 把当前文件夹变成"受 Git 管理的仓库"。只需执行一次,以后这个文件夹里的改动都能被 Git 追踪。
cd 项目文件夹 # 先进入你的项目文件夹
git init # 初始化仓库
输出:
Initialized empty Git repository in D:/项目文件夹/.git/
再敲 git status,提示会从"不是 git 仓库"变成正常输出,说明托管生效了。
init 之后,文件夹里会多出一个隐藏的 .git 文件夹——它就是 Git 的"账本",所有版本记录都存在里面。不要去动它、不要删它,删了 Git 历史就全没了。
三个分寸:
- 先
cd进到正确的文件夹再 init,别在 D 盘根目录乱 init,否则 D 盘全被你"托管"了。 .git是隐藏文件夹,ls默认看不到,用ls -a能看到,但只许看不许删。- 一个项目一个仓库:不要在
项目1里面再对项目1/子文件夹init,嵌套仓库会乱套。
git add 和 git status:把改动放进"购物车"
git add 文件名:把指定文件放进暂存区(购物车)git add .:把当前目录所有改动一次性放进暂存区(.表示当前目录,最常用)git status:查看当前状态——谁改了、谁在购物车里、谁还没进
每天的标准动作:改完代码 → git add . → git status 确认 → 准备 commit。看一遍完整的:
# 第一次:新建一个文件
touch 笔记.txt
git status
# 输出要点:
# Untracked files:
# 笔记.txt ← 提示:有个新文件还没被 Git 跟踪
git add 笔记.txt # 或 git add . (把所有改动都放进购物车)
git status
# 输出要点:
# Changes to be committed:
# 新文件: 笔记.txt ← 提示:已经在购物车里了,等着 commit
Untracked(未被跟踪)是新手最常见的词,意思是"这个文件 Git 还不知道它的存在"。git add 之后它就变成"已暂存"(staged)了。
几个坑:
git add .的.别漏,git add(不跟任何东西)是另一种用法,会报错。- 忘记 add 直接 commit,会提示
changes not staged for commit,翻译过来是"有改动还没放进购物车",先git add .再 commit。 - 想看购物车里具体有什么,
git status会明明白白列出来,养成"add 后必看 status"的习惯。
git commit 和 git log:存档、翻历史
git commit -m "说明文字":把暂存区的改动永久保存成一个版本。-m是 message(留言),后面那句说明文字就是"这个版本改了什么"的日记git log:查看所有存档记录(每次 commit 的作者、时间、留言)
写 commit 留言的好习惯:用一句话说清"这次干了啥",比如 第一次提交、修复了路径报错。以后回看历史,靠留言就能找到对应版本。
git add .
git commit -m "第一次提交:新建笔记文件"
输出:
[main (root-commit) 1a2b3c4d] 第一次提交:新建笔记文件
1 file changed, 0 insertions(+)
再改一次文件、再提交一次,然后看历史:
# 修改笔记.txt 后
git add .
git commit -m "第二次提交:补充路径笔记"
git log
输出(节选):
commit 5f6g7h8i (HEAD -> main)
Author: 小明 <xiaoming@example.com>
Date: ...
第二次提交:补充路径笔记
commit 1a2b3c4d
Author: 小明 <xiaoming@example.com>
Date: ...
第一次提交:新建笔记文件
最新的版本在最上面,HEAD 表示"当前所在版本"。
这里有三处容易栽跟头:
-m后面的说明文字必须加引号:git commit -m "第一次"对,git commit -m 第一次可能报错。- 不写
-m会进入一个编辑界面(vim),新手进去出不来很慌——永远记得带 -m。 - 忘记 add 直接 commit 会提示 nothing to commit,先
git add .再 commit,顺序别乱。
分支:另开一条平行线
分支(branch)是 Git 最强大的功能:在主线之外另开一条平行线路,在分支上随便折腾,不影响主线;折腾好了再合并回主线。
打个比方:主线是"正式出版的书",分支是"草稿本"。你在草稿本上随便写、写坏了扔掉,正式出版的版本一点不受影响。团队开发时,每个人在各自的分支上干活,最后合并。
今天只需要会用三个命令:
| 命令 | 作用 |
|---|---|
git branch dev |
新建一个叫 dev 的分支 |
git checkout dev |
切换到 dev 分支(两条分支各自独立) |
git checkout main |
切回主分支(默认主分支叫 main) |
git branch dev # 新建 dev 分支
git branch # 列出所有分支,* 号标在当前所在分支
git checkout dev # 切到 dev 分支
# 输出:Switched to branch 'dev'
git checkout main # 切回主分支
完整感受一下分支的独立性:
git checkout dev
touch dev版本.py # 在 dev 分支上新建文件
git add .
git commit -m "dev 分支上的新文件"
git checkout main # 切回主线
ls # 会发现 dev版本.py 不见了!
git checkout dev # 切回 dev 又出现了
这正是分支的威力:两边互不干扰,各存各的版本。
注意三点:
- 切分支前最好先 commit 或确认改动已处理,未提交的改动会跟着你"串门"到别的分支。
- 新旧版 Git 命令不同:老教材教
git checkout,新 Git 推荐git switch(git switch dev),两者效果一样。今天用 checkout 即可,遇到 switch 别慌。 - 分支名用英文小写、不带空格:
dev、feature-login,别用中文。
回滚:git reset 读档
回滚 = 把代码恢复到之前某个版本。这是 Git 最让人有安全感的功能:写崩了?读档!
最常用的回滚命令:
git reset --hard HEAD~1
拆开看:
reset:重置/回滚--hard:干脆利落型,直接把工作区的文件也一起变回旧版(慎用,当前未提交的改动会丢掉)HEAD~1:往回退 1 个版本;HEAD~2退 2 个版本
--hard 是"彻底读档":连正在编辑的、还没保存的改动也会被覆盖。练习时用测试文件玩,别拿重要代码练手。
git log # 记下当前有哪些版本
git reset --hard HEAD~1 # 回到上一个版本
git log # 刚才最新的那条 commit 没了
git reset --hard HEAD~2 # 再退一个版本
"后悔药"场景:现在代码是坏的?没关系,回到刚才的正常版本:
git reset --hard HEAD~1
回滚前想清楚这三条:
--hard会丢掉当前未提交的改动,重要代码前先把改动 commit 掉再回滚。- 回滚后
git log里最新的 commit 会消失,这是正常的,不是出 bug。 - 今天只学"回退"。"跳到指定版本"(reset 到具体版本号)以后用到再学,原理一样。
冲突:Git 的"吵架现场"
冲突(conflict)发生的场景:两个人改了同一个文件的同一行,Git 不知道该听谁的,就把决定权交给你,在文件里标出矛盾。
出现冲突时,文件里会出现这样的标记:
<<<<<<< HEAD
这是你的版本(当前分支的内容)
=======
这是别人的版本(要合并进来的内容)
>>>>>>> dev
<<<<<<<、=======、>>>>>>> 是 Git 留下的"吵架现场",你的任务就是当裁判:
- 打开文件
- 把
<<<<<<<到>>>>>>>之间多余的内容删掉,只保留你想要的 - 把三行标记(
<<<<<<<、=======、>>>>>>>)也删干净 - 再
git add+git commit一次,冲突就解决了
冲突标记长这样(示例,不用真的去制造):
def 打招呼():
<<<<<<< HEAD
print("你好")
=======
print("Hello")
>>>>>>> dev
解决思路是二选一或自己改,最终文件长这样:
def 打招呼():
print("你好") # 保留想要的,删掉标记行
今天只要求听懂概念、会认标记,不要求独立解决。几个要点:
- 报错里出现
CONFLICT字样就是冲突,先别慌,这是 Git 的常规操作,不是数据丢了。 - 解决冲突时必须删掉标记行,只删内容留标记,代码会语法报错。
- 单人练习时几乎遇不到冲突,遇到也别怕:把报错复制给 AI,让 AI 帮你分析。
随堂练习
新建一个空文件夹 git练习,全程在 Cursor 终端里完成。
-
练习一(跑通完整流程):
git init→ 新建文件hello.py并随便写一行print("hi")→git add .→git commit -m "第一次提交"→git log。 提示:每步后用git status看状态变化;log 里能看到你刚才的 commit。 -
练习二(感受时光机):修改
hello.py里的内容 → 再次 add + commit → 数数 log 里现在有几个版本 → 执行git reset --hard HEAD~1→ 再用cat hello.py看文件内容变回哪一版了。 提示:回滚后 log 少了一条、文件内容变旧,这就是"时光机";再用git reset --hard HEAD~1回到最开始那版。 -
练习三(分支切换):
git branch dev→git checkout dev→ 新建文件dev.py并 commit →git checkout main→ 用ls看dev.py消失了 → 切回 dev 又回来了。 提示:观察"文件出现/消失"的变化,这就是分支隔离;最后切回 main 收尾。 -
★ 进阶题(乱改自救):把
hello.py改成完全跑不了的一堆乱码,commit 一次;然后用一条命令回到还能跑的那个版本,并解释你用了什么命令、为什么有效。
AI 协作提示词
场景:Git 报错看不懂,复制报错问 AI
提示词:
我是 Git 初学者,在 Windows 上执行 Git 命令时遇到问题,报错内容是:
(把报错原文粘贴到这里)
请用大白话告诉我:这个报错是什么意思?我该怎么解决?请给完整的命令。
场景:想加深理解,让 AI 出 Git 练习题
提示词:
我是初学者,刚学完 git init、add、commit、log、branch、checkout、reset 这些命令。
请给我出 5 道操作练习题,难度从简单到进阶,每道题给出"目标"和"提示",
不要直接给答案,让我自己先做。
常见报错速查
| 报错信息 | 什么意思 | 怎么办 |
|---|---|---|
not a git repository |
这个文件夹还没 git init |
先 git init 再执行其他命令 |
nothing to commit, working tree clean |
购物车是空的(没 add 或没改动) | 改完文件先 git add .,再 commit |
changes not staged for commit |
有改动但还没放进暂存区 | 先 git add .,再 commit |
Please tell me who you are / 报错要配置用户名邮箱 |
Git 不知道你是谁,commit 需要作者信息 | 运行 git config --global user.name "你的名字" 和 git config --global user.email "你的邮箱" |
| 进入了奇怪的编辑界面(vim) | 没带 -m 直接 commit,进入了文本编辑器 |
按 Esc → 输入 :q 回车退出;以后 commit 一定带 -m "说明" |
收个尾
今天的内容串起来就一条线:工作区(改动)→ 暂存区(购物车,add)→ 仓库(存档,commit),顺序不能乱。标准流程是 git init(一次)→ 改代码 → git add . → git commit -m "说明" → git log 看历史,迷路了就 git status。git reset --hard HEAD~1 是"读档键",能回到上一版,但会丢掉未提交的改动,慎用。冲突就是同一行被两个人改了,删掉标记、保留想要的内容即可。
明天装开发环境:Python + VSCode + Cursor,然后跑通你人生第一个 Python 程序。今天 Git 练的 cd、ls 明天全用得上,而且从明天起,每次写代码都要养成 add + commit 的习惯。