为什么要用Git
想象你正在写一篇论文:
论文_初稿.doc
论文_修改1.doc
论文_最终版.doc
论文_最终版_绝对不改.doc
时间一长,你不知道哪个才是最新版,也不敢删掉旧的。Git 就是帮你管理这些“版本”的工具,它会记录每次修改的内容、时间、作者,让你能随时回到过去的某个状态,也能和别人并行合作,最后合并到一起。
核心概念先有个印象:
仓库(Repository):一个被 Git 管理的项目目录,里面藏着完整的历史记录。
提交(Commit):一次“保存快照”的操作,就像游戏的存档点。
安装并配置Git
环境:WSL2,Ubuntu24.04
打开终端,先更新包列表,再安装 Git:
sudo apt update
sudo apt install git -y
安装完成后,检查是否成功:
git --version
你应该会看到类似 git version 2.43.0 的输出(版本号以实际为准)。
配置身份
Git 每次提交都会记录“谁做的”,所以要先告诉 Git 你的名字和邮箱。这个信息会随提交一起被永久记录在历史里。
在终端依次执行(把名字和邮箱换成你自己的,建议邮箱使用 GitHub 注册邮箱):
git config --global user.name "你的名字"
git config --global user.email "你的邮箱@example.com"
--global 表示这个配置对你整个系统的当前用户生效,所有 Git 仓库都会默认使用这个身份。
验证一下配置是否生效:
git config --global --list
你会看到类似输出:
user.name=你的名字
user.email=你的邮箱@example.com
可选设置
为了让以后的输出更易读,建议打开命令行颜色高亮:
git config --global color.ui auto
在 Ubuntu 终端中,这会让 diff、status 等命令的输出用不同颜色标记增、删、改,看起来一目了然。
创建仓库与第一次提交
创建第一个项目目录
首先,我们在主目录下建一个练习文件夹,叫 my-first-repo:
cd ~
mkdir my-first-repo
cd my-first-repo
初始化仓库
让 Git 接管这个目录:
git init
你会看到类似输出:
Initialized empty Git repository in /home/你的用户名/my-first-repo/.git/
这行字告诉你:仓库诞生了。它会在这个目录下创建一个隐藏文件夹 .git,里面存着 Git 需要的所有历史数据。用 ls -a 可以看到它。
重要认知:
git init后,这个目录就变成了工作区(Working Directory),里面的.git文件夹就是仓库(Repository)。
Git 的三个区域
继续之前,必须先把这三个区域记在心里,这是 Git 的灵魂:
工作区(Working Directory)
就是你能看到的项目文件夹,你直接在这里增、删、改文件。
Git 会监视这里的变化,但不会自动记录。
暂存区(Staging Area / Index)
你希望被记录的那些修改,需要先“添加”到这个区域。
可以理解为一张“准备提交的快照暂存清单”。
使用
git add会把文件从工作区送到暂存区。
仓库(Repository / Commit History)
.git文件夹里的东西,藏着所有历史提交。使用
git commit会把暂存区的内容永久保存为一个“提交”。
工作流程是:
工作区 ──(git add)──> 暂存区 ──(git commit)──> 仓库
记住这个流程,后面你就能理解每一个命令在干什么。
创建第一个文件
在工作区创建一个文件 hello.txt:
echo "Hello, Git" > hello.txt
现在用 git status 看一眼仓库状态:
git status
输出会显示:
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
hello.txt
nothing added to commit but untracked files present (use "git add" to track)
Git 告诉你:
当前在 master 分支(这是默认的主分支名)。
还没有任何提交(No commits yet)。
hello.txt 是未跟踪文件(Untracked),工作区有个新文件,但 Git 还没管它。
把文件加入暂存区
让 Git 开始跟踪 hello.txt:
git add hello.txt
再运行 git status 看看变化,现在输出像这样:
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: hello.txt
hello.txt 现在在暂存区 了,状态是 “new file”,准备被提交。
第一次提交
把暂存区的内容永久保存到仓库中:
git commit -m "第一次提交:添加 hello.txt"
-m后面跟的是提交信息(commit message),用来描述这次做了什么修改。提交信息必须写,而且最好写清楚,这是以后看历史的你会感谢你的事。
执行后你会看到:
[master (root-commit) xxxxxxx] 第一次提交:添加 hello.txt
1 file changed, 1 insertion(+)
create mode 100644 hello.txt
这意味着:
在
master分支上生成了第一个提交(root-commit 表示它是整个历史的根)。一个文件改变了,添加了一行内容。
提交的哈希值(一串十六进制字符)已经生成,唯一标识这次提交。
查看历史
现在看看仓库里记录了什么:
git log
输出类似:
commit a1b2c3d4e5f...(一串哈希值)
Author: 你的名字 <你的邮箱@example.com>
Date: Mon Apr 27 10:00:00 2026 +0800
第一次提交:添加 hello.txt
你看到了:
提交的唯一哈希值(不用记全,前几位就能区分)
作者和日期信息,正是你第一章配置的身份
提交信息
按 q 键可以退出 log 的浏览模式。
巩固流程
趁热打铁,再做一轮完整的修改→暂存→提交。
修改文件:向
hello.txt追加一行
echo "Git is fun" >> hello.txt
查看状态:
git status
查看具体改动:
git diff
能看到你添加了什么内容(以 + 开头的绿字)。
加入暂存区:
git add hello.txt
提交:
git commit -m "添加第二行:Git is fun"
再次查看历史:
git log
现在会看到两次提交,从新到旧排列。最新的在上面。
深入暂存区与文件管理
接下来会教你后悔药怎么吃——修改错了怎么撤,提交反悔了怎么退,还会让你真正看透 git diff 的各种用法。先确认一下历史:
cd ~/my-first-repo
git log --oneline
你应该能看到类似两条记录(哈希值会不同):
a1b2c3d 添加第二行:Git is fun
e5f6g7h 第一次提交:添加 hello.txt
git diff 的三种常用姿势
git diff 是“对比神器”,不同参数对比不同区域。
工作区 vs 暂存区(
git diff,无参数)
先制造一个工作区修改:
echo "第三行:learning diff" >> hello.txt
现在修改只存在工作区,未暂存。运行:
git diff
输出会显示什么?以 + 开头的绿字是你新增的内容,前面带有 @@ 的行是位置标记。这个命令对比的是工作区和暂存区(如果暂存区为空,就是和最新提交比)。
因为暂存区现在还是原来的版本,所以你能看到新增的“第三行”。
暂存区 vs 最新提交(
git diff --staged)
先把刚才的修改加入暂存区:
git add hello.txt
现在再运行 git diff 会发现没有任何输出,因为工作区和暂存区内容一致了。但你想看 暂存区和最新提交相比有什么变化,就用:
git diff --staged
(也可以用 git diff --cached,一个意思。)
这次你会看到刚才添加的 +第三行:learning diff,说明暂存区比当前提交多了这一行。
工作区 vs 最新提交(
git diff HEAD)
在工作区再追加一行(暂存区没变):
echo "第四行:will be unstaged" >> hello.txt
现在工作区比暂存区多了一行,暂存区又比最新提交多了一行。直接比较工作区和最新提交:
git diff HEAD
你会看到两条新增行:一条是之前暂存的“第三行”,另一条是刚才加的“第四行”。HEAD 总是指向当前分支的最新提交,所以这个命令跳过了暂存区,直接拿工作区和最后一次 commit 比。
小总结:
git diff→ 工作区 vs 暂存区
git diff --staged→ 暂存区 vs HEAD
git diff HEAD→ 工作区 vs HEAD
撤销工作区的修改
假设你现在发现“第四行”写错了,想丢弃工作区的这个修改,恢复成暂存区(或最新提交)的样子。在丢弃之前,再看一眼状态确认:
git status
你会看到 hello.txt 既有暂存的修改(绿色 “modified”),又有未暂存的修改(红色 “modified”)。现在我们丢弃工作区的修改(即刚才加的那行“第四行”):
git checkout -- hello.txt
或者新版本 Git 也可以使用等价命令 git restore hello.txt。执行后,查看文件内容:
cat hello.txt
你会发现“第四行”消失了,文件内容回到了暂存区保存的版本(只有三行)。再用 git diff HEAD 看,现在只显示暂存区里的“第三行”,说明工作区已经恢复到了暂存区的状态。
注意:这个操作会永久丢失工作区的未提交修改,而且很难恢复(除非用 IDE 的本地历史)。请一定确认要丢弃再执行。
取消暂存
当前的暂存区里还保存着“第三行”的修改。如果你决定:先不把第三行放在这次提交里,但保留在工作区,该怎么操作?
我们需要把文件从暂存区移回工作区。
git reset HEAD hello.txt
(新版本 Git 也可以用 git restore --staged hello.txt)
运行之后,git status 你会看到:
“Changes to be committed” 里不再有
hello.txt但
hello.txt出现在 “Changes not staged for commit” 里,而且还是被修改过的状态
也就是说,文件从暂存区退回了工作区,修改本身没有丢失。
此时如果你又后悔了,可以再次 git add 把它暂存回去。如果你连这个修改都不想要了,可以用上一步的 git checkout -- hello.txt 彻底丢弃。
git reset 的三种模式
比撤销文件更彻底的,是撤销一次提交。我们先创建一个“临时”提交来演示。
先把刚才的第三行暂存并提交:
git add hello.txt
git commit -m "添加第三行:learning diff"
现在 git log --oneline 会显示三个提交。
接下来,我们要“退回”到上一个提交。git reset 可以移动当前分支指针,有三种常用模式:
1. --soft:提交后悔了,但想重新修改提交信息
执行(注意:把 HEAD~1 指向上一个提交):
git reset --soft HEAD~1
git status 查看状态,你会看到 hello.txt 的修改仍然在暂存区(绿色,等待提交),但 git log 里“添加第三行”那个提交已经消失了。这就像刚 git add 完,还没来得及 commit。你可以修改提交信息,或添加其他文件后再提交。
2. --mixed(默认):提交错了,想把修改推回工作区重新编辑
先重新提交回去,以便演示:
git commit -m "第三行(临时)"
现在再次回退,这次不给模式(默认就是 --mixed):
git reset HEAD~1
再 git status,你会发现:
暂存区是空的
hello.txt的修改在工作区,“not staged”
这就是让你重新整理要提交的内容,再 add 并 commit。
3. --hard:彻底放弃,回到干净状态(危险)
我们故意创建一个新文件并提交,然后彻底丢弃它。
echo "临时垃圾文件" > junk.txt
git add junk.txt
git commit -m "添加一个不要的提交"
现在回退:
git reset --hard HEAD~1
结果:
用
git log看,那个提交消失了junk.txt被彻底删除,工作区干干净净
这就是 --hard 的威力:它会让你的工作区和暂存区完全和回退到的提交一致,未提交的修改也会丢失。一般情况下,不要轻易用 --hard,除非你十分确定可以丢弃。
分支的世界
分支是 Git 真正强大的地方——你可以在一条独立的线上开发新功能,不影响主线的稳定,成熟后再合并回去。
想象你在玩一种可以存档的冒险游戏。主线剧情是 master(或现在叫 main),当你走到某个关卡,突然想试试“如果我先去拿隐藏道具会怎样”,你就可以在那个时间点创建一个分支,在里面自由探索。就算玩砸了,主剧情毫发无损;如果探索成功,就把分支的进展合并回主线。
在 Git 里,分支仅仅是一个指向某个提交的轻量级指针。创建分支几乎瞬间完成,完全不占什么空间。
默认的主分支名在较新的 Git 中是 main,但你的仓库可能还是 master(取决于版本和配置)。我们这里以 master 为例,如果你看到的是 main,命令中替换即可。
查看分支
先看看当前仓库有哪些分支:
git branch
输出:
* master
前面的 * 表示你当前所在的分支——master。
创建分支
假设我们想给 hello.txt 添加一个“作者署名”功能,但不想直接在主线上改。我们创建一个叫 feature/author 的新分支:
git branch feature/author
git branch 再看一下分支列表:
feature/author
* master
新分支出现了,但 * 还停留在 master 上。创建分支并不会自动切换过去。
切换分支
要进入新分支工作,需要切换过去。推荐使用较新的命令 git switch(Git 2.23+),语义更清晰:
git switch feature/author
你也可以使用传统的 git checkout feature/author,效果一样。现在再用 git branch 查看分支,* 已经移到 feature/author 前面了,表示你正在该分支上。
也可以同时创建并切换,用:
git switch -c 分支名
# 或
git checkout -b 分支名
在分支上工作和提交
现在你在 feature/author 分支上。让我们修改 hello.txt,在文件末尾添加一行署名:
echo "Author: GitLearner" >> hello.txt
git status 查看状态,暂存并提交:
git add hello.txt
git commit -m "在 feature/author 分支添加作者署名"
用 git log --oneline 看一下这个分支的日志,你会看到,feature/author 比 master 多了一个新提交。切回 master 看看文件:
git switch master
cat hello.txt
你会发现,master 上的 hello.txt 完全没有那句 “Author: GitLearner”。因为那个修改只存在于 feature/author 分支上。这就是分支隔离的魔力。
合并分支
现在你觉得“署名功能”已经开发好了,想把它合并回主分支。首先确保你当前在想要合并到的目标分支上(即主分支 master):
git switch master
然后执行合并:
git merge feature/author
你会看到类似输出:
Updating a1b2c3d..f6g7h8i
Fast-forward
hello.txt | 1 +
1 file changed, 1 insertion(+)
关键词:Fast-forward(快进合并)。
为什么会快进?
因为 master 自从分出 feature/author 之后,自己没有产生任何新提交。feature/author 相当于在 master 的基础上直线往前走了几步。合并时,Git 只需要把 master 的指针直接“快进”到 feature/author 的最新提交即可,无需创建额外的“合并提交”。
此时的提交历史是一条直线:
第一次提交 → 添加第二行 → 添加第三行 → 在 feature/author 分支添加作者署名
此时 master 和 feature/author 指向同一个提交。你可以用 git log --oneline 验证。再查看 hello.txt,署名已经出现了。
合并后分支清理
功能分支完成使命后,可以安全删除:
git branch -d feature/author
查看分支列表,只剩 master。如果分支没有被合并,用 -d 会拒绝删除(防止误删),此时若确定不需要,可用 -D 强制删除。
理解“分叉”合并(非快进)
快进合并很干净,但现实里往往各个分支会同时推进,产生分叉历史。我们模拟一次。
创建并切换到新分支
feature/sign:
git switch -c feature/sign
在这个分支上修改,在
hello.txt添加一行 “Sign: Best regards”:
echo "Sign: Best regards" >> hello.txt
git add hello.txt
git commit -m "在 feature/sign 分支添加签名"
切回
master,在master上也做一个修改,比如新建一个文件readme.md:
git switch master
echo "This is a README" > readme.md
git add readme.md
git commit -m "在 master 添加 README"
现在两个分支各自往前走了。看一下图景:master 和 feature/sign 在 “添加作者署名” 这个提交之后分叉了。查看图形化日志(也可以不加 --graph,但图形很直观):
git log --oneline --graph --all
你会看到类似:
* (HEAD -> master) 在 master 添加 README
| * (feature/sign) 在 feature/sign 分支添加签名
|/
* 在 feature/author 分支添加作者署名
* 添加第三行:learning diff
...
合并分叉:产生合并提交
现在把 feature/sign 合并回 master。
确保当前在 master:
git merge feature/sign
这一次,因为两个分支各自有新提交,Git 无法直接快进。它会生成一个 合并提交(merge commit),会把两个分支的修改合并到一起。
你会进入一个提交信息编辑界面(通常是 nano 或 vim)。如果是 nano,直接 Ctrl+X 退出保存就行;如果是 vim,按 :wq 保存退出。Git 已经默认填好了 “Merge branch ‘feature/sign’”。
合并完成后,再看看日志图:
git log --oneline --graph --all
你会看到类似:
* (HEAD -> master) Merge branch 'feature/sign'
|\
| * (feature/sign) 在 feature/sign 分支添加签名
* | 在 master 添加 README
|/
* 在 feature/author 分支添加作者署名
...
这就是典型的功能分支开发与合并。
Git的简单使用-1
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法