📃个人主页:island1314
⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞
- 生活总是不会一帆风顺,前进的道路也不会永远一马平川,如何面对挫折影响人生走向 – 《人民日报》
🔥 目录
一、前言
在工作或学习时经常遇到这样的情况:我们在编写各种文档时,为了防止文档丢失,更改失误,失误后能恢复到原来的版本,不得不复制出一个副本,比如:
- “报告-v1”
- “报告-v2”
- “报告-v3”
- “报告-确定版”
- “报告-最终版”
每个版本有各自的内容,但最终会只有一份报告需要被我们使用。但在此之前的工作都需要这些不同版本的报告,于是每次都是复制粘贴副本,产出的文件就越来越多,文件多不是问题,问题是:随着版本数量的不断增多,你还记得这些版本各自都是修改了什么吗?
文档如此,我们写的项目代码,也是存在这个问题的!!
如何解决–版本控制器
为了能够更方便我们管理这些不同版本的文件,便有了版本控制器。所谓的版本控制器,就是能让你了解到一个文件的历史,以及它的发展过程的系统。通俗的讲就是一个可以记录工程的每一次改动和版本迭代的一个管理系统,同时也方便多人协同作业
最主流的版本控制器就是 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这几大平台上正常运行了。
如果你的的平台是ubuntu,安装git相当简单,以我的ubuntu20.04为例
- 首先,你可以试着输入git,看看系统有没有安装Git:
$ git
Command 'git'not found, but can be installed with:
sudo apt install git
- 出现像上面的结果,Linux会友好地告诉你Git没有安装,还会告诉你如何安装Git。安装 Git:
sudo apt-get install git -y
- 查看 git 版本
git --version
二、git 基本操作
1. 创建 Git 本地仓库
要提前说的是,仓库是进行版本控制的一个文件目录。我们要想对文件进行版本控制,就必须先创建一个仓库出来。
创建一个 Git 本地仓库对应的命令为 git init
,注意命令要在文件目录下执行,例如:
lighthouse@VM-8-10-ubuntu:gitcode$ git init
Initialized empty Git repository in /home/lighthouse/code/gitcode/.git/
lighthouse@VM-8-10-ubuntu:gitcode$ ll
total 12
drwxrwxr-x 3 lighthouse lighthouse 4096 Apr 7 10:02 ./
drwxrwxr-x 7 lighthouse lighthouse 4096 Apr 7 09:49 ../
drwxrwxr-x 7 lighthouse lighthouse 4096 Apr 7 10:02 .git/
注意:当我们在一个目录下初始化git时 可能会出现下面这个提示
lighthouse@VM-8-10-ubuntu:gitcode$ git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /home/lighthouse/code/gitcode/.git/
解决方案:一般情况下 我们先设置默认分支为master级别
git config --global init.defaultBranch master
我们发现,当前目录下多了一个.git 的隐藏文件,.git
目录是 Git 来跟踪管理仓库,不要手动修改这个目录里面的文件,不然改乱了,就把 Git 仓库给破坏了。其中包含 Git 仓库的诸多细节
lighthouse@VM-8-10-ubuntu:gitcode$ tree .git/
.git/
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── push-to-checkout.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
9 directories, 17 files
2. 配置 git
当安装 Git 后首先要做的事情是设置你的 用户名称 和 e-mail 地址,这是非常重要的。配置命令为:
git config [--global] user.name "Your Name"
git config [--global] user.email "email@example.com"
# 把 Your Name 改成你的昵称
# 把 email@example.com 改成邮箱的格式,只要格式正确即可。
其中 --global
是一个可选项。如果使用了该选项,表示这台机器上所有的 Git 仓库都会使用这个配置。如果你希望在不同仓库中使用不同的 name或,e-mail,可以不要 --global
选项,但要注意的是,执行命令时必须要在仓库里。
查看配置命令为:
git config -l
删除对应的配置命令为:
git config [--global] --unset user.name
git config [--global] --unset user.email
三、认识工作区、暂存区、版本库
- 工作区:是在电脑上你要写代码或文件的目录。
- 暂存区:英文叫 stage 或index。一般存放在 .git 目录下的
index
文件(.git/index)中,我们把暂存区有时也叫作索引(index)。 - 版本库:又名仓库,英文名 repository。工作区有一个隐藏目录.git,它不算工作区,而是 Git 的版本库。这个版本库里面的所有文件都可以被 Git 管理起来,每个文件的修改、删除,Git都能跟踪,以便任何时刻都可以追踪历史,或者在将来某个时刻可以“还原”
下⾯这个图展示了工作区、暂存区和版本库之间的关系:
- 图中左侧为工作区,右侧为版本库。Git 的版本库里存了很多东西,其中最重要的就是暂存区。
- 在创建 Git 版本库时,Git 会为我们自动创建一个唯一的 master 分支,以及指向 master 的一个指针叫 HEAD
- 当对工作区修改(或新增)的文件执行
git add
命令时,暂存区目录树的文件索引会被更新。 - 当执行提交操作
git commit
时,master分支会做相应的更新,可以简单理解为:此时暂存区的目录树才会被真正写到版本库中
四、文件操作
1. 添加文件 – 场景一
在包含 .git
的目录下新建一个文件,我们可以使用 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,由用户自己完成,这部分内容绝对不能省略,并要好好描述,是用来记录你的提交细节,是给我们人看的
案例如下:
lighthouse@VM-8-10-ubuntu:gitcode$ touch book
lighthouse@VM-8-10-ubuntu:gitcode$ vim book
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "commit my first file"
[master (root-commit) dc24b53] commit my first file
1 file changed, 1 insertion(+)
create mode 100644 book
git commit
命令执行成功后会告诉我们,1个文件被改动(就是我们新添加的文件),插入了一行内容(说明:当前新增文件里面有一行内容)
我们还可以多次 add 不同的文件,而只 commit
一次便可以提交所有文件,
- 原因:需要提交的文件是通通被 add 到暂存区中,然后一次性 commit 暂存区的所有修改
举个例子:
$ touch file1 file2
$ git add file1
$ git add file2
h$ git commit -m "add 2 files"
[master 23807c5] add 2 files
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
create mode 100644 file2
截至目前为止,我们已经更够将代码直接提交至本地仓库了。我们可以使用 git log
命令,来查看下历史提交记录:
lighthouse@VM-8-10-ubuntu:gitcode$ git log
commit dc24b53156838598792f3ff69cccfb4f612edb05 (HEAD -> master)
Author: island0920 <island0920@163.com>
Date: Mon Apr 7 10:52:54 2025 +0800
commit my first file
该命令显示从最近到最远的提交日志,并且可以看到我们 commit
时的日志消息。如果嫌输出信息太多,看得眼花缭乱的,可以试试加上 --pretty=oneline
参数:
lighthouse@VM-8-10-ubuntu:gitcode$ git log --pretty=oneline
dc24b53156838598792f3ff69cccfb4f612edb05 (HEAD -> master) commit my first file
- 需要说明的是,我们看到的一大串类似 23807c5…56eed6 的是每次提交的 commit id(版本号),Git的
commit id
不是1,2,3……递增的数字,而是一个 SHA1 计算出来的一个非常大的数字,用十六进制表示
2. 了解 .git 下目录及文件
添加完新的文件之后,再来查看 .git,会发现它下面的文件就发生了变化,如下:
lighthouse@VM-8-10-ubuntu:gitcode$ tree .git/
.git/
├── branches
├── COMMIT_EDITMSG
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── fsmonitor-watchman.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── pre-merge-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ ├── pre-receive.sample
│ ├── push-to-checkout.sample
│ └── update.sample
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ └── master
├── objects
│ ├── 59
│ │ └── 8dc4cd6941181b51e351f03f0073323d620438
│ ├── ad
│ │ └── 943250ad5c0627b624be300fb6882ae574e31a
│ ├── dc
│ │ └── 24b53156838598792f3ff69cccfb4f612edb05
│ ├── info
│ └── pack
└── refs
├── heads
│ └── master
└── tags
15 directories, 25 files
.git
目录是 Git 版本控制系统的核心,存储了仓库的所有元数据和对象。以下是各个目录和文件的详细介绍:
① 顶级目录和文件
branches
(已废弃)- 早期 Git 版本中用于存储分支的引用,现代 Git 已不再使用此目录。现在分支信息存储在
refs/heads/
中。
- 早期 Git 版本中用于存储分支的引用,现代 Git 已不再使用此目录。现在分支信息存储在
COMMIT_EDITMSG
- 作用:临时保存最近一次提交时编写的提交消息(Commit Message)。
- 生成时机:当运行
git commit
进入编辑提交消息的界面时,Git 会将消息暂存于此文件。提交完成后,内容会被存储到提交对象中,此文件保留最后一次提交的消息
config
- 仓库的配置文件,包含当前仓库的 Git 配置(如远程仓库地址、分支跟踪、别名等)。
- 可通过
git config
命令修改(例如git config user.name "Your Name"
)。
description
- 用于 GitWeb(Git 的网页界面)显示仓库的描述信息,默认是一个示例文本,可手动编辑。
HEAD
注意:
HEAD
指向的是当前分支,而分支才指向提交(默认指向 master)例如:
lighthouse@VM-8-10-ubuntu:gitcode$ cat .git/HEAD ref: refs/heads/master
其实默认的 master 分支,就是:
lighthouse@VM-8-10-ubuntu:gitcode$ cat .git/refs/heads/master
dc24b53156838598792f3ff69cccfb4f612edb05
打印的字符什么东西呢?保存的就是当前最新 的 commit id
② hooks
目录
- 存放 Git 钩子脚本的示例文件(
.sample
后缀)。钩子用于在特定 Git 操作(如提交、推送)前后触发自定义脚本。 - 常用钩子示例:
pre-commit.sample
: 提交前执行(例如代码格式检查)。commit-msg.sample
: 检查提交消息格式。post-update.sample
: 推送后触发(例如自动部署)。
- 要启用钩子,需移除
.sample
后缀并赋予可执行权限。
③ index
- 作用:Git 的 暂存区(Staging Area) 的二进制表示,记录了当前已暂存的文件状态(如文件路径、SHA-1 哈希、时间戳等)。
- 操作关联:
git add
会将文件状态写入index
。git commit
会将index
的内容生成一个提交对象。
- 查看内容:可用
git ls -files --stage
查看暂存区文件信息。
④ logs/
目录
- 作用:记录仓库中 引用(如分支、HEAD)的变更历史,用于实现
git reflog
命令(恢复误删的提交或分支)。logs/HEAD
: 记录所有 HEAD 的移动历史(如切换分支、提交、重置等)。logs/refs/heads/master
: 记录master
分支的提交历史。
- 文件格式:每行包含旧提交哈希、新提交哈希、操作者信息、时间戳和操作描述。
⑤ info
目录
exclude
- 用于定义仓库的忽略规则,类似
.gitignore
,但此文件不会被提交到远程仓库。适合个人本地忽略的临时文件。
- 用于定义仓库的忽略规则,类似
⑥ objects
目录
- 存储 Git 的所有对象(提交、文件内容、目录结构等),每个对象通过 SHA-1 哈希值命名。
info/
: 包含对象存储的附加信息。pack/
: 压缩后的对象包(Git 为优化存储将小对象打包)
- 对象存储:每个对象是一个文件,路径由 SHA-1 哈希的前两位作为目录,剩余字符作为文件名
- 常见对象:
- blob:存储文件内容。
- tree:存储目录结构(类似文件系统的文件夹)。
- commit:存储提交信息(作者、时间、父提交哈希、关联的 tree 对象)
objects 为 Git 的对象库,里面包含了创建的各种版本库对象及内容。
- 当执行
git add
命令时,暂存区的目录树被更新,同时工作区修改(或新增)的文件内容被写入到对象库中的一个新的对象中,就位于"git/objects"目录下,让我们来看看这些对象有何用处:
lighthouse@VM-8-10-ubuntu:gitcode$ ls .git/objects/
59 ad dc info pack
查找 object 时要将 commit id
分成2部分,其前2位是文件夹名称,后38位是文件名称。找到这个文件之后,一般不能直接看到里面是什么,该类文件是经过sha(安全哈希算法)加密过的文件,好在我们可以使用 git cat -file
命令来查看版本库对象的内容:
lighthouse@VM-8-10-ubuntu:gitcode$ git cat-file -p
dc24b53156838598792f3ff69cccfb4f612edb05
tree ad943250ad5c0627b624be300fb6882ae574e31a
author island0920 <island0920@163.com> 1743994374 +0800
committer island0920 <island0920@163.com> 1743994374 +0800
commit my first file
# 这就是最近一次的提交
其中,还有⼀行 tree ad943250ad5c0627b624be300fb6882ae574e31a
,我们使用同样的方法,看看结果:
lighthouse@VM-8-10-ubuntu:gitcode$ git cat-file -p ad943250ad5c0627b624be300fb6882ae574e31a
100644 blob 598dc4cd6941181b51e351f03f0073323d620438 book
- 再看 book 文件对应的
lighthouse@VM-8-10-ubuntu:gitcode$ git cat-file -p 598dc4cd6941181b51e351f03f0073323d620438
Hello Island1314
# 这就是对 ReadMe 做的修改,已被记录
⑦refs
目录
- 存储引用(指针),包括分支和标签。
heads/
: 分支的引用(例如refs/heads/main
指向main
分支的最新提交)。tags/
: 标签的引用(例如refs/tags/v1.0
指向某个提交的标签)。
总结
- 对象存储:
objects
目录是 Git 的底层数据库,所有数据(文件内容、提交记录等)均以对象形式存储- 引用管理:
refs
目录通过简单的文本文件指向对象的 SHA-1 哈希值,实现分支和标签的快速定位- 本地配置:
config
和hooks
允许定制化 Git 行为,而exclude
和.gitignore
用于文件忽略index:暂存区,git add 后会更新该内容。
HEAD:默认指向 master 分支的一个指针。
refs/heads/master:文件里保存当前 master 分支的最新 commit id
objects:包含了创建的各种版本库对象及内容,可以简单理解为放了 git 维护的所有修改。
3. 添加文件 – 场景二
那么我们再展示一种添加文件的场景,能加深对工作区、暂存区、版本库的理解,示例如下
$ touch file4 #1. 新增file4⽂件
$ git add file4 #2. 将file4添加到暂存区
$ touch file5 #3. 新增file5⽂件
$ git commit -m"add file" #4. 提交修改
[master 3d406c0] add file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
提交后发现打印了 1 file changed,0 insertions(+),0 deletions(-)
,意思是只有一个文件改变了,这时我们提出了疑问,不是新增了两个文件吗?
- 再来回忆下,
git add
是将文件添加到暂存区,git commit
是将暂存区的内容添加到本地仓库中。由于我们并没有使用git add file5
,file5 就不在暂存区中维护,所以我们commit
的时候其实只是把已经在暂存区的 file4 提交了,而遗漏了工作区的file5。 - 如何提交 file5 呢?很简单,再次add ,commit 即可。
4. 修改文件
Git 比其他版本控制系统设计得优秀,因为 Git 跟踪并管理的是修改,而非文件。
- 什么是修改? ===> 比如你新增了一行,这就是一个修改,删除了一行,也是一个修改,更改了某些字符,也是一个修改,删了一些又加了一些,也是一个修改,甚至创建一个新文件,也算一个修改。对 book 文件进行一次修改:
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
此时,仓库中的 book
和我们工作区的 book
是不同的,如何查看当前仓库的状态呢?
git status
命令用于查看在你上次提交之后是否有对文件进行再次修改。
lighthouse@VM-8-10-ubuntu: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: book
no changes added to commit (use "git add" and/or "git commit -a")
上面的结果告诉我们,ReadMe被修改过了,但还没有完成添加与提交。
- 目前,我们只知道文件被修改了,但是并不知道具体哪些地方被修改了
git diff [file]
命令用来显示暂存区和工作区文件的差异,显示的格式正是Unix通用的diff格式。
- 也可以使
git diff HEAD -- [file]
命令来查看版本库和工作区文件的区别。
lighthouse@VM-8-10-ubuntu:gitcode$ git diff book
diff --git a/book b/book
index 598dc4c..92a1e2d 100644
--- a/book
+++ b/book
@@ -1 +1,2 @@
Hello Island1314
+Hello World
知道了对当前文件做了什么修改后,再把它提交到本地仓库就放心多了。
git add
之后,就没有看到上面no changes added to commit(use "git add" and/or "git commit -a")
的消息了。- 接下来让我们继续
git commit
即可:
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "add modify Book file"
[master b2f0ee2] add modify Book file
1 file changed, 1 insertion(+)
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch master
nothing to commit, working tree clean
5. 版本回退
🔥 之前我们也提到过,Git 能够管理文件的历史版本,这也是版本控制器重要的能力。如果有一天你发现之前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了。
- 执行
git reset
命令用于回退版本,可以指定退回某一次提交的版本
要解释一下“回退”本质是要将版本库中的内容进行回退,工作区或暂存区是否回退由命令参数决定:
git reset
命令语法格式为:git reset[--soft | --mixed | --hard] [HEAD]
--mixed
:默认选项,使用时可以不用带该参数。该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变。--soft
参数:对于工作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。--hard
参数:将暂存区与工作区都退回到指定版本。- 切记工作区有未提交的代码时不要用这个命令,因为工作区会回滚,你没有提交的代码就再也找不回了,所以使用该参数前一定要慎重。
HEAD
说明:
可直接写成
commitid
,表示指定退回的版本。HEAD 表示当前版本
HEAD^ 上一个版本
HEAD^^上上一个版本。以此类推…0
可以使用 ~数字表示:
- HEAD~0 表示当前版本
- HEAD~1 上一个版本
为了便于表述,方便测试回退功能,我们先做一些准备工作:更新3个版本的book,并分别进行3次提交,如下所示:
# 第一次修改提交
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "add version1"
[master 6af6d8b] add version1
1 file changed, 1 insertion(+)
# 第二次修改提交
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "add version2"
[master 6c506d8] add version2
1 file changed, 1 insertion(+)
# 第三次提交
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "add version3"
[master c0117bd] add version3
1 file changed, 1 insertion(+)
现在,如果我们在提交完 version3后,发现 version3
编写错误,想回退到 version2,重新基于 version2
开始编写。
- 由于我们在这里希望的是将工作区的内容也回退到 version 2 版本,所以需要用到–hard 参数,示例如下:
lighthouse@VM-8-10-ubuntu:gitcode$ git log --pretty=oneline
c0117bd12effb75985b185a59ac69b21e20949c1 (HEAD -> master) add version3
6c506d833b9d90494255f572e414a2637941577e add version2
6af6d8b16aed1c3c8908ecfe7b856c99ee9815b9 add version1
b2f0ee2d8a167c59732da07df60cc7f2337c50e9 add modify Book file
dc24b53156838598792f3ff69cccfb4f612edb05 commit my first file
lighthouse@VM-8-10-ubuntu:gitcode$ git reset --hard 6c506d833b9d90494255f572e414a2637941577e
HEAD is now at 6c506d8 add version2
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
但是如果我后悔了,想再回到version3怎么办?
- 我们可以继续使用 git reset 命令,回退到 version 3 版本,但我们必须要拿到 version 3的
commitid
去指定回退的版本。
lighthouse@VM-8-10-ubuntu:gitcode$ git log --pretty=oneline
6c506d833b9d90494255f572e414a2637941577e (HEAD -> master) add version2
6af6d8b16aed1c3c8908ecfe7b856c99ee9815b9 add version1
b2f0ee2d8a167c59732da07df60cc7f2337c50e9 add modify Book file
dc24b53156838598792f3ff69cccfb4f612edb05 commit my first file
- 但是现在
git log
并不能打印出 version 3 版本的commit id
,运气好的话我们可以从终端上去找找之前的记录,运气不好的话commitid
已经被我们搞丢了,如下是找到了version 3 的commit id
lighthouse@VM-8-10-ubuntu:gitcode$ git reset --hard c0117bd12effb75985b185a59ac69b21e20949c1
HEAD is now at c0117bd add version3
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
如果没找到的话:Git 还提供了一个 git reflog
命令能补救一下,该命令用来记录本地的每一次命令
lighthouse@VM-8-10-ubuntu:gitcode$ git reflog
6c506d8 (HEAD -> master) HEAD@{0}: reset: moving to 6c506d833b9d90494255f572e414a2637941577e
c0117bd HEAD@{1}: reset: moving to c0117bd12effb75985b185a59ac69b21e20949c1
6c506d8 (HEAD -> master) HEAD@{2}: reset: moving to 6c506d833b9d90494255f572e414a2637941577e
c0117bd HEAD@{3}: commit: add version3
6c506d8 (HEAD -> master) HEAD@{4}: commit: add version2
6af6d8b HEAD@{5}: commit: add version1
b2f0ee2 HEAD@{6}: commit: add modify Book file
dc24b53 HEAD@{7}: commit (initial): commit my first file
这样,你就可以很方便的找到你的所有操作记录了,但 c0117bd
这个是啥东西?这个是 version3 的 commit id 的部分。没错,Git 版本回退的时候,也可以使用部分 commit id 来代表目标版本。示例如下:
lighthouse@VM-8-10-ubuntu:gitcode$ git reset --hard c0117bd
HEAD is now at c0117bd add version3
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
但是在实际开发中,由于长时间的开发了,导致 commit id 早就找不到了,可突然某一天,我又想回退到version3,那该如何操作呢?貌似现在不可能了
- 值得说的是,Git 的版本回退速度非常快,因为 Git 在内部有个指向当前分支(此处是master)的HEAD 指针,
refs/heads/master
文件里保存当前master
分支的最新commit id
。
当我们在回退版本的时候,Git仅仅是给 refs/heads/master
中存储一个特定的 version
,可以简单理解成如下示意图:
6. 撤销修改
如果我们在我们的工作区写了很长时间代码,越写越写不下去,觉得自己写的实在是垃圾,想恢复到上一个版本
1️⃣对于工作区的代码,还没有 add
当然可以选择直接删掉你目前在工作区新增的代码,但如果是过了一段时间之后的代码呢,那该怎么办?
- 你自己都忘了自己新增过哪些,有同学说,我可以
git diff xxx
一下,看看差别在删啊,那你肯定又要花3天时间删代码了,并且很大的概率还会改出bug。一周过去了,你怎么向你的老板交代呢? - Git 其实还为我们提供了更好的方式,我们可以使用
git checkout -- [file]
命令让工作区的文件回到最近一次add
或commit
时的状态。 - 要注意
git checkout -- [file]
命令中的--
( 很重要,切记不要省略,一旦省略,该命令就变为其他意思了,这个后面再说)示例如下:
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
This piece of code is like shit #新增代码
lighthouse@VM-8-10-ubuntu: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: book
no changes added to commit (use "git add" and/or "git commit -a")
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -- book
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
2️⃣已经 add,但没有 commit
add 后还是保存到了暂存区,该怎么撤销呢??
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
This piece of code is like shit #新增代码
# add 存入暂存区
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: book
然后再使用之前说过的 git reset
回退命令,该命令如果使用 --mixed 参数,可以将暂存区的内容退回为指定的版本内容,但工作区文件保持不变。那我们就可以回退下暂存区的内容了!!!
示例如下:
# --mixed 是默认参数, 使用时可省略
lighthouse@VM-8-10-ubuntu:gitcode$ git reset HEAD book
Unstaged changes after reset:
M book
# 此时暂存区就是干净的, 工作区有修改
lighthouse@VM-8-10-ubuntu: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: book
no changes added to commit (use "git add" and/or "git commit -a")
然后此时就回到了情况一的时候,再使用 git checkout -- book
丢弃掉工作区的修改即可
3️⃣已经 add,也已经 commit
我们可以 git reset --hard HEAD^
回退到上一个版本!
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
This piece of code is like shit #新增代码
# 提交
lighthouse@VM-8-10-ubuntu:gitcode$ git add book
lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "test quash"
[master 3a76865] test quash
1 file changed, 1 insertion(+)
# 回退
lighthouse@VM-8-10-ubuntu:gitcode$ git reset --hard HEAD^
HEAD is now at c0117bd add version3
lighthouse@VM-8-10-ubuntu:gitcode$ cat book
Hello Island1314
Hello World
hello version1
hello version2
hello version3
注意事项:
- 不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程
- 还记得Git是分布式版本控制系统吗?我们后面会讲到远程版本库,一旦你推送到远程版本库,你就真的惨了……
7. 删除文件
在 Git 中,删除也是一个修改操作,我们实战一下,如果要删除 file5 文件,怎么搞呢?如果你这样做了:
lighthouse@VM-8-10-ubuntu:gitcode$ ls
book file
lighthouse@VM-8-10-ubuntu:gitcode$ rm file
注意:但这样直接删除是没有用的,反而徒增烦恼,git status 命令会立刻告诉你哪些文件被删除了
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file
no changes added to commit (use "git add" and/or "git commit -a")
- 此时:工作区和版本库就不一致了,要删文件,目前除了要删工作区的文件,还要清除版本库的文
件
一般走到这里,有两种可能:
- 不小心删错了
- 如果是在这种情况下,就需要使用
git checkout -- [file]
来进行恢复(删除也是修改)
- 如果是在这种情况下,就需要使用
lighthouse@VM-8-10-ubuntu:gitcode$ git checkout -- file
lighthouse@VM-8-10-ubuntu:gitcode$ git status
On branch master
nothing to commit, working tree clean
确实要从版本库中删除该文件
- 在这种情况下:很明显是没有删完,我们只删除了工作区的文件。这时就需要使用
git rm
将文件从暂存区和工作区中删除,并且commit
lighthouse@VM-8-10-ubuntu:gitcode$ git rm file rm 'file' lighthouse@VM-8-10-ubuntu:gitcode$ git status On branch master Changes to be committed: (use "git restore --staged <file>..." to unstage) deleted: file # 删除之后, 还需要 commit 一次 lighthouse@VM-8-10-ubuntu:gitcode$ git commit -m "delete file" [master f312a54] delete file 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 file # 此时, 文件就从版本库被删除了 lighthouse@VM-8-10-ubuntu:gitcode$ git status On branch master nothing to commit, working tree clean
- 在这种情况下:很明显是没有删完,我们只删除了工作区的文件。这时就需要使用