用Git进行版本控制(五)撤销更改

前言:
教程来源于Udacity的免费教程-用Git进行版本控制,这里仅是个人的笔记,参考使用。

image.png

git commit --amend:
可以更改最近的提交,比如你忘记提交了某个文件,或是你的commit说明写错了。想要进行修改,就需要使用amend.
git revert:
还原指定的commit,传入指定的SHA,就可以撤销在该commit中的修改。
git reset:
删除提交的commit.

更改最后一个 commit

你已经使用 git commit 命令提交了大量的 commit。现在,借助 --amend 选项,你可以更改最近的 commit。

$ git commit --amend
如果你的工作目录没有内容(也就是仓库中没有任何未 commit 的更改),那么运行 git commit --amend 将使你能够重新提供 commit 消息。代码编辑器将打开,并显示原始 commit 消息。只需纠正拼错的单词或重新表述即可!然后保存文件并关闭编辑器,以便采用新的 commit 消息。

image.png

更改了上一次合并的commit,会弹出vim编辑窗口,可以进行一些修改,并关闭退出。

向 commit 中添加忘记的文件
此外,git commit --amend 使你能够包含忘记包含的文件(或文件更改)。假设你更新了整个网站的导航链接颜色。commit 了该更改,并以为完事了。但是后来发现深藏在页面上的一个特殊导航链接没有新的颜色。你可以执行新的 commit 并更新该链接的颜色,但是这样就会出现两个 commit 执行完全相同的任务(更改链接颜色)。

相反,你可以修改最后一个 commit(更新所有其他链接颜色的 commit)以包含这个忘记的链接。要包含忘记的链接,只需:

编辑文件
保存文件
暂存文件
运行 git commit --amend
你对必要的 CSS 和/或 HTML 文件作出了更改,以便修正被遗忘的链接样式,然后保存所有被修改的文件,并使用 git add 暂存所有被修改的文件(就像要提交新的 commit 那样!),但是你可以运行 git commit --amend 来更新最近的 commit,而不是创建新的 commit。

git commit --amend会将新修改的内容一并提交commit.

还原 commit

什么是还原?
当你告诉 git 还原(revert) 具体的 commit 时,git 会执行和 commit 中的更改完全相反的更改。我们详细讲解下。假设 commit A 添加了一个字符,如果 git 还原 commit A,那么 git 将创建一个新的 commit,并删掉该字符。如果删掉了一个字符,那么还原该 commit 将把该内容添加回来!

上节课最后讲解了合并冲突,并通过将标题设为 Adventurous Quest 解决了该冲突。假设现在仓库中有个 commit 将标题改为 Quests & Crusades。

git revert 命令
现在我创建了一个包含一些更改的 commit,我可以使用 git revert 命令还原它

$ git revert <SHA-of-commit-to-revert>
因为最近的 commit 的 SHA 是 07212dc,要还原该 commit: 我需要运行 git revert 07212dc(随即弹出代码编辑器,以便编辑/确认提供的 commit 消息)

你看到 git revert 命令的输出结果是如何告诉我们它还原了什么吗?它输出了我要求它还原的 commit 的提交说明。同时值得注意的是,它创建了新的 commit。

image.png

按ESC,并输入:wq保存并退出vim,我们再回到资源编辑器里,比如我这里是Notepad++,发现字符串又恢复了,commit提交的内容被驳回。(创建新的commit)

revert 小结
总结下,git revert 命令用于还原之前创建的 commit:

$ git revert <SHA-of-commit-to-revert>
此命令:

将撤消目标 commit 所做出的更改
创建一个新的 commit 来记录这一更改

重置 commit

重置与还原

初看,重置(reset) 似乎和 还原(revert) 相似,但它们实际上差别很大。还原会创建一个新的 commit,并还原或撤消之前的 commit。但是重置会清除 commit!

⚠️ 重置很危险 ⚠️

一定要谨慎使用 git 的重置功能。这是少数几个可以从仓库中清除 commit 的命令。如果某个 commit 不再存在于仓库中,它所包含的内容也会消失。

为了减轻你的压力,澄清下,git 会在完全清除任何内容之前,持续跟踪大约 30 天。要调用这些内容,你需要使用 git reflog 命令。请参阅以下链接以了解详情:

相关 commit 引用
你已经知道可以使用 SHA、标签、分支和特殊的 HEAD 指针引用 commit。有时候这些并不足够,你可能需要引用相对于另一个 commit 的 commit。例如,有时候你需要告诉 git 调用当前 commit 的前一个 commit,或者是前两个 commit。我们可以使用特殊的“祖先引用”字符来告诉 git 这些相对引用。这些字符为:

^ – 表示父 commit
~ – 表示第一个父 commit
我们可以通过以下方式引用之前的 commit:

父 commit – 以下内容表示当前 commit 的父 commit
HEAD^
HEAD~
HEAD~1
祖父 commit – 以下内容表示当前 commit 的祖父 commit
HEAD^^
HEAD~2
曾祖父 commit – 以下内容表示当前 commit 的曾祖父 commit
HEAD^^^
HEAD~3

^ 和 ~ 的区别主要体现在通过合并而创建的 commit 中。合并 commit 具有两个父级。对于合并 commit,^ 引用用来表示第一个父 commit,而 ^2 表示第二个父 commit。第一个父 commit 是当你运行 git merge 时所处的分支,而第二个父 commit 是被合并的分支。

我们来看一个示例,这样更好理解。这是我的 git log 当前的显示结果:

* 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
* db7e87a Set page heading to "Quests & Crusades"
*   796ddb0 Merge branch 'heading-update'
|\  
| * 4c9749e (heading-update) Set page heading to "Crusade"
* | 0c5975a Set page heading to "Quest"
|/  
*   1a56a81 Merge branch 'sidebar'
|\  
| * f69811c (sidebar) Update sidebar with favorite movie
| * e6c65a6 Add new sidebar content
* | e014d91 (footer) Add links to social media
* | 209752a Improve site heading for SEO
* | 3772ab1 Set background color for page
|/  
* 5bfe5e7 Add starting HTML structure
* 6fa5f34 Add .gitignore file
* a879849 Add header to blog
* 94de470 Initial commit

我们来看看如何引用一些之前的 commit。因为 HEAD 指向 9ec05ca commit:

HEAD^ 是 db7e87a commit
HEAD~1 同样是 db7e87a commit
HEAD^^ 是 796ddb0 commit
HEAD~2 同样是 796ddb0 commit
HEAD^^^ 是 0c5975a commit
HEAD~3 同样是 0c5975a commit
HEAD^^^2 是 4c9749e commit(这是曾祖父的 (HEAD^^) 第二个父 commit (^2))
*HEAD^^^2 表示父commit,即向下数两个commit,而最后的2代表合并后的第二个分支,即被合并的分支,所以是heading-update分支的commit 4c9749e

哪一个 commit?
请使用此仓库回答以下练习问题:

* 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
* db7e87a Set page heading to "Quests & Crusades"
*   796ddb0 Merge branch 'heading-update'
|\  
| * 4c9749e (heading-update) Set page heading to "Crusade"
* | 0c5975a Set page heading to "Quest"
|/  
*   1a56a81 Merge branch 'sidebar'
|\  
| * f69811c (sidebar) Update sidebar with favorite movie
| * e6c65a6 Add new sidebar content
* | e014d91 (footer) Add links to social media
* | 209752a Improve site heading for SEO
* | 3772ab1 Set background color for page
|/  
* 5bfe5e7 Add starting HTML structure
* 6fa5f34 Add .gitignore file
* a879849 Add header to blog
* 94de470 Initial commit

*~ 表示第一个父 commit,数字(这里是 6)表示要往回数多少个父 commit。因此找到 HEAD 指向的 commit,并往回数六个 commit。
往回数6个父commit.

image.png

上道题答的不错,再试试这道题吧!对于相同的仓库,HEAD~4^2 引用的是哪个 commit?

HEAD~4 引用的是当前分支的第四个父 commit,然后 ^2 告诉我们它是合并 commit 的第二个父 commit(被合并的那个 commit !)

答案是:f69811c

*^ 和 ~ 的区别主要体现在通过合并而创建的 commit 中。合并 commit 具有两个父级。比如heading_update分支和master分支,通常我们是合并到master分支的,
合并后产生新的提交commit,该commit有两个父级。
^ 引用用来表示第一个父 commit,而 ^2 表示第二个父 commit。第一个父 commit 是当你运行 git merge 时所处的分支,而第二个父 commit 是被合并的分支。

所以第一个父级就是master(即要合并到的分支),而上面被合并的heading_update就是第二个分支了!所以答案是f69811c

git reset 命令
git reset 命令用来重置(清除)commit:

$ git reset <reference-to-commit>
可以用来:

将 HEAD 和当前分支指针移到目标 commit
清除 commit
将 commit 的更改移到暂存区
取消暂存 commit 的更改

git reset 的选项
git 根据所使用选项来判断是清除、暂存之前 commit 的更改,还是取消暂存之前 commit 的更改。这些选项包括:

--mixed
--soft
--hard

默认是--mixed参数

image.png

如上图:
我们现在的HEAD指向master分支,最近的commit是3,如果这时候我执行
git reset HEAD~1,结果取决于后面的参数

首先他们都会回到commit-a上,但对于commit-3的处理却不一样:

默认是--mixed ,当执行了reset后,commit-3会回到工作区当中,下次你执行
git add .
会再次添加到暂存区域当中。
--soft:
会将commit-3放到暂存区当中,你下次可以继续进行提交。
--hard:
会删除当前的commit.

💡 备份分支 💡
注意,使用 git reset 命令将清除当前分支上的 commit。因此,如果你想跟着操作接下来出现的所有重置操作,需要在当前 commit 上创建一个分支,以便用作备份。

在进行任何重置操作之前,我通常会在最近的 commit 上创建一个 backup 分支,因此如果出现错误,我可以返回这些 commit:

$ git branch backup

reset 的 --mixed 选项
我们来看看每个选项。

  • 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
  • db7e87a Set page heading to "Quests & Crusades"
  • 796ddb0 Merge branch 'heading-update'
    使用上述示例仓库,其中 HEAD 指向 9ec05ca 上的 master,运行 git reset --mixed HEAD^ 会把 commit 9ec05ca 中做出的更改移至工作目录中。

💡 回到正常状况💡
如果你在重置任何内容前创建了 backup 分支,那么你可以轻松地让 master 分支指向 backup 分支所指向的同一 commit。你只需:

从工作目录中删除未 commit 的更改
将 backup 合并到 master(这将导致快进合并并使 master 向上移到和 backup 一样的点)

git checkout -- index.html git merge backup

reset 的 --soft 选项
我们使用相同的几个 commit 并看看 --soft 选项的工作方式:

  • 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
  • db7e87a Set page heading to "Quests & Crusades"
  • 796ddb0 Merge branch 'heading-update'
    运行 git reset --soft HEAD^ 会把 commit 9ec05ca 中做出的更改直接移至暂存区。

reset 的 --hard 选项
最后再看看 --hard 选项(当然并非最不重要选项):

  • 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
  • db7e87a Set page heading to "Quests & Crusades"
  • 796ddb0 Merge branch 'heading-update'
    运行 git reset --hard HEAD^ 将清除 commit 9ec05ca 中做出的更改。

reset 小结
总结下,git reset 命令被用来清除 commit:

$ git reset <reference-to-commit>
它可以用来:

将 HEAD 和当前分支指针移到引用的 commit
使用 --hard 选项清除 commit
使用 --soft 选项将 commit 的更改移至暂存区
使用 --mixed 选项取消暂存已被 commit 的更改
我们通常会用到祖先引用来指代之前的 commit。祖先引用包含:

^ – 表示父 commit
~ – 表示第一个父 commit

嗯,到此为上,git基本使用的咖啡课程结束了,还需要在实际的项目中多实践才好,还是挺消耗时间的,现在坐在雕刻时光的咖啡馆里,今天没有开空调,太热了,车已经充完了电,该回去了,拖延了一些事儿,回去搞定!!!

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

推荐阅读更多精彩内容