当前位置:   article > 正文

Git 的原理与使用(上)

Git 的原理与使用(上)

Git是一个分布式版本控制系统,它被广泛用于协作开发和管理软件项目。开发人员可以通过Git来跟踪文件的变化、协调工作、并管理项目的不同版本。

Git允许用户在不同的分支上开发新功能,然后合并这些分支并确保团队成员之间的工作协调一致。此外,Git还提供了强大的工具,如提交、合并、回滚等等。因此通过 Git,团队能够高效地管理项目并追踪代码的变化历史。

本文整理自博主日常编码实践中对Git的使用,包括Git的相关概念,基本操作等,希望能带给各位小伙伴们一个关于Git的清晰认识,快速上手。

目录

一、认识 Git

1.提出问题

2.如何解决:版本控制器

二、Git 安装

Linux-centos

Linux-ubuntu

Windows

三、Git 的初始化与配置

1.创建 Git 本地仓库

2.配置 Git

3.查看配置

4.删除配置

四、认识工作区、暂存区、版本库

1.添加文件--场景一

2.查看.git文件

3.添加文件--场景二

4.修改文件

5-版本回退 reset

6-撤销修改

情况一:对于工作区的代码,还没有add

情况二:已经add,但没有commit

情况三:已经add,并且也commit了

7-删除本地仓库中的文件

**小结


一、认识 Git

1.提出问题

不知道你在工作或学习时有没有遇到这样的情况:我们在编写各种文档时,为了防止文档丢失或更改失误,又或是希望在失误后能恢复到原来的版本,不得不复制一个原文档的副本,比如:

“报告-v1”

“报告-v2”

“报告-v3”

“报告-确定版”

“报告-最终版”

“报告-绝对是最终版本再改是狗”

...

每个版本内容各不相同,但最终往往会只有一份报告将为我们所用。而由于每份报告是迭代产出的,于是每次复制粘贴副本,产出的文件就越来越多。

文件多不是问题,问题是:随着版本数量的不断增多,你还能记得这些版本各自都做了哪些修改吗?

文档如此,我们写的项目代码时也是存在这个问题的。

2.如何解决:版本控制器

为了能够让我们更方便地管理不同版本的文件,便有了版本控制器

所谓版本控制器,可以简单地理解为“一个能让你了解到某个文件的历史版本以及发展过程的系统”。换句话说,版本控制器就是一个可以记录工程的每一次改动和版本迭代的一个管理系统,同时也支持多人协同作业。

目前最主流的版本控制器就是Git。Git可以控制电脑上所有格式的文件,例如doc、excel、dwg、dgn、rvt等等。而对于我们开发人员来说,Git最重要的就是可以帮助我们管理软件开发项目中的源代码文件。

有一点需要明确:所有的版本控制系统(Git也不例外)只能跟踪文本文件的改动,比如 txt 文件,网页,所有的程序代码等等。对于文本文件,它可以告诉你每次文件内容的改动情况,比如某文件在第5行加了一个单词“Linux”,在第8行删了一个单词“Windows”。

但图片、视频这类的二进制文件,虽然也能由版本控制系统管理,但是没法跟踪文件具体的变化信息的。版本控制系统只能把二进制文件的每次改动的结果串起来,只能知道某图片从100KB改成了120KB,但到底改了什么部分,它是并不知道、也没法知道的。


二、Git 安装

Git是开放源代码的代码托管工具,最早是在Linux下开发的,开始也只能应用于Linux平台,后面才慢慢地被移植到Windows下,现在,Git可以在Linux、Unix、Mac和 Windows这几大平台上正常运行了。

对于Git的安装,本文对Linux下的安装作简单介绍,其余系统不作过多说明,有需要的朋友可以自行搜索“Git安装教程”,选择与自身平台相适应的教程进行学习。

Linux-centos

以我的centos7.6为例,安装Git:

sudo yum install git -y

查看Git安装的版本:

git --version

Linux-ubuntu

以ubuntu20.04为例:

sudo apt-get install git -y

查看git安装的版本:

git --version

Windows

Windows下的安装可以看这个视频:

Windows下安装 git 和图形化界面工具

这份视频教程相对细致,且视频中还介绍了Git的UI程序小乌龟(TortoiseGit),UI界面操作Git对于初学者而言更加简洁方便,大家也可以看着下载。


三、Git 的初始化与配置

1.创建 Git 本地仓库

仓库是进行版本控制的文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来。只有仓库下的文件才能被Git追踪管理。

创建一个Git本地仓库对应的命令为:

 git init

注意命令要在文件目录下执行,如:

  1. [wyd@VM-4-13-centos ~]$ mkdir gitcode
  2. [wyd@VM-4-13-centos ~]$ cd gitcode
  3. [wyd@VM-4-13-centos gitcode]$ git init
  4. Initialized empty Git repository in /home/wyd/gitcode/.git/
  5. [wyd@VM-4-13-centos gitcode]$ ls -al
  6. total 12
  7. drwxrwxr-x 3 wyd wyd 4096 Dec 1 19:55 .
  8. drwx------ 10 wyd wyd 4096 Dec 1 19:55 ..
  9. drwxrwxr-x 7 wyd wyd 4096 Dec 1 19:55 .git

执行git init后我们发现,当前目录下多了一个.git的隐藏文件。

.git目录是Git用来跟踪管理仓库的。注意,千万不要手动修改这个目录里面的文件,否则改坏了,Git仓库也就随之被破坏了。

.git文件中包含了Git仓库的诸多细节:

  1. [wyd@VM-4-13-centos gitcode]$ tree .git
  2. .git
  3. |-- branches
  4. |-- config
  5. |-- description
  6. |-- HEAD
  7. |-- hooks
  8. | |-- applypatch-msg.sample
  9. | |-- commit-msg.sample
  10. | |-- post-update.sample
  11. | |-- pre-applypatch.sample
  12. | |-- pre-commit.sample
  13. | |-- prepare-commit-msg.sample
  14. | |-- pre-push.sample
  15. | |-- pre-rebase.sample
  16. | `-- update.sample
  17. |-- info
  18. | `-- exclude
  19. |-- objects
  20. | |-- info
  21. | `-- pack
  22. `-- refs
  23. |-- heads
  24. `-- tags
  25. 9 directories, 13 files

这些字段代表什么含义,我们将在后续对Git的深入学习中逐步接触。 

2.配置 Git

安装Git后首先要做的事情是配置你的用户名(user.name)和email地址(user.email),这是非常重要的一步。

配置命令为:

git config

注意,执行命令时必须要在仓库里(cd gitcode):

  1. git config [--global] user.name "YourName"
  2. git config [--global] user.email "email@example.com"
  3. # 把YourName改成你的昵称
  4. # 把email@example.com改成邮箱的格式,只要格式正确即可。

如:

  1. [wyd@VM-4-13-centos linux_gitcode]$ git config user.name "zhangsan"
  2. [wyd@VM-4-13-centos linux_gitcode]$ git config user.email "123456@qq.com"

其中,--global是一个可选项,如果使用了该选项,则表示这台机器上所有的Git仓库都会使用这个配置。

如果你希望在不同仓库中使用不同的name或e-mail,可以不加 --global 选项。 

3.查看配置

查看配置的命令为:

git config -l

git config -l命令用来列出Git的配置信息。运行该命令将显示当前仓库的Git配置项,包括用户信息、颜色设置、别名、远程仓库等等。通过git config -l可以查看当前Git仓库的所有配置项,帮助用户了解当前Git环境的设置和配置。

此外,用户还可以通过git config --global -l查看全局的Git配置项,该命令将列出全局的Git配置信息。

4.删除配置

删除配置的命令为:

  1. git config [--global] --unset user.name
  2. git config [--global] --unset user.email

如果 git conifg 的时候加了--global选项,那么删除的时候也要加上,否则是无法直接删掉 global 的配置的。


四、认识工作区、暂存区、版本库

如果直接将某个文件拷贝到 .git 文件的同级目录gitcode下,此时这个文件是不会被Git管理的。

事实上,.git 目录才是真正的Git版本库(即代码仓库)。

那么,是不是直接把文件拷贝到 .git 目录内就可以了呢?

答案是不行的,而且是万万不能这么做的!不允许在 .git 下手动进行任何修改,否则很可能导致整个本地仓库报废。我们自定义的文件,只能写在 gitcode 这个目录下。

而gitcode文件夹就是Git的工作区

(.git 文件虽然也被包括在 gitcode 文件夹中,但它并不属于工作区,而是版本库。)

  • 工作区:是在电脑上你要写代码或文件的目录。

  • 暂存区:英文叫stage或index。一般存放在目录下的index文件(.git/index)中,我们把暂存区有时也叫作索引(index)。

  • 版本库:又名仓库,英文名repository 。工作区有一个隐藏目录.git,它不算工作区,而是Git的版本库。这个版本库里面的所有文件都可以被Git管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”。

  • 本地仓库:local repogit commit 命令就是把暂存区内的修改提交到本地仓库中。

下面这个图展示了工作区、暂存区、版本库之间的关系:

  • 图中左侧为工作区,右侧为版本库。Git的版本库里存了很多东西,其中最重要的就是暂存区(stage)。

  • 在创建Git版本库时,Git会为我们自动创建一个唯一的master分支(),以及指向master的一个指针叫HEAD。(分支和HEAD的概念后面再说)

  • 当对工作区修改(或新增)的文件执行git add命令时,暂存区目录树的文件索引会被更新。

  • 当执行提交操作 git commit 时,master分支会做相应的更新,可以简单理解为暂存区的目录树才会被真正写到版本库中。【master是本地仓库中的主要分支,可以理解为提交到master中,才是提交x真正到了本地仓库。】

由上述描述我们便能得知:通过新建或粘贴进目录的文件,并不能称之为向仓库中新增文件,而只是在工作区新增了文件。必须要通过使用git add和 git commit命令才能将文件添加到仓库中进行管理。

1.添加文件--场景一

在包含.git的目录下新建一个ReadMe文件,我们可以git add命令将文件添加到暂存区

  • 添加一个或多个文件到暂存区:git add [file1] [file2] ...

  • 添加指定目录到暂存区,包括子目录:git add [dir]

  • 添加当前目录下的所有文件改动到暂存区:git add .

使用git commit命令将暂存区内容添加到本地仓库中:

  • 提交暂存区全部内容到本地仓库中:git commit -m "message"

  • 提交暂存区的指定文件到仓库区:git commit [file1] [file2] ... -m "message"

注意,git commit后面的-m选项要跟上描述本次提交的message,由用户自己填写。这部分内容不仅绝不能省略,而且还要好好描述,message是用来记录你的提交细节的,是给其他人看的。

例如:

  1. [wyd@VM-4-13-centos linux_gitcode]$ touch ReadMe
  2. # 在ReadMe文件中写入 hello world
  3. [wyd@VM-4-13-centos linux_gitcode]$ echo hello world > ReadMe
  4. [wyd@VM-4-13-centos linux_gitcode]$ cat ReadMe
  5. hello world
  6. # 将ReadMe的修改加入暂存区
  7. [wyd@VM-4-13-centos linux_gitcode]$ git add ReadMe
  8. # 将暂存区的内容提交到仓库
  9. [wyd@VM-4-13-centos linux_gitcode]$ git commit -m '提交第一个文件'
  10. [master (root-commit) 1853b26] 提交第一个文件
  11. 1 file changed, 1 insertion(+)
  12. create mode 100644 ReadMe

git commit命令执行成功后会告诉我们:1个文件被改动(也就是我们新添加的ReadMe文件),插入了1行内容(ReadMe有1行内容)。

我们还可以多次add不同的文件,而只commit一次便可以提交所有文件,是因为需要提交的文件是通通被add到暂存区中,然后一次性commit暂存区的所有修改。如:

  1. [wyd@VM-4-13-centos linux_gitcode]$ touch file1 file2 file3
  2. [wyd@VM-4-13-centos linux_gitcode]$ git add file1 file2 file3
  3. [wyd@VM-4-13-centos linux_gitcode]$ git commit -m '一次性提交3个文件'
  4. [master 68df79a] 一次性提交3个文件
  5. 3 files changed, 0 insertions(+), 0 deletions(-)
  6. create mode 100644 file1
  7. create mode 100644 file2
  8. create mode 100644 file3

截至目前,我们已经更够将代码直接提交至本地仓库了。

git log命令可以帮助我们查看历史提交记录: 

  1. [wyd@VM-4-13-centos linux_gitcode]$ git log
  2. commit 68df79a6f2a582fd8f390eaa947577b898bc2069
  3. Author: wyd <1256970054@qq.com>
  4. Date: Sun Dec 3 21:41:13 2023 +0800
  5. 一次性提交3个文件
  6. commit 1853b26b95891348de92982b34f3bdbdfa01e049
  7. Author: wyd <1256970054@qq.com>
  8. Date: Sun Dec 3 21:39:19 2023 +0800
  9. 提交第一个文件

该命令显示从最近到最远的提交日志,并且可以看到我们commit时的日志消息。

如果嫌输出信息太多,看得眼花缭乱的,可以试试加上--pretty=onelne参数:

git log --pretty=onelne

我们看到的一大串数字是每次提交的 commit id(版本号),Git 的 commit id 不是1,2,3……递增的数字,而是一个 SHA1 计算出来的一个非常大的数字,用十六进制表示。

2.查看.git文件

先来查看.git目录的结构:

  1. [wyd@VM-4-13-centos linux_gitcode]$ tree .git
  2. .git
  3. |-- branches
  4. |-- COMMIT_EDITMSG
  5. |-- config
  6. |-- description
  7. |-- HEAD
  8. |-- hooks
  9. | |-- applypatch-msg.sample
  10. | |-- commit-msg.sample
  11. | |-- post-update.sample
  12. | |-- pre-applypatch.sample
  13. | |-- pre-commit.sample
  14. | |-- prepare-commit-msg.sample
  15. | |-- pre-push.sample
  16. | |-- pre-rebase.sample
  17. | `-- update.sample
  18. |-- index
  19. |-- info
  20. | `-- exclude
  21. |-- logs
  22. | |-- HEAD
  23. | `-- refs
  24. | `-- heads
  25. | `-- master
  26. |-- objects
  27. | |-- 18
  28. | | `-- 53b26b95891348de92982b34f3bdbdfa01e049
  29. | |-- 25
  30. | | `-- 1f5c5b7c0b8937ee454e3c1ec6a26e92951bd5
  31. | |-- 3b
  32. | | `-- 18e512dba79e4c8300dd08aeb37f8e728b8dad
  33. | |-- 68
  34. | | `-- df79a6f2a582fd8f390eaa947577b898bc2069
  35. | |-- 82
  36. | | `-- a432cf4469d279b2ec65a226fbbb5c19fb56c9
  37. | |-- e6
  38. | | `-- 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
  39. | |-- info
  40. | `-- pack
  41. `-- refs
  42. |-- heads
  43. | `-- master
  44. `-- tags
  45. 18 directories, 24 files

其中:

1、index就是暂存区,add后的内容都是添加到这里的。

2、HEAD就是我们的默认指向master分支的指针。

  1. [wyd@VM-4-13-centos linux_gitcode]$ cat .git/HEAD
  2. ref: refs/heads/master

找到默认的master分支:

其中存放的一串ID其实就是当前最新的 commit id,可以理解为一个git对象。

3、objects为Git的对象库,里面包含了创建的各种版本库对象及内容。

当执行命令git add时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,就位于".git/objects"目录下。

查找object时要将分成2部分,其前2位是文件夹名称,后38位是文件名称。

比如上面查到的 68df79a6f2a582fd8f390eaa947577b898bc2069 ,即说明它位于 68 文件夹下。

找到这个文件之后,一般不能直接看到里面是什么,该类文件是经过sha(安全哈希算法)加密过的文件,好在我们可以使用git cat-file命令来查看版本库对象的内容:

  1. [wyd@VM-4-13-centos linux_gitcode]$ git cat-file -p 68df79a6f2a582fd8f390eaa947577b898bc2069
  2. tree 82a432cf4469d279b2ec65a226fbbb5c19fb56c9
  3. parent 1853b26b95891348de92982b34f3bdbdfa01e049
  4. author wyd <xxxxxxxxxx@qq.com> 1701610873 +0800
  5. committer wyd <xxxxxxxxxx@qq.com> 1701610873 +0800
  6. 一次性提交3个文件

其中,还有一行tree 82a432cf4469d279b2ec65a226fbbb5c19fb56c9,使用同样的方法查看:

  1. [wyd@VM-4-13-centos linux_gitcode]$ git cat-file -p 82a432cf4469d279b2ec65a226fbbb5c19fb56c9
  2. 100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad ReadMe
  3. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file1
  4. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file2
  5. 100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 file3

再看 ReadMe 对应的 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

  1. [wyd@VM-4-13-centos linux_gitcode]$ git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
  2. hello world
  3. # 这是我们对ReadMe做的修改!!被git记录了下来!!

每一次提交的修改都会被git以对象的方式记录下来。

总结一下,在本地的git仓库中,有几个文件或者目录很特殊

  • index:暂存区,git add后会更新该内容。

  • HEAD:默认指向master分支的一个指针。

  • refs/heads/master:文件里保存当前master分支的最新commit id(索引,对应的是git对象,对象被维护在objects中)。

  • objects:包含了创建的各种版本库对象及内容,可以简单理解为放了git维护的所有修改。

后面再学习过程中,最好能将常见的git操作与.git目录当中的结构内容变化对应起来,这样有利于我们理解git细节流程。

3.添加文件--场景二

学习到这里,我们已经清楚了如何向仓库中添加文件,并且对于工作区、暂存区、版本库也有了一定的认识。这里再展示一种添加文件的场景,能加深我们对工作区、暂存区、版本库的理解:

  1. tjfz@139-159-150-152:~/gitcodes touch file4 #1.新增file4文件
  2. tjfz@139-159-150-152:~/gitcodes git add file4 #2.将file4添加到暂存区
  3. tjfz@139-159-150-152:~/gitcodes touch file5 #3.新增file5文件
  4. tjfz@139-159-150-152:~/gitcodes git commit -m "add file" #4.提交修改
  5. [master 3d406co] add file
  6. 1 file changed, insertions(+), deletions(-)
  7. create mode 100644 file4

提交后发现打印了 1 file changed,0 insertions(+),0 deletions(-),意思是只有一个文件改变了,这时我们提出了疑问,不是新增了两个文件吗?

再来回忆下,git add file5,file5 就不在暂存区中维护,所以我们 commit 的时候其实只是把已经在暂存区的file4提交了,而遗漏了工作区的file5。

如何提交file5呢?很简单,再次addcommit即可。

4.修改文件

Git比其他版本控制系统设计得优秀,因为Git跟踪并管理的是修改,而非文件。

什么是修改?新增、删除、更改了某些字符都是修改。

objects存储的git对象记录的就是修改的工作区中的内容。

让我们将ReadMe文件进行一次修改:

  1. [wyd@VM-4-13-centos linux_gitcode]$ echo wonderful! > ReadMe
  2. [wyd@VM-4-13-centos linux_gitcode]$ cat ReadMe
  3. wonderful!

此时,仓库中的ReadMe和我们工作区的ReadMe是不同的,如何查看当前仓库的状态呢?

git status命令用于查看在上次提交之后是否有对文件进行再次修改。

  1. [wyd@VM-4-13-centos linux_gitcode]$ git status
  2. # On branch master
  3. # Changes not staged for commit:
  4. # (use "git add <file>..." to update what will be committed)
  5. # (use "git checkout -- <file>..." to discard changes in working directory)
  6. #
  7. # modified: ReadMe
  8. #
  9. no changes added to commit (use "git add" and/or "git commit -a")

上面的结果告诉我们,ReadMe被修改过了,但还没有完成添加与提交。

目前,我们只知道文件被修改了,如果能知道具体哪些地方被修改了,就更好了。此时可以用 git diff命令:

  1. [wyd@VM-4-13-centos linux_gitcode]$ git diff ReadMe
  2. diff --git a/ReadMe b/ReadMe
  3. index 3b18e51..af3b811 100644
  4. --- a/ReadMe
  5. +++ b/ReadMe
  6. @@ -1 +1 @@
  7. -hello world
  8. +wonderful!

git diff [file]命令用来显示暂存区工作区文件的差异,显示的格式正是Unix通用的diff格式。

再修改一下 ReadMe 文件:

  1. [wyd@VM-4-13-centos linux_gitcode]$ cat ReadMe
  2. wonderful!
  3. wonderful1!
  4. wonderful2!
  5. wonderful3!

git diff 一下,对比暂存区(之前add过的版本)和工作区(刚修改的版本)的ReadMe文件区别:

  1. [wyd@VM-4-13-centos linux_gitcode]$ git diff ReadMe
  2. diff --git a/ReadMe b/ReadMe
  3. index 3b18e51..6a2ca8c 100644
  4. --- a/ReadMe
  5. +++ b/ReadMe
  6. @@ -1 +1,5 @@
  7. -hello world
  8. +wonderful!
  9. +
  10. +wonderful1!
  11. +wonderful2!
  12. +wonderful3!

也可以使用git diff HEAD -- [file]命令来查看本地仓库和工作区文件的区别。

知道了对ReadMe做了什么修改后,再把它提交到本地仓库就放心多了。

  1. [wyd@VM-4-13-centos linux_gitcode]$ git add ReadMe
  2. [wyd@VM-4-13-centos linux_gitcode]$ git status
  3. # On branch master
  4. # Changes to be committed:
  5. # (use "git reset HEAD <file>..." to unstage)
  6. #
  7. # modified: ReadMe
  8. #

git add 之后,就没有看到上面 no changes added to commit (use "git add" and/or "git commit -a") 的消息了。接下来让我们继续 git commit 即可。

  1. [wyd@VM-4-13-centos linux_gitcode]$ git commit -m '提交修改后的文 件'
  2. [master 2d511b4] 提交修改后的文件
  3. 1 file changed, 5 insertions(+), 1 deletion(-)

5-版本回退 reset

Git能够管理文件的历史版本,这也是版本控制器重要的能力。

如果有一天你发现之前前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,那么这个时候,就需要版本回退的功能了。

执行git reset命令用于回退版本,可以指定退回某一次提交的版本。

“回退”本质是要将本地仓库中的内容进行回退,工作区或暂存区是否回退由命令参数决定。

git reset命令的语法格式为:git reset [--soft | --mixed | --hard] [HEAD]

  • --mixed 为默认选项,使用时可以不用带该参数。该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变。

  • --soft 参数对于工作区和暂存区的内容都不变,只是将本地仓库回退到某个指定版本。

  • --hard 参数将工作区和暂存区都退回到指定版本。

    • 切记工作区有未提交的代码时不要用这个命令,因为工作区也会回滚,你没有提交的代码就再也找不回了,所以使用该参数前一定要慎重。

  • HEAD参数说明:

    • 可直接写成commit id,表示指定退回的版本

    • HEAD表示当前版本

    • HEAD^上一个版本

    • HEAD^^上上一个版本

    • 以此类推……

  • 可以使用 ~数字 表示:

    • HEAD~0 表示当前版本

    • HEAD~1 上一个版本

    • HEAD^2 上上一个版本

    • 以此类推……

回退功能演示:

执行命令 git reset --hard 58d0aa3 后,可见工作区、暂存区和本地仓库的内容都回退到了第一版本的样子,HEAD指针也更改的指向,指向了第一版本的commitID58d0aa3。且 git log --pretty=oneline 打印日志可见,只剩下操作第一版本时的日志,中间添加各种file的日志也没有了。

如果后悔了,还想从第一版本58d0aa3恢复到回滚前的999cead版本呢?同样的操作,git reset --hard 999cead,工作区、暂存区和本地仓库都回滚到了原来版本999cead的样子。

可见,只有拿到某一版本的commitID,才能通过reset命令实现回滚操作。

但是上述情况下,我们能从第一版本回滚到原来版本,是因为我们在还在原来版本时就打印了一下log,知道了原来版本的commitID。如果我们没有打印过原来版本的commitID,不就不能从第一版本又回退到原来版本了呢?

也就是说,如果从一个新版本回退到旧版本,但后悔了,又想回到一个新版本,在旧版本时git log肯定是拿不到想要的新版本的commitID的,这时还有一个补救的方法:git reflog,该命令能记录到本地的每一次命令:

这样,你就可以很方便的找到你的所有操作记录了,但第一列的一串数字是啥东西?

这个也是各个版本的 commit id 的部分。没错,Git 版本回退的时候,也可以使用部分 commit id 来代表目标版本。

可往往理想很丰满,现实很骨感。在实际开发中,突然某一天,我又想回退到某个版本,可由于开发的时间长了,commit id早就找不到了,那该如何操作呢?貌似现在不可能了……

值得说的是,Git 的版本回退速度非常快,因为 Git 在内部有个指向当前分支(此处是master)的HEAD 指针, refs/heads/master文件里保存当前 master 分支的最新 commit id 。

当我们在回退版本的时候,Git 仅仅是给refs/heads/master 中更换一个存储的version(即commitID),可以简单理解成如下示意图:

6-撤销修改

如果我们在我们的工作区写了很长时间代码,越写越写不下去,觉得自己写的实在是垃圾,想恢复到上一个版本。

情况一:对于工作区的代码,还没有add

你当然可以直接删掉你目前在工作区新增的代码,像这样:

  1. # 向ReadMe中新增一行代码
  2. hyb@139-159-150-152:~/gitcode$ git status
  3. On branch master
  4. nothing to commit, working tree clean
  5. hyb@139-159-150-152:~/gitcode$ vim ReadMe
  6. hyb@139-159-150-152:~/gitcode$ cat ReadMe
  7. hello bit
  8. hello git
  9. hello world
  10. hello version1
  11. hello version2
  12. hello version3
  13. This piece of code is like shit #新增代码
  14. # 查看状态
  15. hyb@139-159-150-152:~/gitcode$ git status
  16. On branch master
  17. Changes not staged for commit:
  18. (use "git add <file>..." to update what will be committed)
  19. (use "git restore <file>..." to discard changes in working directory)
  20. modified: ReadMe
  21. no changes added to commit (use "git add" and/or "git commit -a")
  22. # 直接删除代码 恢复原来的样子
  23. hyb@139-159-150-152:~/gitcode$ vim ReadMe
  24. hyb@139-159-150-152:~/gitcode$ cat ReadMe
  25. hello bit
  26. hello git
  27. hello world
  28. hello version1
  29. hello version2
  30. hello version3
  31. hyb@139-159-150-152:~/gitcode$ git status
  32. On branch master
  33. nothing to commit, working tree clean

辛亏我们工作效率不高,才写了一行代码就发现不行了,要是你写了3天,一直都没有提交,该怎么删掉呢?你自己都忘了自己新增过哪些。

有同学说,我可以 git diff xxx 一下,看看差别在删啊,那你肯定又要花3天时间删代码了,并且很大的概率还会改出bug。一周过去了,你怎么向你的老板交代呢?

Git 其实还为我们提供了更好的方式,我们可以使用git checkout -- [file]命令让工作区的文件回到最近一次 add 或 commit 时的状态。

要注意 git checkout -- [file] 命令中的--很重要,切记不要省略,一旦省略,该命令就变为其他意思了,后面我们再说。示例如下:

情况二:已经add,但没有commit

如果已经给代码执行了add,保存到了暂存区,该怎么撤销呢?

让我们来回忆一下学过的 reset 回退命令:

该命令如果使用 --mixed 参数,可以将暂存区的内容退回为指定版本的本地仓库的内容,但工作区文件保持不变。这就达成了回退暂存区的效果,并且把当前的情况二转换成了上面的情况一,此时再要回退工作区使工作区的内容和暂存区一致,使用 git checkout -- ReadMe 命令即可。(当然,要完成工作区和暂存区的同时回退,也可以直接使用 --hard 选项,这样只需要一行代码,这里不做演示。)

示例如下:

注意:git reset HEAD 就是回到当前版本的意思(如果要回到上一版本,写作HEAD^)

git status查看一下,发现现在暂存区是干净的,只有工作区有修改。

丢弃工作区的修改:

恢复了!

情况三:已经add,并且也commit了

不要担心,我们可以 git reset --hard HEAD^回退到上一个版本。

  • --hard:同时将本地仓库、工作区、暂存区都回退到上一版本。

  • HEAD^:上一版本的写法。

不过,前提条件是你还没有把自己的本地仓库push到远程仓库。

事实上,撤销的目的就是让本地仓库的代码不影响远程仓库的代码。

还记得Git是分布式版本控制系统吗?我们后面会讲到远程版本库,一旦你推送到远程版本库,你就真的惨了……

准备工作:add、commit

回退操作:将本地仓库内容回退到上一版本,且同步至工作区、暂存区。

7-删除本地仓库中的文件

在Git中,删除也是一个修改操作。

如果要删除本地仓库中的文件,怎么操作呢?

方法一:先在工作区中正常 rm file5,然后把工作区删除操作add file5到暂存区、commit到本地仓库。

在工作区中的修改(修改也包括删除操作)add到暂存区中后,暂存区会提示 file5 被删除,再 commit的时候这个删除的操作和结果也会被同步到本地仓库。

方法二:git rm file 命令直接将 file 从工作区和暂存区中一同删除,然后直接 commit 到本地仓库。


**小结

本篇涉及的部分git命令:

git init:初始化git仓库

git config:配置git配置项

git config -l:查看配置项

git config --unset:删除配置项

git add:添加工作区的内容到暂存区

git commit:提交暂存区中的内容到版本库

git log:查看历史提交记录

git cat-file:查看版本库对象的内容

git status:查看仓库状态

git diff:显示文件差异

git reset:版本回退

**下篇内容

Git 的原理与使用(中)

五、分支管理

六、远程操作

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/680612
推荐阅读
相关标签
  

闽ICP备14008679号