Git 基础操作不是命令顺序表,而是围绕几个问题反复判断:我在哪个仓库、哪些文件变了、哪些变化应该进入下一次提交、这次提交会不会影响别人、如果错了能不能恢复。

1. 获取 Git 仓库

通常有两种获取 Git 项目仓库的方式:

  1. 将尚未进行版本控制的本地目录转换为 Git 仓库。
  2. 从其它服务器克隆一个已存在的 Git 仓库。

在目录中初始化仓库

// 当前目录下初始化仓库
git init

该命令将创建一个名为 .git 的子目录,包含 Git 仓库所有必需文件。

克隆现有的仓库

如果你想获得一份已存在的 Git 仓库的拷贝,使用 git clone 命令:

// 克隆远程仓库
git clone <url>

自定义本地仓库名字:

// 指定仓库本地命名
git clone <url> <name>

克隆实际上是多个命令的分解:初始化本地仓库 → 添加远程仓库 → 拉取远程数据。

2. 记录每次更新

拥有仓库后,运行 git status 查看仓库状态。工作目录中的文件分为两种状态:

  • 已跟踪:被纳入版本控制的文件,上一次快照中有记录,状态可能是未修改、已修改或已放入暂存区。
  • 未跟踪:不在上次快照中、也未放入暂存区的文件。

使用 git add 将文件添加至暂存区。对已暂存的文件继续修改后,可以用 git diff 查看工作区和暂存区之间的差异。这里的关键不是“add 之后 commit”,而是用暂存区选择一个可解释的历史单元。

完成开发并提交至暂存区后,运行 git commit 提交更新至 Git 目录,记录此次快照。

检查当前仓库状态

// 查看当前仓库状态总览
git status
 
// 查看当前仓库状态简览
git status -s
git status --short
 
// 当前文件和暂存区之间的具体差异
git diff
 
// 暂存区和最后一次提交的具体差异
git diff --staged
git diff --cached

追踪新文件或暂存已修改的文件

// 添加文件到暂存区
git add <file>
 
// 添加路径到暂存区
git add <path>

3. 提交更新

// 提交更新,同时会启动文本编辑器来输入提交说明
git commit
 
// 将提交信息与命令放在同一行
git commit -m <msg>
 
// 跳过暂存,直接提交已跟踪文件
git commit -a

4. 忽略文件

有些文件无需纳入 Git 管理,也不希望它们出现在未跟踪文件列表。可以创建一个名为 .gitignore 的文件,列出要忽略的文件模式。不同目录下可以拥有不同的 .gitignore

.gitignore 格式规范

  • 所有空行或者以 # 开头的行都会被 Git 忽略。
  • 可以使用标准的 glob 模式匹配,它会递归地应用在整个工作区中(glob 模式是指 shell 所使用的简化了的正则表达式)。
  • 匹配模式可以以(/)开头防止递归。
  • 匹配模式可以以(/)结尾指定目录。
  • 要忽略指定模式以外的文件或目录,可以在模式前加上叹号(!)取反。

GitHub 有一个十分详细的针对数十种项目及语言的 .gitignore 文件列表,你可以在 https://github.com/github/gitignore 找到它。

5. 查看提交历史

进行多次开发后,使用 git log 查看提交历史。

常用选项

// 格式化输出一行显示提交历史
git log --oneline
 
// 显示分支与合并历史的 ASCII 图形
git log --graph
 
// 显示每次提交的文件修改统计信息
git log --stat
 
// 按补丁格式显示每个提交引入的差异
git log --patch
git log -p
 
// 仅显示最近的 n 条提交
git log -<n>
 
// 按时间范围过滤
git log --since="2024-01-01" --until="2024-06-01"
git log --after="2024-01-01" --before="2024-06-01"

定制显示格式

--pretty=format 可以定制记录的显示格式:

git log --pretty=format:"%h - %an, %ar : %s"

常用格式占位符:%h(简写哈希)、%an(作者名字)、%ar(作者修订日期距今)、%s(提交说明)。

6. 撤销操作

提交后发现漏掉文件或提交信息写错,可以使用 --amend 重新提交:

// 撤销上次提交
git commit --amend

此命令会将当前暂存区的文件一并提交,最终只有一个提交,第二次提交将代替第一次提交的结果。只在提交尚未共享、或者团队明确允许时使用。

撤销已暂存的文件

// 取消暂存区文件
git reset HEAD <file>

git reset 是个危险的命令,加上 --hard 选项则更是如此。但在上述场景中,工作目录中的文件尚未修改,因此相对安全。

撤销对文件的修改

// 撤销工作区的文件修改
git checkout -- <file>

注意:git checkout -- <file> 是一个危险的命令。你对该文件的本地任何修改都会消失——Git 会用最近提交的版本覆盖它。除非你确实清楚不想要本地修改,否则不要使用这个命令。

7. 远程仓库管理

为了在 Git 项目上协作,你需要管理远程仓库。

查看远程仓库

// 查看远程仓库
git remote
 
// 显示远程仓库简写及其 URL
git remote -v

添加远程仓库

// 添加一个新的远程 Git 仓库
git remote add <remote-name> <url>

从远程仓库中抓取与拉取

// 从远程仓库拉取数据,不自动合并
git fetch <remote-name>
 
// 从远程仓库抓取数据,并尝试自动合并到当前分支
git pull

推送到远程仓库

// 推送分支到远程仓库
git push <remote> <branch>

查看、重命名与移除远程仓库

// 查看远程仓库
git remote show <remote>
 
// 远程仓库的重命名
git remote rename <old> <new>
 
// 远程仓库的移除
git remote remove <name>

8. 打标签

Git 可以给仓库历史中的某一个提交打上标签,以示重要。比较有代表性的是标记发布结点(v1.0v2.0 等)。

Git 支持两种标签:轻量标签(lightweight)附注标签(annotated)

  • 轻量标签很像一个不会改变的分支——它只是某个特定提交的引用。
  • 附注标签是存储在 Git 数据库中的一个完整对象,包含打标签者的名字、电子邮件地址、日期时间以及标签信息,可以使用 GPG 签名并验证。通常建议创建附注标签。

创建标签

// 创建轻量标签
git tag <tagname>
 
// 创建附注标签
git tag -a <tagname>

对过去的提交打标签,输入提交的 SHA-1 值:

// 后期打标签
git tag <tagname> <commit-id>

查看标签

// 列出已有的标签
git tag
 
// 显示标签信息
git show <tagname>

共享标签

默认情况下 git push 不会传送标签到远程仓库,创建完标签后必须显式推送:

// 推送标签到远程仓库
git push origin <tagname>
 
// 推送全部标签
git push origin --tags

删除标签

// 删除标签
git tag -d <tagname>
 
// 删除远程仓库标签
git push origin --delete <tagname>

9. 日常操作原则

每次操作前看状态git status -sgit branch --show-current 能避免大多数低级错误。

提交前看差异git diff 看未暂存变化,git diff --staged 看将要进入提交的变化。不要盲提交。

撤销前确认层级:取消暂存、撤销工作区、改写提交、重置分支是不同层级。越靠近 reset --hard 和强推,越要停下来确认。

远程操作默认保守fetchpull 更可控;push --force-with-lease 比裸 push --force 更安全;共享分支上少改历史。

标签是发布契约:标签一旦推送给别人,就当作公开引用对待。删除或重打标签需要明确沟通。

掌握基础操作后,Git 的真正威力在于分支和历史整理:它们决定团队如何并行工作、如何审查变化、如何恢复错误。