一、为什么需要理解 Git 状态?
很多开发人员日常使用 Git:
git add .
git commit
git pull
但是遇到问题:
-
修改代码想撤销;
-
add 后想取消;
-
commit 提错想回滚;
-
分支乱了想恢复;
-
本地和远端不一致;
经常不知道该用:
git checkout .
还是:
git reset --hard
还是:
git fetch
还是:
git pull
原因是:
Git 实际管理的是多个状态区域。
二、理解 Git 四个核心区域
Git 可以理解为:
git commit
暂存区 -----------------> 本地仓库
(Index) (Repository)
^
|
git add
^
|
工作区
(Working Tree)
本地仓库
|
|
git fetch
v
远程跟踪分支
(origin/master)
|
|
merge/rebase
v
本地分支
(master)
1. 工作区 Working Tree
就是你正在编辑的代码。
例如:
chrome/browser/foo.cc
修改:
xxx();
此时:
git status
看到:
modified: foo.cc
代码只存在工作区。
2. 暂存区 Index
执行:
git add foo.cc
代码进入暂存区。
表示:
下一次 commit 我要提交这个版本。
3. 本地仓库 Repository
执行:
git commit -m "fix xxx"
生成 commit。
例如:
A---B---C
4. 远程跟踪分支 origin/master
执行:
git fetch
Git 更新:
origin/master
它代表:
Git 当前知道的远端状态。
三、git status:查看当前状态
所有操作前:
先:
git status
例如:
On branch master
Changes not staged:
modified:
foo.cc
表示:
工作区修改。
如果:
Changes to be committed:
modified:
foo.cc
表示:
已经 git add。
如果:
nothing to commit
表示:
当前干净。
四、git diff:查看修改内容
查看工作区修改
git diff
例如:
+ new code
- old code
查看暂存区修改
git diff --cached
查看:
git add
后的内容。
五、git add:把修改放入暂存区
例如:
git add foo.cc
或者:
git add .
含义:
工作区
|
|
v
暂存区
注意:
add 不会提交。
六、git restore:撤销文件修改
新版 Git 推荐:
替代:
git checkout .
1. 恢复工作区
例如:
修改:
foo.cc
执行:
git restore foo.cc
效果:
工作区恢复到暂存区状态
全部恢复:
git restore .
七、git checkout .:旧版恢复方式
以前常用:
git checkout .
作用:
恢复工作区。
例如:
commit:
A---B---C
修改:
foo.cc
执行:
git checkout .
恢复:
A---B---C
但是:
它不能删除 commit。
例如:
A---B---C---D
D 已经提交。
执行:
git checkout .
没有效果。
八、git reset:移动 HEAD 和恢复状态
reset 是 Git 最重要命令。
形式:
git reset [模式] [目标]
三个模式:
soft
mixed
hard
九、git reset --soft
用途:
撤销 commit,但是保留修改。
例如:
A---B---C
^
错误commit
执行:
git reset --soft HEAD~1
结果:
A---B
但是:
修改仍然在暂存区。
适合:
-
commit message 写错;
-
想重新提交。
十、git reset --mixed(默认)
例如:
git reset HEAD~1
等价:
git reset --mixed HEAD~1
效果:
撤销 commit。
但是:
代码回到工作区。
结果:
commit:
A---B
working tree:
修改存在
适合:
想重新 add。
十一、git reset --hard
最强恢复。
执行:
git reset --hard
会恢复:
HEAD
+
Index
+
Working Tree
全部清空。
例如:
A---B---C
修改:
foo.cc
执行:
git reset --hard
恢复:
A---B---C
删除最后一次 commit
git reset --hard HEAD~1
例如:
A---B---C---D
变:
A---B---C
D 消失。
十二、git stash:临时保存修改
开发中经常:
正在改代码:
feature A
突然需要切分支。
可以:
git stash
保存。
恢复:
git stash pop
查看:
git stash list
十三、git clean:删除未跟踪文件
例如:
编译产生:
out/
tmp/
xxx.log
Git 不管理。
查看:
git clean -n
预览。
删除:
git clean -f
删除未跟踪文件。
十四、git branch:备份分支
危险操作前:
推荐:
git branch backup_before_reset
例如:
当前:
master
A---B---C---D
创建:
backup_before_reset
A---B---C---D
master
A---B---C---D
之后:
git reset --hard HEAD~1
即使后悔:
还有备份。
十五、git reflog:找回误删 commit
很多人以为:
git reset --hard
之后 commit 永久消失。
实际上:
Git 保存 HEAD 移动历史。
查看:
git reflog
例如:
HEAD@{0}: reset
HEAD@{1}: commit D
恢复:
git reset --hard HEAD@{1}
这是 Git 的后悔药。
十六、git fetch:只同步远端信息
这是很多人最容易误解的命令。
执行:
git fetch origin
不会:
-
修改代码;
-
合并分支;
-
改 HEAD。
只更新:
origin/master
例如:
远端:
A---B---C---D
本地:
A---B---C
fetch 后:
origin/master:
A---B---C---D
master:
A---B---C
十七、git merge:合并代码
例如:
master:
A---B
feature:
A---B---C
切回 master:
git merge feature
结果:
A---B---M
\
C
产生 merge commit。
十八、git rebase:重新整理历史
例如:
master:
A---B---C
feature:
A---B---D
rebase:
git rebase master
变:
A---B---C---D'
历史更线性。
十九、git pull:fetch + merge/rebase
默认:
git pull
等价:
git fetch
+
git merge
如果配置:
git pull --rebase
则:
fetch
+
rebase
二十、如何让本地完全和远端一致?
这是开发中最常见场景。
例如:
本地:
A---B---C---D
远端:
A---B---C---E
目标:
丢弃 D。
正确:
第一步
git fetch origin
得到:
origin/master
A---B---C---E
第二步
git reset --hard origin/master
结果:
master:
A---B---C---E
origin/master:
A---B---C---E
完全一致。
二十一、Chromium 大仓库实际使用建议
Chromium:
src/
chrome/
content/
third_party/
提交和回滚频繁。
场景1:刚改几个 cpp,发现错了
使用:
git restore .
场景2:已经 git add
使用:
git reset
取消 add。
如果全部不要:
git reset --hard
场景3:实验 commit 错了
先:
git branch backup_bad_commit
然后:
git reset --hard HEAD~1
场景4:分支完全乱掉
例如:
zero_132
A---B---C---D
origin/zero_132
A---B---C
执行:
git fetch origin
git reset --hard origin/zero_132
二十二、Git 常用恢复命令速查表
| 目的 | 命令 |
|---|---|
| 查看状态 | git status |
| 查看修改 | git diff |
| 加入暂存区 | git add |
| 提交 | git commit |
| 撤销文件修改 | git restore . |
| 旧版撤销 | git checkout . |
| 取消 add | git reset |
| 撤销commit保留代码 | git reset --soft HEAD~1 |
| 撤销commit代码不要 | git reset --hard HEAD~1 |
| 临时保存修改 | git stash |
| 删除未跟踪文件 | git clean -f |
| 同步远端状态 | git fetch |
| 拉取并合并 | git pull |
| 合并分支 | git merge |
| 整理历史 | git rebase |
| 查看历史移动 | git reflog |
| 完全同步远端 | git fetch + git reset --hard origin/xxx |
总结
Git 命令不要死记,要理解它操作哪个区域:
git restore
↓
恢复文件
git add
↓
工作区 → 暂存区
git commit
↓
暂存区 → 本地仓库
git fetch
↓
远端 → origin分支
git merge/rebase
↓
origin分支 → 本地分支
git reset
↓
移动HEAD,调整状态
最终记住:
-
restore 管文件
-
add 管暂存
-
commit 管历史
-
fetch 管远端状态
-
pull 管同步合并
-
reset 管回滚
-
reflog 管后悔
掌握这些命令,基本可以解决日常开发(包括 Chromium 大型项目开发)中绝大多数 Git 恢复、回滚、同步问题。