Git 基础操作
本章将介绍 Git 的基本操作,包括创建仓库、添加文件、提交修改等核心知识。掌握这些基础操作是高效使用 Git 的前提。
Git 工作流程
理解 Git 的工作区、暂存区和版本库三个区域是掌握 Git 的基础。很多人一开始觉得 Git 操作复杂,其实只要理解了这三个区域的关系,一切都会变得清晰。
三个核心区域
- 工作区(Working Directory):你当前正在编辑的文件所在目录,就是你在电脑上看到的项目文件
- 暂存区(Staging Area / Index):一个临时区域,标记哪些文件变更将在下次提交时被记录。它相当于一个"购物车",你决定哪些修改要提交
- 版本库(Repository / .git):Git 存储项目历史的地方,包含所有提交记录
工作流程说明
- 在工作区修改文件(编辑代码)
- 使用
git add将需要的文件添加到暂存区(选择要提交的修改) - 使用
git commit将暂存区的内容提交到版本库(创建一个永久快照)
实际场景:假设你修改了 5 个文件,但只想提交其中 3 个作为一次提交。你可以用 git add 选择这 3 个文件放入暂存区,然后用 git commit 提交。另外 2 个文件的修改会保留在工作区,不会被这次提交包含。
这种设计的好处在于,你可以精确控制每次提交包含哪些修改,而不是一股脑全部提交。这对于编写有意义的提交历史非常有帮助。
创建仓库
初始化新仓库
# 创建新目录
mkdir my-project
cd my-project
# 初始化 Git 仓库
git init
初始化后会创建一个 .git 目录,这就是 Git 存储版本信息的地方。这个目录包含所有 Git 需要的数据,包括对象数据库、引用、配置等。
# 查看 .git 目录结构
ls .git/
# 输出示例
HEAD # 指向当前分支
config # 仓库配置
objects/ # 存储所有数据对象
refs/ # 存储分支和标签引用
hooks/ # 钩子脚本
克隆现有仓库
# 克隆远程仓库
git clone https://github.com/username/repository.git
# 克隆到指定目录
git clone https://github.com/username/repository.git my-folder
# 克隆特定分支
git clone -b develop https://github.com/username/repository.git
# 浅克隆(只克隆最近一次提交,适合大型仓库)
git clone --depth 1 https://github.com/username/repository.git
克隆操作会自动完成以下工作:
- 下载仓库的所有数据
- 创建远程跟踪分支(
origin/main等) - 创建本地
main分支并检出
查看状态
# 查看工作区状态
git status
# 简短输出(更直观)
git status -s
输出说明:
??- 未跟踪的新文件A- 新添加到暂存区的文件M- 已修改的文件D- 已删除的文件MM- 文件被修改并已暂存,但工作区又有新修改
理解状态信息的重要性:养成频繁使用 git status 的习惯。在每次提交前查看状态,确保你提交的内容符合预期。这能避免很多意外,比如不小心提交了不需要的文件。
添加文件
添加单个文件
# 添加特定文件
git add filename.txt
# 添加多个文件
git add file1.txt file2.txt
添加目录
# 添加当前目录下的所有修改
git add .
# 添加特定目录
git add src/
添加所有文件
# 添加所有修改和新增的文件(不包括删除)
git add .
# 添加所有文件(包括删除操作)
git add -A
# 或
git add --all
., -A 的区别:
git add .:添加当前目录及子目录的所有变更(不包括删除)git add -A:添加整个仓库的所有变更(包括删除)
交互式添加
# 交互式选择要添加的内容
git add -p
# 会逐段显示差异,让你选择是否添加
# y - 添加这个块
# n - 不添加
# s - 分割成更小的块
# e - 手动编辑
git add -p 是一个非常实用的功能,它让你可以逐个代码块地选择要暂存的内容。当你在一个文件中做了多处修改,但想把它们分成多个提交时,这个命令特别有用。
检查文件差异
# 查看工作区与暂存区的差异(未暂存的修改)
git diff
# 查看暂存区与上次提交的差异(已暂存的修改)
git diff --staged
# 查看特定文件的差异
git diff filename.txt
# 查看两次提交之间的差异
git diff commit1 commit2
# 查看统计信息(不显示具体差异)
git diff --stat
提交修改
基本提交
提交是将暂存区的内容保存到版本库的操作,每次提交都会创建一个永久的快照。
git commit -m "提交说明"
例如:
git commit -m "添加用户登录功能"
提交后的版本库状态:
编写好的提交信息
提交信息应该清晰地说明这次修改的目的。推荐的格式:
# 简短标题(不超过 50 个字符)
git commit -m "修复用户注册时的邮箱验证问题"
# 如果需要详细说明,使用不带 -m 的提交
git commit
# 会打开编辑器,第一行是标题,空一行后是详细说明
提交信息的约定:
- 使用祈使语气("添加"而不是"添加了")
- 标题简短,说明做了什么
- 正文解释为什么做这个修改
添加并提交
# 一步完成添加和提交(只适用于已跟踪的文件)
git commit -a -m "提交说明"
# 简写
git commit -am "提交说明"
注意:-a 只会提交已跟踪的文件(已经被 add 过的文件),新增的文件不会被包含。
修改提交信息
如果发现提交信息写错了,可以修改最后一次提交:
# 修改最后一次提交的信息
git commit --amend -m "新的提交说明"
# 修改最后一次提交,同时添加遗漏的文件
git add forgotten-file.txt
git commit --amend --no-edit # --no-edit 保持原提交信息不变
修改提交信息的过程(不会创建新提交,而是替换最后一次提交):
注意:如果最后一次提交已经推送到远程,修改后需要使用 git push --force,这会改写历史,在团队协作中要谨慎使用。
查看提交历史
# 查看提交历史
git log
# 简洁输出(一行一个提交)
git log --oneline
# 显示每次提交的文件差异
git log -p
# 显示文件修改统计
git log --stat
# 查看最近 n 条记录
git log -n 5
# 图形化显示所有分支
git log --graph --oneline --all
# 查看特定文件的修改历史
git log --follow filename.txt
# 查看某个时间段的提交
git log --since="2024-01-01"
git log --until="2 weeks ago"
# 按作者筛选
git log --author="张三"
自定义输出格式:
# 美化输出
git log --pretty=format:"%h - %an, %ar : %s" --graph
# 常用占位符:
# %h - 短哈希值
# %an - 作者名
# %ar - 相对时间(如 3 天前)
# %s - 提交说明
# %d - 引用名(分支、标签)
撤销操作
撤销工作区修改
# 撤销特定文件的修改(恢复到暂存区的状态)
git checkout -- filename.txt
# 使用新命令(Git 2.23+,更直观)
git restore filename.txt
# 撤销所有修改
git checkout -- .
git restore .
警告:这些操作会丢弃工作区的修改,且无法恢复。使用前确保你真的不需要这些修改。
取消暂存
# 取消暂存特定文件
git reset filename.txt
git restore --staged filename.txt
# 取消所有暂存
git reset
git restore --staged .
撤销提交
soft 模式(保留修改到暂存区)
# 撤销最后一次提交,修改保留在暂存区
git reset --soft HEAD~1
soft 模式示意图:
执行后,提交 C 被撤销,但修改保留在暂存区,可以直接重新提交。这在你想修改最后一次提交的内容时很有用。
mixed 模式(默认,保留修改到工作区)
# 撤销最后一次提交,修改保留在工作区
git reset --mixed HEAD~1
# 或简写
git reset HEAD~1
mixed 模式示意图:
执行后,提交 C 被撤销,修改回到工作区,需要重新 add 后提交。
hard 模式(丢弃修改)
# 撤销最后一次提交,丢弃所有修改
# 警告:这会丢失所有修改,请谨慎使用!
git reset --hard HEAD~1
hard 模式示意图:
执行后,提交 C 和其中的所有修改都被永久删除,HEAD 指向 B。如果误操作了,可以通过 git reflog 找回。
撤销前 n 次提交
# 撤销前 n 次提交,保留修改在暂存区
git reset --soft HEAD~n
# 撤销前 3 次提交
git reset --soft HEAD~3
恢复删除的文件
# 恢复误删的文件(从暂存区恢复)
git checkout HEAD -- filename.txt
git restore --source=HEAD filename.txt
# 恢复到某个提交的版本
git checkout abc123 -- filename.txt
使用 reflog 恢复误操作
reflog 记录了 HEAD 的所有变化,即使使用了 reset --hard,也能通过 reflog 找回丢失的提交。
# 查看所有操作历史
git reflog
# 输出示例
abc1234 HEAD@{0}: reset: moving to HEAD~1
def5678 HEAD@{1}: commit: 添加重要功能
...
# 恢复到指定操作之前的状态
git reset --hard HEAD@{1}
# 或创建新分支
git branch recover-branch HEAD@{1}
文件操作
删除文件
# 从工作区和暂存区删除
git rm filename.txt
# 只从暂存区删除(保留工作区文件)
git rm --cached filename.txt
# 删除目录
git rm -r directory/
# 强制删除(即使文件有未提交的修改)
git rm -f filename.txt
重命名文件
git mv old-name.txt new-name.txt
这相当于执行了以下操作:
mv old-name.txt new-name.txt
git rm old-name.txt
git add new-name.txt
使用 git mv 的好处是 Git 能正确追踪文件的重命名历史。
查看文件历史
# 查看文件的提交历史
git log filename.txt
# 查看文件的每次修改内容
git log -p filename.txt
# 查看谁修改了文件的每一行
git blame filename.txt
# 查看文件在不同提交中的内容
git show abc123:filename.txt
.gitignore 文件
创建 .gitignore 文件来忽略不需要跟踪的文件:
# 忽略所有 .log 文件
*.log
# 忽略 node_modules 目录
node_modules/
# 忽略构建输出
build/
dist/
# 忽略敏感文件
secret.txt
.env
# 但跟踪 lib.js(即使在忽略的目录中)
!lib.js
# 忽略当前目录及子目录的所有 .tmp 文件
**/*.tmp
# 只忽略根目录下的 build 目录
/build/
创建 .gitignore 的技巧:
GitHub 提供了各种语言和框架的 .gitignore 模板,可以参考 gitignore 模板。
# 如果文件已经被跟踪,需要先取消跟踪
git rm --cached filename.txt
# 然后添加到 .gitignore
储藏工作区
当你需要切换分支但不想提交当前未完成的工作时,可以使用储藏(stash)功能。
# 储藏当前工作区的修改
git stash
# 带说明的储藏
git stash push -m "正在开发新功能"
# 查看储藏列表
git stash list
# 恢复最近的储藏(不删除储藏记录)
git stash apply
# 恢复并删除最近的储藏
git stash pop
# 恢复指定的储藏
git stash apply stash@{2}
# 删除储藏
git stash drop stash@{0}
# 清空所有储藏
git stash clear
# 储藏未跟踪的文件
git stash -u
# 储藏所有文件(包括被 .gitignore 忽略的)
git stash -a
实际使用场景:
你正在开发功能 A,突然需要切换到另一个分支修复紧急 bug:
# 1. 储藏当前工作
git stash push -m "功能A开发中"
# 2. 切换到修复分支
git checkout hotfix-branch
# 3. 修复 bug 并提交
git commit -am "修复紧急 bug"
# 4. 切换回原分支
git checkout feature-branch
# 5. 恢复之前的工作
git stash pop
标签操作
创建标签
# 创建轻量标签(只是一个指向提交的引用)
git tag v1.0.0
# 创建附注标签(包含标签信息,推荐用于正式发布)
git tag -a v1.0.0 -m "版本 1.0.0 发布"
# 为历史提交添加标签
git tag -a v0.9.0 abc123 -m "0.9.0 版本"
# 签名标签(使用 GPG 签名)
git tag -s v1.0.0 -m "签名的标签"
列出标签
# 列出所有标签
git tag
# 搜索标签(支持通配符)
git tag -l "v1.*"
# 查看标签详情
git show v1.0.0
删除标签
# 删除本地标签
git tag -d v1.0.0
# 删除远程标签
git push origin --delete v1.0.0
推送标签
# 推送特定标签
git push origin v1.0.0
# 推送所有标签
git push origin --tags
配置 Git
全局配置
# 设置用户名和邮箱
git config --global user.name "张三"
git config --global user.email "[email protected]"
# 设置默认编辑器
git config --global core.editor "vim"
git config --global core.editor "code --wait" # VS Code
# 设置默认分支名
git config --global init.defaultBranch main
# 启用颜色输出
git config --global color.ui auto
查看配置
# 查看所有配置
git config --list
# 查看特定配置
git config user.name
# 查看配置来源
git config --list --show-origin
别名设置
# 设置常用别名
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
# 更复杂的别名
git config --global alias.lg "log --oneline --graph --all"
git config --global alias.last "log -1 HEAD --stat"
设置后可以使用简写:
git st # 等同于 git status
git co main # 等同于 git checkout main
git lg # 查看图形化历史
小结
本章我们学习了:
- Git 工作流程:工作区、暂存区、版本库的三区模型
- 创建仓库:初始化和克隆
- 查看状态:
git status、git diff - 添加和提交:
git add、git commit的各种用法 - 撤销操作:
reset、restore、reflog恢复误操作 - 文件操作:删除、重命名、查看历史
- .gitignore:忽略不需要跟踪的文件
- 储藏:
git stash临时保存工作 - 标签:版本标记
- 配置:个性化 Git 设置
练习
- 创建一个新仓库,添加几个文件并提交
- 修改已提交的文件,尝试使用
git diff查看差异 - 使用
git add -p交互式选择要暂存的内容 - 创建一个
.gitignore文件 - 使用
git stash储藏并恢复工作区 - 练习
git reset的三种模式