Git

Basic Git Knowledge

Git 是一个分布式版本控制系统。它与“文件备份”最大的区别在于,它记录的是状态的快照而非文件的单纯拷贝

四个区域

区域名称 物理对应 操作目的
工作区 (Workspace) 磁盘上看到的 .md.py 文件 实际编写代码和文档的地方
暂存区 (Staging Area / Index) 一个隐藏的二进制文件 .git/index 挑选准备提交的内容(并非所有修改都要一次性提交)
本地仓库 (Local Repository) .git 文件夹内部的快照记录 存储已确认的版本历史,此时已产生 Commit ID
远程仓库 (Remote Repository) GitHub 服务器上的副本 团队协作或跨设备同步的媒介

本地与远程的关系 (Git Vs GitHub)

  • Git 是工具,安装在你的 Windows/WSL 2 上
  • GitHub 是云端宿主,存放你的仓库副本(Remote)
  • git push:将本地快照推送到云端
  • git fetch/pull:从云端获取他人的快照

Workflow

A. 状态追踪 (git status & git add)

  • git status: 会告诉你哪些文件被修改了但没加入暂存区(红色),哪些已经准备好提交(绿色)
  • git add <file>: 将修改标记为“准备好了”。可以用到 .gitignore 文件来排除不需要追踪的 .venv 文件夹或巨大的 .npz 数据集

B. 提交快照 (git commit)

  • 本质: 生成一个 SHA-1 校验和(例如 a1b2c3d...
    • 通过 SHA-1 哈希算法计算出一个 40 位的十六进制字符串独一无二地代表本次 commit
  • 规范: git commit -m "feat: add latex support"。其中 -m 代表 message,message 的惯例如下
类型 说明 示例
feat 新功能 (feature) feat: add latex rendering support
fix 修复 Bug fix: handle empty yaml front-matter
docs 文档更新 (README, 笔记) docs: update deployment steps
style 格式调整 (不影响逻辑,如空格、分号) style: lint sync_publish.py
refactor 代码重构 (既不是新功能也不是修 Bug) refactor: optimize image sync logic
perf 性能优化 perf: speed up hexo generation
chore 构建过程或辅助工具的变动 (如修改 .gitignore) chore: update .venv dependencies

C. 同步远程 (git push & git pull)

  • origin: 远程仓库的默认代号
  • main: 默认主分支名称
  • git pull: 实际上是 git fetch(下载)+ git merge(合并)

Branch & Merge Conflicts

分支本质上是一个指向特定提交(Commit)的指针

冲突处理 (Merge Conflicts)

当你和队友修改了同一个文件的同一行,或者你在两台电脑上修改了同一个配置文件并推送时,就会发生冲突,Git 会在文件里直接注入冲突标记:

1
2
3
4
5
<<<<<<< HEAD
display: true (这是你本地的版本)
=======
display: "true" (这是远程仓库的版本)
>>>>>>> main
  1. 手动抉择: 保留哪一行,或者合并两行
  2. 清理标记: 删掉所有 <<<<, ====, >>>> 符号
  3. 重新提交: git add -> git commit

协作

  • Pull Request (PR): “请求合并”。当你修改了学长的代码,你不是直接写入他的分支,而是发一个 PR 让他 Review
  • Issue: 任务看板。用于记录 Bug 或待办事项(TODO)
  • GitHub Actions: 自动化 CI/CD

More Commands

基础命令

  • git status: 最优先运行的命令。 随时查看哪些文件改了、哪些没存
  • git diff: 查看具体的代码改动。如果你改了 sync_publish.py 但忘了改了哪一行,它会用红绿颜色标出差异
  • git add <file>:
    • git add . : 暂存当前目录下所有改动(慎用,容易把 .venv 这种不需要同步的文件存进去)
    • git add doc/*.md : 仅暂存 doc 文件夹下的所有 Markdown 文件
  • git commit -m "type: description":
    • 生成快照。SHA-1 哈希值就是在这里产生的
  • git log --oneline --graph --all:
    • 以极其直观的“字符树”形式查看提交历史,你会看到各个分支是如何生长和分叉的

分支与合并

  • git branch: 查看本地所有分支
  • git checkout -b <branch_name>: 创建并切换
    • 例如:git checkout -b feat-smpl-render
  • git checkout <branch_name>: 纯切换分支
  • git merge <branch_name>: 将某个分支的成果合并到当前分支
    • 注意:如果你在 main 上执行 git merge feat-smpl-render,就是把实验结果收回主线
  • git branch -d <branch_name>: 删除已经合并完、没用的分支

云端:GitHub

  • git remote -v: 查看你关联的远程仓库地址。你会看到 origin 指向你的 GitHub URL
  • git push origin <branch_name>: 把本地分支推送到云端
  • git pull origin <branch_name>: 把云端的更新拉取下来并自动合并
  • git fetch: 只下载云端的更新,但不合并。这比 pull 更安全,因为你可以先用 git log 看看云端改了什么,再决定要不要合并

撤销

  • git restore <file>: 放弃工作区某个文件的修改,回到上一次 commit 的状态(不可恢复,慎用)
  • git restore --staged <file>: 把文件从暂存区拉回来,撤销 git add
  • git commit --amend: 发现 commit message 写错了?或者漏 add 了一个文件?执行这个命令可以修改上一次提交,不会产生多余的 SHA-1 ID
  • git reset --hard <SHA-1>: 终极重置。将代码彻底回滚到指定的哈希版本
    • 例如:git reset --hard a1b2c3d

临时保存

假设你正在 Research 分支,突然让你去 Blog 分支修一个 Bug

  1. git stash: 把当前写了一半、还没法 commit 的代码暂存
  2. git checkout Blog: 去修 Bug,完成后 commit
  3. git checkout Research: 回来写论文
  4. git stash pop: 把之前藏起来的代码“吐”出来,继续写

.gitignore

它的作用是告诉 Git:哪些文件或文件夹是不需要被追踪(track)的,永远不要把它们提交到仓库里

通常以下内容是不应该放入 Git 仓库的:

  • 临时文件/日志:如 .log 文件,或者是系统自动生成的 .DS_Store(Mac)和 Thumbs.db(Windows)
  • 虚拟环境和依赖包:如 Python 的 .venv 文件夹或 Node. Js 的 node_modules。这些文件可以通过配置文件(如 requirements.txtpackage.json)在另一台电脑上重新生成,没必要上传几万个小文件到 GitHub
  • 编译输出:如 C++ 编译生成的 .exe.obj 文件,或者是 Python 运行产生的 __pycache__ 文件夹
  • 敏感信息:包含 API 密钥、数据库密码的 .env 配置文件

Syntax

.gitignore 使用一种类似于正则表达式的“Glob 模式”来匹配文件路径:

模式 含义 示例
filename 忽略名为 filename 的文件 config.ini
dir/ 忽略整个 dir 目录 .venv/
*.ext 忽略所有以 .ext 结尾的文件 *.log
!important.log 排除例外:即便忽略了 .log,也不忽略这个文件 !important.log
temp/*.txt 忽略 temp 文件夹下一级的 .txt,但不包括子文件夹 temp/1.txt
**/logs/ 忽略任何路径下的 logs 目录 project/module1/logs/

处理“忽略得太晚了”

如果你已经 git addcommit 了一个文件,再把它写进 .gitignore 是没用的。因为 Git 已经开始追踪它了,如果你想让 Git 停止追踪一个已经提交的文件(但不想在硬盘上删除它),需要运行以下命令:

1
2
3
4
5
6
# 1. 从 Git 暂存区中移除文件(文件本身还在硬盘上)
git rm -r --cached <文件名或文件夹>
# 其中 -r 表示recursively,当操作目标是一个目录(文件夹) 而非单个文件时,必须使用 `-r`。它指示 Git 进入该目录,并递归地对其中所有的子目录和文件执行移除操作
# 2. 重新提交
git add .
git commit -m "chore: remove files that should be ignored"

Tips

不需要从零开始写每一个规则。在 gitignore.io,你只需要输入你的开发工具(如 Windows, Python, Visual Studio Code, Hexo),它就会为你生成一个配置清单