适用:所有 Linux 耗时:约 40 分钟 前置:T1(会编辑文件)

Git 最常见的错误用法,是把它当成"上传工具"。

它真正解决的是一个问题:我改了东西,怎么退回上一版?

这一篇只讲最小闭环——够你保护自己的文件,不多讲一行。


一、先想清楚:Git 解决什么

没 Git 的时候

报告-最终版.docx
报告-最终版2.docx
报告-最终版-真的最终.docx
报告-最终版-改完待定-20261020.docx

这是所有人都有过的经历。 文件名承载了版本信息,然后就失控了。

有 Git 的时候

报告.docx      ← 只有一个文件
历史记录:       ← 版本信息在这里
  10-20 17:30  改了第三段
  10-20 15:00  加了结论
  10-19 21:00  初稿

两个核心能力:

  1. 能退回:任何一次修改都能还原
  2. 能对比:这次改了什么,一行行看得见

不要被吓到

Git 的命令有几十个。但日常只需要 7 个。

剩下那些(rebase、cherry-pick、bisect)在用不到的时候学,只会增加心理负担。


二、四个概念(用"拍照"来理解)

概念类比说明
工作区你正在摆的场景你眼前这些文件
暂存区(index)取景框你决定"这次要拍进去的部分"
本地仓库(.git)相册已经拍下来的照片
远程仓库(remote)云相册备份到别处的相册

流程:

改文件(工作区)
   ↓ git add        ← 放进取景框
暂存区
   ↓ git commit     ← 按下快门
本地仓库(一张照片 = 一个版本)
   ↓ git push       ← 上传云相册
远程仓库

“暂存区"这个中间层让新手困惑,但它有用:你可以一次改十个文件,但只提交其中三个。这在"改了一大堆但只想提交一部分"时是必需的。


三、七个命令(日常全部)

一次性配置

git config --global user.name "你的名字"
git config --global user.email "你的邮箱"
git config --global init.defaultBranch main
git config --global core.editor nano     # 免得 commit 时进了 vim 出不来

只做一次。 之后所有仓库通用。

1. git init —— 建仓库

mkdir 我的项目 && cd 我的项目
git init

会在当前目录建一个 .git 隐藏目录,所有历史都存在里面。

2. git status —— 最常用的命令

git status

这个命令你应该用得比所有其他命令加起来还多。

输出告诉你:哪些文件改了、哪些已暂存、当前在哪个分支。

git status -s        # 简短版

简短版输出:

 M 文件1.txt        ← 改了,没暂存
M  文件2.txt        ← 改了,已暂存
?? 新文件.txt       ← 未跟踪(Git 还没管它)

3. git add —— 放进暂存区

git add 文件.txt           # 单个
git add .                  # 当前目录下所有改动
git add *.py               # 按模式
git add -A                 # 所有改动(含删除)

4. git commit —— 拍下这一版

git commit -m "说明这次改了什么"

-m 后面那句话很重要。 三个月后你只会看到这条信息,“改了"这种说明等于没写。

好的提交信息:

✅ 修复登录页在 Safari 下按钮错位
✅ 补充第三章的练习题(12 道)
❌ 更新
❌ 改了点东西
❌ asdf

一个土办法:写完后问自己"如果只看这句话,能想起改了什么吗”。

跳过暂存直接提交(已跟踪的文件):

git commit -am "说明"

-a 只对"已经跟踪的文件"生效,新建的文件还是要 git add。

5. git log —— 看历史

git log                    # 完整
git log --oneline          # 一行一条(最常用)
git log --oneline -10      # 最近 10 条
git log --oneline --graph  # 带分支图
git log -p 文件            # 看某个文件的每次改动内容

6. git diff —— 看改了什么

git diff                   # 工作区 vs 暂存区(还没 add 的改动)
git diff --staged          # 暂存区 vs 上次提交(add 了的改动)
git diff HEAD              # 工作区 vs 上次提交(全部改动)

提交前跑一下 git diff --staged,确认这次到底改了什么。这是防止提交垃圾的关键一步。

7. git restore / git reset —— 退回

这是 Git 最有价值的能力,也是最需要小心的。

# 撤销工作区的改动(回到上次提交的状态)⚠️ 改了的东西会没
git restore 文件.txt

# 把文件从暂存区拿出来(改动还在,只是不提交了)
git restore --staged 文件.txt

# 撤销最近一次提交,但保留改动
git reset --soft HEAD~1

# 撤销最近一次提交,且丢弃改动 ⚠️⚠️
git reset --hard HEAD~1

⚠️ git restore 文件 和 git reset --hard 会永久丢弃未提交的改动。 没有回收站。 用之前先 git status 和 git diff 看清楚。

救命的一招:如果你 reset --hard 删错了,还能找回来(只要没被 Git 清理):

git reflog                 # 看所有 HEAD 移动记录
git reset --hard HEAD@{2}  # 回到两步之前

git reflog 是 Git 的"后悔药”。 记住这个命令,能救很多次。


四、.gitignore:别把垃圾也提交

有些文件不该进版本库:

  • 编译产物(*.o、*.pyc、build/)
  • 依赖目录(node_modules/、venv/)
  • 密钥和密码(*.key、.env)← 这条最重要
  • 系统文件(.DS_Store、Thumbs.db)
  • 临时文件(*.log、*.tmp)

在项目根目录建 .gitignore:

# 编译产物
*.o
*.pyc
__pycache__/
build/
dist/

# 依赖
node_modules/
venv/
.venv/

# 密钥和配置(千万不能提交)
*.key
*.pem
.env
config.local.*

# 系统垃圾
.DS_Store
Thumbs.db

# 日志和临时
*.log
*.tmp

⚠️ 已经提交过密钥怎么办: git rm --cached 文件 只从 Git 移除,但历史里还在。 正确的做法是立刻把那个密钥作废、重新生成。 历史清理很麻烦,而且如果不 push 到公网还好,一旦推上去就当泄露处理。


五、连接远程仓库(GitHub / Gitee / 自建)

方式一:HTTPS + 令牌(简单)

git remote add origin https://github.com/用户名/仓库名.git
git push -u origin main

现在 GitHub 不支持密码,要用 Personal Access Token(PAT)当密码。

方式二:SSH(推荐,配一次永久免密)

复用 T3 的密钥:

# 看有没有现成的公钥
cat ~/.ssh/id_ed25519.pub

复制输出,粘到 GitHub → Settings → SSH and GPG keys → New SSH key。

验证:

ssh -T git@github.com
# 应该看到 "Hi 用户名! You've successfully authenticated..."

然后:

git remote add origin git@github.com:用户名/仓库名.git
git push -u origin main

四个远程命令

git remote -v              # 看当前配的远程地址
git push                   # 推上去
git pull                   # 拉下来(= fetch + merge)
git clone 地址             # 克隆一整个仓库

首次 push 要 -u(git push -u origin main),之后直接 git push。


六、分支:最小用法

分支 = 平行世界。 你可以在分支上乱改,不影响主分支。

日常只需要三个命令:

git branch                 # 看有哪些分支
git switch -c 新分支名     # 建并切过去
git switch main            # 切回主分支

合并:

git switch main
git merge 新分支名

新手先不学分支也完全没问题。 一个人写文档/小项目,直接在 main 上提交就够。 分支是"多人协作"和"做实验性改动"时才需要的。


七、一个完整的实战流程

假设你要管理一个文档项目。

# ===== 第一次 =====
mkdir 我的文档 && cd 我的文档
git init
git config user.name "张三"          # 只在仓库内有效
git config user.email "zhang@x.com"

# 建 .gitignore
cat > .gitignore << 'EOF'
*.log
*.tmp
.DS_Store
EOF

# 写第一个文件
echo "# 我的文档" > README.md

# 第一次提交
git add .
git status                    # 确认要提交什么
git commit -m "初始化项目"

# ===== 日常 =====
# 改文件
nano README.md

# 看改了什么
git status
git diff

# 提交
git add README.md
git commit -m "补充项目说明"

# 看历史
git log --oneline

这就是 90% 的日常用法。


八、四个真实场景

场景 1:改坏了,想退回

git status                    # 看哪个文件改了
git diff 那个文件              # 确认改了什么
git restore 那个文件           # 退回 ⚠️ 改动会丢

场景 2:提交了但信息写错了

git commit --amend -m "正确的说明"

只改最近一次,且还没 push 的情况。

场景 3:提交了不该提交的文件

# 如果刚提交、还没 push
git rm --cached 文件
git commit --amend -m "移除误提交的文件"

场景 4:想看某个文件的历史

git log --oneline -- 文件名
git log -p -- 文件名           # 带每次的改动内容

九、动手:五个练习

练习 1:建仓库并提交

mkdir -p /tmp/gitlab && cd /tmp/gitlab
git init
git config user.name "测试"
git config user.email "test@test.com"

echo "第一版" > a.txt
git add a.txt
git status
git commit -m "第一次提交"
git log --oneline

练习 2:改文件、看 diff、提交

echo "第二版" > a.txt
git diff                    # 看改动
git add a.txt
git diff --staged           # 看暂存的内容
git commit -m "改成第二版"
git log --oneline

练习 3:退回上一版

echo "第三版" > a.txt
cat a.txt                   # 第三版
git restore a.txt           # 退回
cat a.txt                   # 变回第二版

# 已经提交的退回
echo "第四版" > a.txt
git add a.txt && git commit -m "第四版"
git reset --hard HEAD~1     # ⚠️ 退回上次提交
cat a.txt                   # 第二版

练习 4:用 reflog 找回

git reflog                  # 看所有移动记录
git reset --hard HEAD@{1}   # 回到刚才那步
cat a.txt                   # 第四版回来了

这个练习很重要——亲手体验"删了还能救回来"。

练习 5:.gitignore 生效

echo "secret" > password.key
echo "*.key" > .gitignore
git status                  # password.key 不该出现
git add .
git commit -m "加 gitignore"

十、验证:你过关了吗

  • 会 git init / add / commit / status / log / diff
  • 知道暂存区是干什么的
  • 会写有意义的提交信息
  • 会用 git restore 退回未提交的改动
  • 会用 git reflog 找回误删的提交
  • 会写 .gitignore,知道密钥不能提交
  • 会 git remote add + git push

十一、不行怎么办

Q1:fatal: not a git repository 当前目录不是仓库。cd 到有 .git 的目录,或者先 git init。

Q2:Please tell me who you are 没配用户名邮箱:

git config --global user.name "名字"
git config --global user.email "邮箱"

Q3:git commit 时进了 vim,出不来 Esc 然后 :wq。预防:

git config --global core.editor nano

Q4:push 报 rejected (non-fast-forward) 远程有你本地没有的提交(常见于网页上直接改过)。先拉:

git pull --rebase
git push

Q5:push 要密码,输密码又不对 GitHub 已不支持账号密码。用 Personal Access Token 代替密码,或者改用 SSH(推荐)。

Q6:Permission denied (publickey) SSH 密钥没配好。见 T3 SSH 的排障部分,然后验证:

ssh -T git@github.com

Q7:提交了很大的文件,push 很慢

git rm --cached 大文件
echo "大文件" >> .gitignore
git commit -m "移除大文件"

但历史里还在,仓库依然大。要彻底清需要用 git filter-repo(高级话题,先不用碰)。

Q8:把整个项目搞乱了,想重来

ls -a                  # 确认有 .git
rm -rf .git            # ⚠️ 删掉所有历史
git init               # 重新开始

这会丢失全部历史。 确认不要了再动手。


十二、一句话总结

Git 解决的是"能退回",不是"能上传"。

日常 7 个命令:init / status / add / commit / log / diff / restore。

救命命令:git reflog。

.gitignore 第一条规矩:密钥永远不进仓库。


← 上一篇 T4|文件传输 下一篇 → T6|软件源:为什么装不上