您的位置:首页 > 其它

Git教程3——撤销更改

2015-09-22 09:26 411 查看
上一节中,我们学习了如何在代码仓库中记录版本。我们之所以不辞辛苦的记录,那只是为了,如果某一天项目进展失败至少还有可用的版本,并且我们还可以由此确定麻烦代码被引入的位置。

不过,保存下来的”安全可用”版本如果不能恢复那就一文不值了。接下来将要学习的是如何查看项目的先前状态,并恢复之,最后重置未提交的更改。


点击下载本节的代码仓库

如果你学习过前面的章节,那就不需要下载上面的代码仓库了。如果没有,直接下载并解压就可以继续了。

显示提交校验和(Display Commit Checksums)

首先快速预览一下仓库的提交历史。在命令行界面(或Git Bash中)切换到
my-git-repo
目录中,然后执行

git log --oneline


输出类似如下的信息:

1c310d2 Add navigation links
54650a3 Create blue and orange pages
b650e4b Create index page


Git仅仅输出了校验和的前7个字符(查看完整的校验和使用git log)。不过起始的几个字符足以用来唯一标识一次提交了。

查看老版本

使用
git checkout
命令,可以查看以前的快照内容。请确保将以下命令中的
54650a3
替换为你的第二次提交ID。

git checkout 54650a3


执行命令后,会输出很多关于
detached HEAD
状态的信息,暂时忽略这些。你只需要知道上面的命令将
my-git-repo
目录中内容变成了第二次快照的内容(参看上一章的基础知识)。

使用编辑器或者浏览器打开HTML文件验证我们在第三次提交时添加的链接已经消失了。此时
git log
命令不再显示第三次提交的信息了。在检出第二次提交后,我们的仓库历史看起来如下图(红色的圆圈代表当前的提交)。



查看更老的版本

让我们回溯到更久远的历史。注意将
b650e4b
替换成你的第一次提交ID。

git checkout b650e4b


现在,
blue.html
orange.html
文件都消失了,下面是git log的历史记录。



在上一章中,我说过Git被设计为从不舍弃任何提交记录。那么,我们的第二次和第三次提交哪儿去了?简单的
git status
命令可以告诉我们。它应该输出以下信息:

# Not currently on any branch.
nothing to commit (working directory clean)


将之与上一章的输出相比较:

# On branch master
nothing to commit (working directory clean)


上一章中我们所有的操作都发生在master分支,第二次和第三次提交也存在于该分支上。要获取我们所有的历史记录,仅仅需要检出该分支。现在仅仅只是对分支做简要的说明,然而有这些知识就足以让我们在各个提交之间切换了。下一章我们会详细讨论分支。

返回当前的版本

我们使用相同的
git checkout
命令来返回master分支。

git checkout master


该命令使得Git更新我们的工作目录来反映master分支的快照状态。它重新生成了
blue.html
orange.html
文件,并且更新了
index.html
的内容。我们已经回到了项目的当前状态,此时提交历史记录如下:



标记一个发布版本

假如现在这个实例网站项目是一个稳定版本。我们可以给最近的提交标记一个版本数字。

git tag -a v1.0 -m "Stable version of the website"


标记是软件项目的正式发本版本和一些重大的里程碑。方便开发者浏览和检出重要的版本。例如,现在我们可以使用v1.0标签替代随机ID来标识第三次提交。查看标记列表,不带参数执行
git tag
命令。

上面的命令中,
-a
选项使得Git创建一个带注释的标记,意味着我们可以记录我们的名字,日期,以及一个描述性的文字(通过
-m
选项指定)。使用这个标记,在我们进行一些疯狂的实验之后还能找到稳定的版本。

疯狂实验

现在我们可以随意的向示例网站中添加一些试验性的更改。创建文件
crazy.html
添加如下HTML.

<!DOCTYPE html>
<html lang="en">
<head>
<title>A Crazy Experiment</title>
<meta charset="utf-8" />
</head>
<body>
<h1>A Crazy Experiment</h1>
<p>We're trying out a <span style="color: #F0F">crazy</span>
<span style="color: #06C">experiment</span>!

<p><a href="index.html">Return to home page</a></p>
</body>
</html>


暂存并提交快照

照旧执行如下命令

git add crazy.html
git status
git commit -m "Add a crazzzy experiment"
git log


在通过
git commit -m
提交前,最好是使用
git status
确认你要提交的内容。这样可以防止无意中提交了不属于该快照的文件。

不出意料的话该次提交会出现在仓库的提交历史中。如果输出的信息太多,你可以通过Space键滚动查看或者键入q退出到命令行。

查看稳定的提交

让我们回到稳定版本。现在
v1.0
标记可以代替第三次的提交ID使用。

git checkout v1.0


在查看稳定版本后,我们决定舍弃该次的疯狂实验。但是,在我们撤销更改之前,我们需要回到主分支。如果不这样,那么所有的更新都将发生在一个不存在的分支上。正如下一章将要介绍的那样,绝不要在老版本上直接更改。

git checkout master
git log --oneline


此时我们的仓库历史记录类似如下:

514fbe7 Add a crazzzy experiment
1c310d2 Add navigation links 54650a3 Create blue and orange pages b650e4b Create index page


撤销已提交的更改

我们准备通过删除最近的提交来恢复到稳定的版本。在执行以下命令前,请确保将
514fbe7
替换成为你的疯狂实验提交ID。

git revert 514fbe7


该操作会弹出一个默认的提交信息
Revert "Add a crazy experiment"
…保持默认然后关闭文件即可。此时
crazy.html
文件已经消失,执行
git log --oneline
查看历史记录

506bb9b Revert "Add a crazzzy experiment"
514fbe7 Add a crazzzy experiment
1c310d2 Add navigation links 54650a3 Create blue and orange pages b650e4b Create index page


值得注意的是,Git没有删掉
crazzzy experiment
这次提交,而是根据此次提交进行相应的撤销,然后使用撤销后的内容进行一次新的提交。因此,我们的第五次提交和第三次提交代表了相同的快照内容,如下图。重申一次,Git不会丢失历史:第四次快照仍然可以访问,以备我们需要继续开发。



在使用
git revert
命令时,记得指定你需要撤销的提交——而不是你想要恢复到的稳定提交。最好是将该命令理解为”撤销该提交”而不是“恢复该版本”。

进行一次小型实验

接下来尝试一次小型的实验。创建
dummy.html
空白文件。然后在
index.html
中的“Navigation”中添加一个链接,如下:

<h2>Navigation</h2>
<ul>
<li style="color: #F90">
<a href="orange.html">The Orange Page</a>
</li>
<li style="color: #00F">
<a href="blue.html">The Blue Page</a>
</li>
<li>
<a href="dummy.html">The Dummy Page</a>
</li>
</ul>


在接下来的小节中,我们准备放弃该实验。由于
git revert
命令需要指定一个提交ID,因此我们不能使用前面讨论的方法。

撤销未提交的更改

在撤销之前,首先查看仓库的状态。

git status


我们有一个已跟踪的和一个未跟踪的文件需要更改。首先处理
index.html
:

git reset --hard


该命令将所有已跟踪文件恢复到最近提交的状态。注意
--hard
选项是必需的,否则
git reset
命令仅仅将index.html置为未跟踪状态,保留其中的内容。不过在两种情况下,
git reset
命令仅仅作用于工作目录和暂存区,因此我们的
git log
历史记录不变。

接下来,我们删除
dummy.html
。我们当然可以手动删除掉它,但是借助于Git来重置(reset)可以消除掉大型团队处理多个文件时可能会有的错误。运行以下命令:

git clean -f


这将删除掉所有未跟踪文件。在删除掉
dummy.html
后,
git status
会显示工作目录为
clean
状态,意味着我们的工作目录跟最近的提交匹配。

注意
git reset
git clean
命令都是作用于工作目录,而不是已提交的快照。跟
git revert
不同的是,这些命令会永久的撤销更改,所以使用之前请三思。

总结

正如我们在上一章中提到的,大部分的Git命令都是作用于Git仓库的三个主要组成部分:工作目录,暂存快照区,提交快照区。
git reset
的撤销动作作用于工作目录和暂存区,
git revert
则作用于已提交的快照。同理,
git status
git log
也是如此(
git status
作用于工作目录和暂存区,
git log
作用于提交区)。



我提到过,
git revert
不会删除一次提交,以备你再次访问。当然这只是git保留提交快照的一个原因,我们会看到,在多个开发者协同工作时删除一个提交会造成严重的后果。

本章同样介绍了如何使用
git checkout
在不同的提交和分支之间切换。加上分支,我们就完成了对git核心组件的讨论,并且分支的概念使得我们的工作流程更加优雅。下一章中,我们将会讨论分支的基本命令。

快速参考

git checkout <commit-id>
View a previous commit.
git tag -a <tag-name> -m "<description>"
Create an annotated tag pointing to the most recent commit.
git revert <commit-id>
Undo the specified commit by applying a new commit.
git reset --hard
Reset tracked files to match the most recent commit.
git clean -f
Remove untracked files.
git reset --hard / git clean -f
Permanently undo uncommitted changes.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: