需求一: 如何把 stage 中的修改还原到 work dir 中
这个需求很常见, 也很重要, 比如我先将当前 work dir 中的修改添加到 stage 中, 然后又对 work dir 中的文件进行了修改, 但是又后悔了, 如何把 work dir 中的全部或部分文件还原成 stage 中的样子呢?
来个实际场景, 我先新建两个文件, 然后把他们都加到 stage:
- $ touch a.txt b.txt
- $ Git add .
- $ Git status
- On branch master
- Changes to be committed:
- new file: a.txt
- new file: b.txt
然后我又修改了 a.txt 文件:
- $ echo hello world>> a.txt
- $ Git status
- On branch master
- Changes to be committed:
- new file: a.txt
- new file: b.txt
- Changes not staged for commit:
- modified: a.txt
现在, 我后悔了, 我认为不应该修改 a.txt, 我想把它还原成 stage 中的空文件, 怎么办?
答案是, 使用 checkout 命令:
- $ Git checkout a.txt
- Updated 1 path from the index
- $ Git status
- On branch master
- Changes to be committed:
- new file: a.txt
- new file: b.txt
看到了么, 输出显示从 index 区 (也就是 stage 区) 更新了一个文件, 也就是把 work dir 中 a.txt 文件还原成了 stage 中的状态(一个空文件).
当然, 如果 work dir 中被修改的文件很多, 可以使用通配符全部恢复成 stage:
$ Git checkout .
有一点需要指出的是, checkout 命令只会把被「修改」的文件恢复成 stage 的状态, 如果 work dir 中新增了新文件, 你使用 Git checkout . 是不会删除新文件的.
需求二: 比如说 commit 完之后, 突然发现一些错别字需要修改, 又不想为改几个错别字而新开一个 commit 到 history 区
那么就可以使用下面这个命令:
$ Git commit --amend
这样就是把错别字的修改和之前的那个 commit 中的修改合并, 作为一个 commit 提交到 history 区.
需求三: 将 history 区的文件还原到 stage 区
这个需求很常见, 比如说我用了一个 Git add . 一股脑把所有修改加入 stage, 但是突然想起来文件 a.txt 中的代码我还没写完, 不应该把它 commit 到 history 区, 所以我得把它从 stage 中撤销, 等后面我写完了再提交.
- $ echo aaa>> a.txt; echo bbb>> b.txt;
- $ Git add .
- $ Git status
- On branch master
- Changes to be committed:
- modified: a.txt
- modified: b.txt
如何把 a.txt 从 stage 区还原出来呢? 可以使用 Git reset 命令:
- $ Git reset a.txt
- $ Git status
- On branch master
- Changes to be committed:
- modified: b.txt
- Changes not staged for commit:
- modified: a.txt
你看, 这样就可以把 a.txt 文件从 stage 区移出, 这时候进行 Git commit 相关的操作就不会把这个文件一起提交到 history 区了.
上面的这个命令是一个简写, 实际上 reset 命令的完整写法如下:
$ Git reset --mixed HEAD a.txt
其中, mixed 是一个模式 (mode) 参数, 如果 reset 省略这个选项的话默认是 mixed 模式; HEAD 指定了一个历史提交的 hash 值; a.txt 指定了一个或者多个文件.
该命令的自然语言描述是: 不改变 work dir 中的任何数据, 将 stage 区域中的 a.txt 文件还原成 HEAD 指向的 commit history 中的样子. 就相当于把对 a.txt 的修改从 stage 区撤销, 但依然保存在 work dir 中, 变为 unstage 的状态.
需求四: 将 work dir 中的修改提交到 history 区
这个需求很简单, 先 Git add 然后 Git commit 就行了, 或者一个快捷方法是使用命令 Git commit -a.
需求五: 将 history 区的历史提交还原到 work dir 中
这个场景, 我说一个极端一点的例子: 比如我从 GitHub 上 clone 了一个项目, 然后乱改了一通代码, 结果发现我写的代码根本跑不通, 于是后悔了, 干脆不改了, 我想恢复成最初的模样, 怎么办?
依然是使用 checkout 命令, 但是和之前的使用方式有一些不同:
- $ Git checkout HEAD .
- Updated 12 paths from d480c4f
这样, work dir 和 stage 中所有的「修改」都会被撤销, 恢复成 HEAD 指向的那个 history commit.
注意, 类似之前通过 stage 恢复 work dir 的 checkout 命令, 这里撤销的也只是修改, 新增的文件不会被撤销.
当然, 只要找到任意一个 commit 的 HASH 值, checkout 命令可就以将文件恢复成任一个 history commit 中的样子:
- $ Git checkout 2bdf04a some_test.go
- Updated 1 path from 2bdf04a
- # 前文的用法显示 update from index
比如, 我改了某个测试文件, 结果发现测试跑不过了, 所以就把该文件恢复到了它能跑过的那个历史版本......
需求六: 由于 HEAD 指针的回退, 导致有的 commit 在 Git log 命令中无法看到, 怎么得到它们的 Hash 值呢?
只要你不乱动本地的. Git 文件夹, 任何修改只要提交到 commit history 中, 都永远不会丢失, 看不到某些 commit 只是因为它们不是我们当前 HEAD 位置的「历史」提交, 我们可以使用如下命令查看操作记录:
$ Git reflog
比如 reset,checkout 等等关键操作都会在这里留下记录, 所有 commit 的 Hash 值都能在这里找到, 所以如果你发现有哪个 commit 突然找不到了, 一定都可以在这里找到.
来源: https://www.cnblogs.com/kyoner/p/13343163.html