使用checkout,reset,revert进行代码回滚

git reset和git revert都可以用于撤销已存在的commit,其中git reset可以细化到针对单个文件进行操作。

    首先, 一个Git仓库主要有三个重要的组成:工作目录,缓存区和提交历史,如图所示:

Main components of a git repository

1. git reset

git reset通常用来撤销对缓存区和工作目录的修改。用法如下:

(1)git reset <file>

        从缓存区移除特定的文件,但不改变工作目录。

(2)git reset

        重设缓存区,匹配最近的一次提交,工作目录不变。

(3)git reset --hard

        重设缓存区和工作目录,匹配最近的一次提交。除了取消缓存之外,--hard标记还会清除工作目录中所有未提交的更改,因此使用前确定你想扔掉你所有的本地开发。

(4)git reset <commit>

        将当前分支的末端移动到commit,将缓存区重设到这个commit,但不改变工作目录。

(5)git reset --hard <commit>

        将当前分支的末端移动到commit,并将缓存区和工作目录都重设到这个commit。

git reset命令会将HEAD指向你指定的commit,也就是说,可以直接通过git reset命令来移除你指定的commit之后的所有commit。例如,下面这两条命令让hotfix分支向后回退了两个commit:

git checkout hotfix

git reset HEAD~2

before git reset


after git reset

注意,hotfix分支现在最后的两个commit变成了悬挂提交,这意味着下次git进行垃圾回收的时候,这两个commit就会被删除。因此,如果你希望改变此git仓库的提交历史,你可以使用git reset命令。

除了在当前分支上操作,你还可以传入以下参数来更新缓存区和工作区:

--soft 缓存区和工作区都不会改变

--mixed 默认选项。缓存区和你指定的commit同步,工作区不发生改变。

--hard 缓存区和工作区都同步到你指定的commit

这些参数往往针对HEAD来使用。例如你add了某个你不想add的文件,这时可以运行git --mixed reset HEAD,此时暂存区被清空,而你的工作空间并没有改变。

或者你希望将最近的两个commit合并成为一个,此时你可以运行git --mixed reset HEAD~2,这样你的commit记录被改变,缓存区被清空,但工作空间没有改变,因此你可以重新add,再重新commit,这样两个commit记录就变成了一个。

另一方面,你希望完全放弃你没有提交的改动,你可以运行git reset --hard HEAD,这样你的缓存区和工作空间就被强行更新了。

针对已经提交到远程的commit,你希望reset到HEAD~1,此时运行:

(1)git reset HEAD~1 此时查看status,发现有待stage的文件,因为工作空间的文件与HEAD~1的文件不同,因此运行git checkout future2.txt即可。(或者最开始就运行:git reset --hard HEAD~1)

(2)然后执行强制推送:git push -f

git reset可以针对某个文件,此时reset命令会将你指定的文件加入到缓存区中(因此文件从HEAD状态变成了你指定的某个commit的状态)。

git reset
git status

可以看到,暂存区产生了一个变更,这是因为文件从HEAD的内容变成了HEAD~2的内容(逻辑上),实际上,工作区域不会发生改变。而产生Changes not staged for commit的原因是此时工作区的文件和HEAD~2的文件不相同。

git commit

将暂存区的内容commit并push之后,此时future2.txt文件内容就回退为了两个commit之前的版本,并且commit log都没有更改。此时查看status:

git status

发现future2.txt依旧待stage,这是因为git reset命令工作区不会发生改变,因此工作区的文件内容与HEAD下的文件内容不一致,此时运行:

git checkout future2.txt

来撤销所有的更改。再次查看status:

git status

并且此时future2的文件内容已经处于最新状态。

git reset总结:(1)git reset在提交级别上,可以撤销已有的commit,并且清除git log,适用于消除还未提交到远程的commit,或者是自己私有的分支,或者并不在意篡改commit log的情况。

(2)git reset针对单个文件时,工作区不会被改变,暂存区一定改变。并且不会清除git log,往往最后需要通过git checkout <file>来同步工作区。 --soft、--mixed 和 --hard 对文件层面的 git reset 毫无作用,因为缓存区中的文件一定会变化,而工作目录中的文件一定不变。


2. git revert

git revert命令可以通过指定commit id来对某个commit进行撤销,此命令会生成一个新的commit来执行撤销动作,不会修改过去已有的commit,这避免了Git丢失项目历史,这一点对你的版本历史和协作的可靠性来说是很重要的。git revert用法如下:

(1)git revert <commit>

        生成了一个新的提交,此提交用于撤销<commit>引入的修改。

例如,下面的命令会撤销HEAD前面的第二个commit:

git checkout hotfix

git revert HEAD~2

before revert
after revert

相比 git reset,它不会改变现在的提交历史。因此,git revert 可以用在公共分支上,git reset 应该用在私有分支上。你也可以把 git revert 当作撤销已经提交的更改,而 git reset HEAD 用来撤销没有提交的更改。


3. git checkout

git checkout这个命令有三个作用:检出文件,检出提交和检出分支。

(1)git checkout master

        回到master分支。

(2)git checkout <commit> <file>

        查看文件之前的版本。此时工作目录中下的<file>被替换为<commit>中的<file>,并将它加入缓存区。

(3)git checkout <commit>

        更新工作目录中的所有文件,使得和某个特定提交下的文件一致。此操作会使你处于HEAD分离的状态,因此是只读操作。

git checkout <commit>
git checkout <commit> <file>

git checkout命令除了用于常见的分支切换以外,还可以用于代码更改的撤销。例如:

当 future2.txt 存在还没有add的changes时,运行git checkout future2.txt 可以撤销future2.txt的更改

git checkout  HEAD~2 future2.txt 可以将当前的future2.txt恢复为HEAD~2的版本,此时工作区和暂存区都会改变。

总结:如果文件A修改了,你希望撤销这个修改,那么可以使用以下方案:

(1)修改还未加入暂存区(还没有add),直接运行:

         git checkout A

(2)修改已经加入了暂存区,但还没有commit:

         git reset HEAD A(修改暂存区)

         git checkout A(修改工作区)

(3)修改已经commit

         git reset HEAD~1(reset到前一个commit)

         git checkout A

参考:github.com/geeeeeeeeek/git-recipes/wiki/5.2-%E4%BB%A3%E7%A0%81%E5%9B%9E%E6%BB%9A%EF%BC%9AReset%E3%80%81Checkout%E3%80%81Revert-%E7%9A%84%E9%80%89%E6%8B%A9

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容