Git 重置
1 版本库回退
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git status -s
M demo.txt
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat .git/refs/heads/master
ee76d8a1bd776d7042c7054e5abf180b371550cf
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git commit -am "new commit"
[master adf3af7] new commit
1 file changed, 1 insertion(+)
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat .git/refs/heads/master
adf3af7077fe75b98167fbbc26bb8cfcd05eaf5d
[root@izwz9f5nsv33jsmjcx0qw1z demo]#
由上面的命令和结果可以看出,当有新的提交发生时,master 分支对应的引用文件中的内容就会变成最新的提交 ID。且我们可以通过 git reset
命令,人为的改变引用的提交 ID。
引用 refs/heads/master
就好像是一个游标,一般这个游标都指向最新提交。
git reset --hard HEAD^
注意 --hard
参数会破坏工作区未提交的改动,慎用! HEAD^ 也可以是某次提交 ID
reset
命令很危险,因为执行后会彻底丢弃历史,且无法恢复。这里的无法恢复是指通过git log
查看不到之前的提交记录,其实通过下面的reflog
还是可以恢复的。
2 reflog 挽救错误的重置
.git/log/regs/heads/
目录下的日志记录文件记录了分支的变更,例如:
[root@izwz9f5nsv33jsmjcx0qw1z demo]# tail .git/logs/refs/heads/master
为了排版就不贴结果了
使用 Git 为我们提供的命令更直观更方便。例如:
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git reflog show master
adf3af7 master@{0}: commit: new commit
ee76d8a master@{1}: reset: moving to HEAD^
69d6d43 master@{2}: commit: 提交中文测试
ee76d8a master@{3}: reset: moving to HEAD^^
d748b3a master@{4}: commit: 提交中文测试
9938bca master@{5}: commit: <D0><C2><C4><DA><C8><DD><C8><DD><CC>ύ
ee76d8a master@{6}: commit: inset qwe
f325ad0 master@{7}: commit (amend): Initial demo666
9bd630b master@{8}: commit (initial): Initial demo
上面两条命令的结果都可以看到 master 分支指向的变迁。通过这些日志我们就可以恢复我们的误操作。
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat demo.txt
123
qwe
123
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git reset --hard master@{2}
HEAD is now at 69d6d43 提交中文测试
[root@izwz9f5nsv33jsmjcx0qw1z demo]# cat demo.txt
123
qwe
中文测试
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git log --oneline -10
69d6d43 提交中文测试
ee76d8a inset qwe
f325ad0 Initial demo666
[root@izwz9f5nsv33jsmjcx0qw1z demo]#
上面 git reset --hard master@{2}
让我们恢复了重置操作。而且看到提交内容和日志也恢复了。这个时候再来看日志记录
[root@izwz9f5nsv33jsmjcx0qw1z demo]# git reflog show master
69d6d43 master@{0}: reset: moving to master@{2}
adf3af7 master@{1}: commit: new commit
ee76d8a master@{2}: reset: moving to HEAD^
69d6d43 master@{3}: commit: 提交中文测试
ee76d8a master@{4}: reset: moving to HEAD^^
d748b3a master@{5}: commit: 提交中文测试
9938bca master@{6}: commit: <D0><C2><C4><DA><C8><DD><C8><DD><CC>ύ
ee76d8a master@{7}: commit: inset qwe
f325ad0 master@{8}: commit (amend): Initial demo666
9bd630b master@{9}: commit (initial): Initial demo
可以发现,我们恢复操作也被记录在日志文件中。
3 Git reset 操作
git reset [-q] [<tree-ish>] [--] <paths>...
git reset (--patch | -p) [<tree-sh>] [--] [<paths>...]
git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]
reset
命令常用的三种操作方式,但是《Git 权威指南》书上只解释了第一种和第三种。
第一种用法(包含了路径 <paths>
的用法)不会重置引用,不会改变工作区,而是用指定提交 ID 下的文件替换掉暂存区中的文件,例如 git reset HEAD <paths>
相当于取消之前执行 git add <paths>
命令时改变的暂存区。
第三种用法(不使用路径 <paths>
的用法)则会重置引用,根据参数可以对暂存区或工作区进行重置。例如:
-
使用参数
--hard
,如:git reset --hard <commit>
。会执行图上所有动作。- 1.替换引用指向,引用指向新的提交 ID。
- 2.替换暂存区,使用上一步所指向的提交 ID 对应的目录树替换暂存区的目录树
- 3.替换工作区,使用刚被替换的暂存区目录树替换工作区
-
使用参数
--soft
,如:git reset --soft <commit>
。只会指向 1 操作,即只更改引用指向。不替换目录树。 -
使用参数
--mixed
或者不加参数(此参数为默认参数) ,如:git reset <commit>
。会执行 1、2 动作。即更改引用的指向及重置暂存区,但不改变工作区。 -
命令
git reset
和git reset HEAD
效果一样,因为不指定commitID
,默认的就是 HEAD 对应的提交 ID。此命令将 HEAD 对应的目录树替换暂存区的目录树。 -
命令
git reset --soft HEAD^
俗称软回滚 ,工作区和暂存区都不改变,但是引用向前回退一次。当对提交的说明或者提交的更改不满意时,用此撤销提交,以便重新提交。- 前面有个修补提交的命令
git commit --amend
此修补命令相当于执行了下面两条命令: git reset --soft HEAD^
git commit -e -F .git/COMMIT_EDITMSG
。 .git/COMMIT_EDITMSG
保存了上次的提交日志。
- 前面有个修补提交的命令
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于