跟着之前的教程,我相信你已经熟练掌握了如何修改文件并提交这些修改到Git版本库中。接下来,我们再次练习一下这个过程。首先,我们要修改readme.txt
文件,使其内容如下:
Git is a distributed version control system.
Git is free software distributed under the GPL.
完成修改后,我们将这些更改提交到Git版本库中:
$ git add readme.txt
$ git commit -m "append GPL"
[master 1094adb] append GPL
1 file changed, 1 insertion(+), 1 deletion(-)
每当你对文件进行了一系列的修改,并认为这些修改达到了一个可以保存的状态时,你可以使用git add
命令将这些修改添加到暂存区,然后使用git commit
命令将这些修改提交到Git版本库中。这就像是在游戏中每通过一个关卡就保存一次进度,或者在打Boss前手动存档,以便在失败时能够从最近的保存点重新开始。
现在,让我们回顾一下readme.txt
文件的提交历史:
版本1:wrote a readme file
Git is a version control system.
Git is free software.
版本2:add distributed
Git is a distributed version control system.
Git is free software.
版本3:append GPL
Git is a distributed version control system.
Git is free software distributed under the GPL.
当然,对于一个包含数千行的文件,我们很难记住每次提交都做了哪些更改。这正是版本控制系统发挥作用的地方。在Git中,我们可以使用git log
命令来查看提交历史记录:
$ git log
commit 1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master)
Author: LiHua <example@mail.com>
Date: Fri April 4 21:06:15 2024 +0800
append GPL
commit e475afc93c209a690c39c13a46716e8fa000c366
Author: LiHua <example@mail.com>
Date: Fri April 4 21:03:36 2024 +0800
add distributed
commit eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
Author: LiHua <example@mail.com>
Date: Fri April 4 20:59:18 2024 +0800
wrote a readme file
通过git log
命令,我们可以看到从最近到最远的提交日志。在这个例子中,我们可以看到三次提交,最近的一次是“append GPL”,上一次是“add distributed”,而最早的一次是“wrote a readme file”。
如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=oneline
参数:
$ git log --pretty=oneline
1094adb7b9b3807259d8cb349e7df1d4d6477073 (HEAD -> master) append GPL
e475afc93c209a690c39c13a46716e8fa000c366 add distributed
eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0 wrote a readme file
友情提示一下,你所看到的那串如“1094adb…”的数字是commit id(版本号)。与SVN不同,Git的commit id并不是像1、2、3这样递增的数字。它是一个通过SHA1算法计算得出的非常大的数字,以十六进制的形式表示。你看到的commit id与我所看到的肯定是不同的,每个人的commit id都是唯一的。
为什么commit id需要使用这么一大串数字来表示呢?这主要是因为Git是一个分布式的版本控制系统。在后续的学习中,我们将研究多人在同一个版本库中协同工作的情况。如果大家都使用1、2、3这样的数字作为版本号,那么很容易就会发生版本冲突。而使用SHA1算法生成的这一大串数字作为commit id,可以确保在全球范围内都是唯一的,从而避免了版本冲突的问题。这样的设计使得Git成为一个强大且灵活的版本控制系统。
好的,现在我们将启动时光穿梭机,回退到readme.txt
的上一个版本,也就是“add distributed”的那个版本。在Git中,HEAD
表示当前版本,即最新的提交。因此,上一个版本可以通过HEAD^
来表示,上上一个版本是HEAD^^
,依此类推。当然,如果我们要回退100个版本,写100个^
显然不太现实,所以Git提供了HEAD~100
这样的简写。
要回退到上一个版本,我们可以使用git reset
命令。例如:
$ git reset --hard HEAD^
这条命令会将当前版本(即“append GPL”版本)回退到上一个版本(即“add distributed”版本)。--hard
参数的作用是丢弃当前版本的所有更改,直接回退到指定版本。这意味着所有未提交的改动都将丢失,所以在使用时要特别小心。
现在,我们可以检查readme.txt
的内容,确认是否回退到了正确的版本:
$ cat readme.txt
输出应该是:
Git is a distributed version control system.
Git is free software.
果然,内容被还原到了“add distributed”版本。
但是,如果我们想继续回退到更早的“wrote a readme file”版本,我们应该怎么做呢?在回退之前,让我们先用git log
命令查看一下当前版本库的状态:
$ git log
输出会显示所有提交的历史记录。找到你想要回退到的版本的commit id(例如eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
),然后使用git reset
命令回退到该版本:
$ git reset --hard eaadf4e385e865d25c48e7ca9c8395c3f7dfaef0
或者,如果你只记得commit id的前几位,你也可以使用这些前几位数字来指定要回退到的版本。Git会尝试找到与这些数字匹配的最近的commit id。
现在,如果你再次查看readme.txt
的内容,你会看到它已经回退到了“wrote a readme file”版本的内容。
需要注意的是,一旦使用git reset --hard
命令回退到某个版本,之前的提交记录将不再可见(除非你还没有关闭命令行窗口,并且还能够找到之前的commit id)。这意味着如果你不小心回退到了一个错误的版本,并且没有记录下之前的commit id,那么你可能无法再找回之前的版本了。因此,在使用git reset
命令时,一定要小心谨慎。
Git的版本回退速度非常快,因为Git在内部有个指向当前版本的HEAD
指针,当你回退版本的时候,Git仅仅是把HEAD从指向append GPL
:
┌────┐
│HEAD│
└────┘
│
└──▶ ○ append GPL
│
○ add distributed
│
○ wrote a readme file
改为指向add distributed
:
┌────┐
│HEAD│
└────┘
│
│ ○ append GPL
│ │
└──▶ ○ add distributed
│
○ wrote a readme file
然后顺便把工作区的文件更新了。所以你让HEAD
指向哪个版本号,你就把当前版本定位在哪。
如果你不小心回退到了一个版本并关掉了电脑,然后后悔想要恢复到新版本,但又找不到新版本的commit id,这时不必过于焦虑。在Git中,你总是有机会恢复到之前的状态。
Git提供了一个非常有用的命令git reflog
,它会记录你的每一次命令操作,包括你回退版本的操作。通过git reflog
,你可以找到之前版本的commit id,然后再次使用git reset
命令恢复到那个版本。
执行git reflog
命令后,你会看到类似以下的输出:
e475afc HEAD@{1}: reset: moving to HEAD^
1094adb (HEAD -> master) HEAD@{2}: commit: append GPL
e475afc HEAD@{3}: commit: add distributed
eaadf4e HEAD@{4}: commit (initial): wrote a readme file
这个输出显示了你的提交历史,包括每次提交的commit id和对应的操作描述。从输出中,你可以看到“append GPL”的commit id是1094adb
。现在,你可以使用这个commit id来恢复到那个版本:
$ git reset --hard 1094adb
因此,即使你关闭了电脑,也不必担心无法恢复到之前的版本。只要你还记得大致的操作顺序,git reflog
命令就能帮助你找到正确的commit id,并让你乘坐“时光机”回到过去。