git reset、checkout & revert 代码回滚

git reset 和 git checkout 即可以用于commit,也可以用于一个文件,而 revert只能用于commit

git revert:

撤销某次commit的修改,并且自动新建一个commit提交,git log中添加新的revert日志;revert只能作用于commit,不能用于文件
假设当前有3个commit,git log如下:

commit3:  add test3.c
commit2:  add test2.c
commit1:  add test1.c

执行 git revert HEAD~1之后,会提示提交信息,提交后git log如下:

commit4:  Reverts “test2.c”
commit3:  test3.c
commit2:  test2.c
commit1:  test1.c

执行完后,test2.c被删除了(因为commit2的修改就是添加 test2.c,所以 revert commit2 就是撤销此次修改,即删除添加的test2.c),revert后运行git status,无任何变化(因为已经自动commit了),其结果就是新的commit中有 test1.c 和 test3.c 两个文件,无 test2.c。

git checkout

三个作用: checking out files, checking out commits, and checking out branches.

checkout commits, 例如:

git checkout hotfix		// 切换到 hotfix 分支
git checkout HEAD~2		// checkout到两个commit之前, 执行 git status 你会发现: HEAD detached at b09ab7c
git checkout api.c		// 相当于撤销某个文件的修改

checkout commit 基本上只用于查看之前的某一次commit,千万别直接在 checkout commits 后直接修改,然后 add,然后再commit. 因为这样你在 这个branch 修改的东西会消失的。。。(如果想找回,见文章最后 git reflog 命令),相当于你在下图中 Non-existent Branch 上的代码都是临时滴,在分支切换后(切到别的分支,再切回来)就会消失(因为一个分支只有一个HEAD,就是Master指的那个),见图:
这里写图片描述

正确的做法是,在 checkout commit 之后,再马上新建一个branch,然后checkout到新建的 branch,再在新建的 branch上add commit就OK了(因为新的 branch 的 HEAD 就会指向你修改的代码了,而不是跟你那个Master抢同一个HEAD指针)。

It’s important to understand that branches are just pointers to commits.
例如执行 git branch crazy_experiment 如下图:
branch
To start adding commits to it, you need to select it with git checkout, and then use the standard git add and git commit commands

Remember that the HEAD is Git’s way of referring to the current snapshot. Internally, the git checkout command simply updates the HEAD to point to either the specified branch or commit. When it points to a branch, Git doesn’t complain, but when you check out a commit, it switches into a “detached HEAD” state.

see link: https://www.atlassian.com/git/tutorials/using-branches/git-checkout

git reset:

1 . 撤销某个文件的修改:

git reset 可以 unstage 某个文件(git add 的反操作)

例如:
use " git reset HEAD <file> ..." to unstage

git reset HEAD a.txt  # 操作后 a.txt 还的修改还在工作区,只是没有 stage 而已。
git checkout HEAD a.txt  # 继续撤销 a.txt 的修改,这样 a.txt 就跟 HEAD 的记录保持一致了。
git reset/checkout HEAD -- anyfilename  # 加上 -- 将后面参数当成文件名

2 . 撤销某次commit:

move the tip of a branch to a different commit; 回退到某次修改,根据 --mixed, --soft, --hard 选择是否提交修改(add & commit) ,git log中会"删除"回退版本的commit之后的日志
同样有3个commit,git log如下:

commit3:  add test3.c
commit2:  add test2.c
commit1:  add test1.c

执行 git reset HEAD~1 (默认–mixed)之后,再次看git log,如下:

commit2:  test2.c
commit1:  test1.c

执行完后,commit3的log信息被删除了;但是test3.c还在本地缓存区,运行git status,可以看见提示test3.c,可以用git add 包含该文件;

若执行git reset --hard HEAD~1,log为:

commit2:  test2.c
commit1:  test1.c

执行完后,test3.c被删除了,查看git status,无任何变化(因为暂存区,工作区全部用指定提交版本的目录树替换掉了)。

例如,执行

git checkout hotfix		// 切换到 hotfix 分支
git reset HEAD~2		// 回退到两个commit之前
git reset HEAD api.c	// 相当于撤销对某个文件的修改

before reset

after reset

其实reset命令有两种用法:

git reset HEAD~2 foo.py  // 针对某个文件的reset
git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]  // 针对某次commit的reset

第一种用法是不会重置引用的,即不会修改master文件。只是把某一次提交的文件放到暂存区(已经 git add 过的),而且没有 soft、mixed、hard等选项,因为该文件肯定是被 git add 过了的。

第二种用法会重置引用,并且根据参数不同决定是否覆盖暂存区和工作目录(但是都会影响提交记录):

--hard参数会将工作目录、暂存区(git add)和提交记录(git commit) 用 指定提交版本替换掉

--soft 参数只执行提交记录的操作, 不进行工作目录和暂存区的覆盖

--mixed或加参数(默认),覆盖暂存区和提交记录,但不覆盖工目录

这里写图片描述

These flags are often used with HEAD as the parameter. For instance, git reset --mixed HEAD has the affect of unstaging all changes, but leaves them in the working directory. On the other hand, if you want to completely throw away all your uncommitted changes, you would use git reset --hard HEAD. These are two of the most common uses of git reset.
Be careful when passing a commit other than HEAD to git reset, since this re-writes the current branch’s history.

**Remember: reset 最好只跟HEAD一块使用,而且是uncommitted changes **

Remember: Git reset will alter the existing commit history. For this reason, git revert should be used to undo changes on a public branch, and git reset should be reserved for undoing changes on a private branch.

You can also think of git revert as a tool for undoing committed changes, while git reset HEAD is for undoing uncommitted changes.

But But But…

如果你不听劝,还是将reset用于了其他commit,但执行完git reset后又反悔了,想重新回到rest之前的commit,但是此时git log已经找不到那个之前的commit的信息了怎么办?(因为 git reset 会覆盖提交记录,即 "删除"相应git log中的信息)

这时我们可以使用 git reflog 查看所有的变更记录,如下:

$ git reflog
22f8aae HEAD@{0}: pull: Merge made by the 'recursive' strategy.
4e79a0b HEAD@{1}: reset: moving to HEAD^
22f8aae HEAD@{2}: reset: moving to 22f8aae

此时恢复某次修改只需要执行:

git reset --hard 22f8aae

尊重原作,参考自:
http://www.open-open.com/lib/view/open1397013992747.html

http://blog.csdn.net/n289950578/article/details/24738427

https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting/commit-level-operations

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值