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

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

[wyd@VM-4-13-centos ~]$ mkdir gitcode
[wyd@VM-4-13-centos ~]$ cd gitcode

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

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

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

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

[wyd@VM-4-13-centos gitcode]$ tree .git
.git
|-- branches
|-- config
|-- description
|-- HEAD
|-- hooks
|   |-- applypatch-msg.sample
|   |-- commit-msg.sample
|   |-- post-update.sample
|   |-- pre-applypatch.sample
|   |-- pre-commit.sample
|   |-- prepare-commit-msg.sample
|   |-- pre-push.sample
|   |-- pre-rebase.sample
|   `-- update.sample
|-- info
|   `-- exclude
|-- objects
|   |-- info
|   `-- pack
`-- refs
    |-- heads
    `-- tags

9 directories, 13 files

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

2.配置 Git

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

配置命令为:

git config

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

git config [--global] user.name "YourName"
git config [--global] user.email "email@example.com"

# 把YourName改成你的昵称
# 把email@example.com改成邮箱的格式,只要格式正确即可。

如:

[wyd@VM-4-13-centos linux_gitcode]$ git config user.name "zhangsan"
[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.删除配置

删除配置的命令为:

git config [--global]  --unset user.name
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是用来记录你的提交细节的,是给其他人看的。

例如:

[wyd@VM-4-13-centos linux_gitcode]$ touch ReadMe
                                    # 在ReadMe文件中写入 hello world
[wyd@VM-4-13-centos linux_gitcode]$ echo hello world > ReadMe    
[wyd@VM-4-13-centos linux_gitcode]$ cat ReadMe
hello world

                                    # 将ReadMe的修改加入暂存区
[wyd@VM-4-13-centos linux_gitcode]$ git add ReadMe
                                    # 将暂存区的内容提交到仓库
[wyd@VM-4-13-centos linux_gitcode]$ git commit -m '提交第一个文件'
[master (root-commit) 1853b26] 提交第一个文件
 1 file changed, 1 insertion(+)
 create mode 100644 ReadMe

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

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

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

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

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

[wyd@VM-4-13-centos linux_gitcode]$ git log
commit 68df79a6f2a582fd8f390eaa947577b898bc2069
Author: wyd <1256970054@qq.com>
Date:   Sun Dec 3 21:41:13 2023 +0800

    一次性提交3个文件

commit 1853b26b95891348de92982b34f3bdbdfa01e049
Author: wyd <1256970054@qq.com>
Date:   Sun Dec 3 21:39:19 2023 +0800

    提交第一个文件

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

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

git log --pretty=onelne

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

2.查看.git文件

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

[wyd@VM-4-13-centos linux_gitcode]$ tree .git
.git
|-- branches
|-- COMMIT_EDITMSG
|-- config
|-- description
|-- HEAD
|-- hooks
|   |-- applypatch-msg.sample
|   |-- commit-msg.sample
|   |-- post-update.sample
|   |-- pre-applypatch.sample
|   |-- pre-commit.sample
|   |-- prepare-commit-msg.sample
|   |-- pre-push.sample
|   |-- pre-rebase.sample
|   `-- update.sample
|-- index
|-- info
|   `-- exclude
|-- logs
|   |-- HEAD
|   `-- refs
|       `-- heads
|           `-- master
|-- objects
|   |-- 18
|   |   `-- 53b26b95891348de92982b34f3bdbdfa01e049
|   |-- 25
|   |   `-- 1f5c5b7c0b8937ee454e3c1ec6a26e92951bd5
|   |-- 3b
|   |   `-- 18e512dba79e4c8300dd08aeb37f8e728b8dad
|   |-- 68
|   |   `-- df79a6f2a582fd8f390eaa947577b898bc2069
|   |-- 82
|   |   `-- a432cf4469d279b2ec65a226fbbb5c19fb56c9
|   |-- e6
|   |   `-- 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
|   |-- info
|   `-- pack
`-- refs
    |-- heads
    |   `-- master
    `-- tags

18 directories, 24 files

其中:

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

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

[wyd@VM-4-13-centos linux_gitcode]$ cat .git/HEAD
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命令来查看版本库对象的内容:

[wyd@VM-4-13-centos linux_gitcode]$ git cat-file -p 68df79a6f2a582fd8f390eaa947577b898bc2069
tree 82a432cf4469d279b2ec65a226fbbb5c19fb56c9
parent 1853b26b95891348de92982b34f3bdbdfa01e049
author wyd <xxxxxxxxxx@qq.com> 1701610873 +0800
committer wyd <xxxxxxxxxx@qq.com> 1701610873 +0800

一次性提交3个文件

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

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

再看 ReadMe 对应的 3b18e512dba79e4c8300dd08aeb37f8e728b8dad

[wyd@VM-4-13-centos linux_gitcode]$ git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad
hello world

# 这是我们对ReadMe做的修改!!被git记录了下来!!

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

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

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

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

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

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

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

3.添加文件--场景二

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

tjfz@139-159-150-152:~/gitcodes touch file4    #1.新增file4文件
tjfz@139-159-150-152:~/gitcodes git add file4    #2.将file4添加到暂存区
tjfz@139-159-150-152:~/gitcodes touch file5    #3.新增file5文件
tjfz@139-159-150-152:~/gitcodes git commit -m "add file"    #4.提交修改
[master 3d406co] add file
1 file changed, insertions(+), deletions(-)
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文件进行一次修改:

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

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

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

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

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

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

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

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

再修改一下 ReadMe 文件:

[wyd@VM-4-13-centos linux_gitcode]$ cat ReadMe
wonderful!

wonderful1!
wonderful2!
wonderful3!

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

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

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

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

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

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

[wyd@VM-4-13-centos linux_gitcode]$ git commit -m '提交修改后的文 件'
[master 2d511b4] 提交修改后的文件
 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

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

# 向ReadMe中新增一行代码
hyb@139-159-150-152:~/gitcode$ git status
On branch master
nothing to commit, working tree clean
hyb@139-159-150-152:~/gitcode$ vim ReadMe 
hyb@139-159-150-152:~/gitcode$ cat ReadMe 
hello bit
hello git
hello world
hello version1
hello version2
hello version3
This piece of code is like shit #新增代码

# 查看状态
hyb@139-159-150-152:~/gitcode$ git status
On branch master
Changes not staged for commit: 
(use "git add <file>..." to update what will be committed) 
(use "git restore <file>..." to discard changes in working directory) 
    modified: ReadMe
    
no changes added to commit (use "git add" and/or "git commit -a")

# 直接删除代码 恢复原来的样子
hyb@139-159-150-152:~/gitcode$ vim ReadMe 
hyb@139-159-150-152:~/gitcode$ cat ReadMe 
hello bit
hello git
hello world
hello version1
hello version2
hello version3
hyb@139-159-150-152:~/gitcode$ git status
On branch master
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:版本回退

**下篇内容

五、分支管理

六、远程操作

七、标签管理

八、多人协作

九、企业级开发模型

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/617803.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【大模型赋能开发者】海云安入选数世咨询LLM驱动数字安全2024——AI安全系列报告

近日&#xff0c;国内知名数字产业领域第三方调研咨询机构数世咨询发布了LLM驱动数字安全2024——AI安全系列报告。报告通过调研、公开信息收集等方式对目前十余家已具备LLM相关的应用能力安全厂商对比分析出了这一领域当前的产业现状并进行了各厂商的能力展示。 海云安凭借近…

易图讯三维电子沙盘-大数据处理服务

易图讯科技10名高级大数据工程师&#xff0c;高效、快速进行POI、DEM、高清卫星影像、地形地貌、路网、矢量地图等海量大数据处理服务。 免费专业提供POI、AOI、DEM、高清卫星影像、地形地貌、路网、矢量地图等海量大数据处理服务。 1年更新2次POI、高清卫星影像。

Netty源码分析二NioEventLoop 剖析

剖析方向 NioEventLoop是一个重量级的类&#xff0c;其中涉及到的方法都有很复杂的继承关系&#xff0c;调用链&#xff0c;要想把源码全部过一遍工作量实在是太大了&#xff0c;于是小编就基于下面的这些常见的问题来对NioEventLoop的源码来进行剖析 1.Seletor何时创建 1.1Se…

【Linux】- Linux环境变量[8]

目录 环境变量 $符号 自行设置环境变量 环境变量 环境变量是操作系统&#xff08;Windows、Linux、Mac&#xff09;在运行的时候&#xff0c;记录的一些关键性信息&#xff0c;用以辅助系统运行。在Linux系统中执行&#xff1a;env命令即可查看当前系统中记录的环境变量。 …

三、RocketMQ应用

RocketMQ应用 一、测试环境工程准备二、消息响应1.消息发送的状态-SendStatus2.producer消息Id-msgId3.broker消息Id-offsetMsgId 三、普通消息1.消息发送分类1.1 同步发送消息1.2 异步发送消息1.3 单向发送消息 2.代码举例2.1 同步消息发送生产者2.2 异步消息发送生产者2.3 单…

Python中bisect模块

Python中bisect模块 在Python中&#xff0c;如果我们想维持一个已排序的序列&#xff0c;可以使用内置的bisect模块&#xff0c;例如&#xff1a; import bisect# 用于处理已排序的序列 inter_list [] bisect.insort(inter_list, 3) bisect.insort(inter_list, 2) bisect.in…

【博士生必看】论文润色大揭秘!

&#x1f4dd; 投稿拒稿&#xff1f;语言不过关&#xff1f;别怕&#xff0c;我来支招&#xff01;&#x1f469;‍&#x1f393; &#x1f31f; 我的论文润色经历&#xff0c;从拒稿到接收的逆袭之路&#xff01;✨ &#x1f449; 【论文润色&#xff0c;我选了它】 我选择了…

数据结构之排序(上)

片头 嗨&#xff0c;小伙伴们&#xff0c;大家好&#xff01;我们今天来学习数据结构之排序&#xff08;上&#xff09;&#xff0c;今天我们先讲一讲3个排序&#xff0c;分别是直接插入排序、冒泡排序以及希尔排序。 1. 排序的概念及其应用 1.1 排序的概念 排序&#xff1a…

阿里云 物联网平台 MQTT连接、数据传输

阿里云 物联网平台 MQTT连接、数据传输 1、设备连接阿里云 2、多设备之前的通信、数据流转 3、设备数据来源的读取。 基于C# winform 开发上位机&#xff0c;读取设备、仪器、MES或者电子元器件的数据&#xff0c;MQTT传输至阿里云平台&#xff0c;可视化界面构建界面&#…

JSpdf,前端下载大量表格数据pdf文件,不创建dom

数据量太大使用dom》canvas》image》pdf.addimage方法弊端是canvas超出 浏览器承受像素会图片损害&#xff0c;只能将其切割转成小块的canvas,每一次调用html2canvas等待时间都很长累积时间更长&#xff0c;虽然最终可以做到抽取最小dom节点转canvas拼接数据&#xff0c;但是死…

字节码基础

基本概念 java中的字节码&#xff0c;英文bytecode。是java代码编译后的中间代码格式。JVM需要读取并解析字节码才能执行相应的任务。java字节码是JVM的指令集。JVM加载字节码格式的class文件。校验之后通过JIT编译器转换成本机机器代码执行。 java字节码简介 1、java byteco…

指针的奥秘(四):回调函数+qsort使用+qsort模拟实现冒泡排序

指针 一.回调函数是什么&#xff1f;二.qsort函数使用1.qsort介绍2.qsort排序整型数据3.qsort排序结构体数据1.通过结构体中的整形成员排序2.通过结构体中的字符串成员排序 三.qsort模拟实现冒泡排序 一.回调函数是什么&#xff1f; 回调函数就是一个通过函数指针调用的函数。 …

华为机试打卡 HJ2 计算某字符出现次数

要机试了&#xff0c;华孝子求捞&#xff0c;功德 描述 写出一个程序&#xff0c;接受一个由字母、数字和空格组成的字符串&#xff0c;和一个字符&#xff0c;然后输出输入字符串中该字符的出现次数。&#xff08;不区分大小写字母&#xff09; 数据范围&#xff1a; 1≤&a…

47.乐理基础-音符的组合方式-连线

连线与延音线长得一模一样 它们的区别就是延音线的第三点&#xff0c;延音线必须连接相同的音 连线在百分之九十九的情况下&#xff0c;连接的是不同的音&#xff0c;如下图的对比&#xff0c;连线里的百分之1&#xff0c;以现在的知识无法理解&#xff0c;后续再写 在乐谱中遇…

Linux提权--定时任务--打包配合 SUID(本地)文件权限配置不当(WEB+本地)

免责声明:本文仅做技术交流与学习... 目录 定时任务 打包配合 SUID-本地 原理: 背景: 操作演示: 分析: 实战发现: 定时任务 文件权限配置不当-WEB&本地 操作演示: 定时任务 打包配合 SUID-本地 原理: 提权通过获取计划任务执行文件信息进行提权 . 1、相对路径和…

Linux常见指令2️⃣

目录 cp指令&#xff08;重要&#xff09; mv指令&#xff08;重要&#xff09; cat、tac head、tail指令&#xff08;重要&#xff09; 知识点 时间相关的指令 知识点&#xff1a; Cal指令 grep 指令 zip/unzip指令 知识点 cp指令&#xff08;重要&#xff09; 语法…

K-CU12和利时工控单元

K-CU12和利时工控单元。控制策略组态&#xff0c;使用专用的组态软件 人机界面HMI设计&#xff1a;操作员站画面设计&#xff0c;使用专用的组态软件 K-CU12和利时工控单元文件组态 2文档管理软件 在工程师站上进行系统组态的主要工作&#xff1a; K-CU12和利时工控单元。系统配…

1067: 有向图的邻接表存储强连通判断

解法&#xff1a; 定理&#xff1a;有向图G是强连通图的充分必要条件是G中存在一条经过所有节点的回路 跟上道题一样 这是错误代码 #include<iostream> #include<vector> using namespace std; int arr[100][100]; void dfs(vector<bool>& a,int u) {a…

数据分析的统计推断

数据分析的统计推断 前言一、提出问题二、统计归纳方法三、统计推断四、统计推断步骤如何进行统计推断统计推断的基本问题点估计区间估计总体方差已知总体方差未知 假设检验假设检验的假设显著性水平 五、检验统计量常见的检验统计量 六、检验方法七、拒绝域八、假设检验步骤九…

如何使用活字格批量导入照片到数据表

活字格是一款功能强大的电子表格软件&#xff0c;除了基本的表格计算功能之外&#xff0c;还提供了丰富的扩展功能&#xff0c;可以用来实现各种自动化操作。例如&#xff0c;我们可以使用活字格来批量导入照片到数据表中。 以下是具体的操作步骤&#xff1a; 在活字格工作表…