【Git学习笔记】Git结构原理及其分支管理模型分析

【Git学习笔记】Git结构原理及其分支管理模型分析

🔥个人主页大白的编程日记

🔥专栏Git学习笔记


文章目录

前言

哈喽,各位小伙伴大家好!今天开始我们就进入新的篇章------Git学习!。今天我们来讲一下Git初始及其结构原理分析。话不多说,我们进入正题!向大厂冲锋

一.认识工作区、暂存区、版本库

1.1 版本回退

之前我们也提到过,Git 能够管理文件的历史版本,这也是版本控制器重要的能力。如果有一天你发现之前的工作做的出现了很大的问题,需要在某个特定的历史版本重新开始,这个时候,就需要版本回退的功能了。

执行 git reset 命令用于回退版本,可以指定退回某一次提交的版本。要解释一下"回退"本质是要将版本库中的内容进行回退,工作区或暂存区是否回退由命令参数决定:

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

  • --mixed 为默认选项,使用时可以不用带该参数。该参数将暂存区的内容退回为指定提交版本内容,工作区文件保持不变。
  • --soft 参数对于工作区和暂存区的内容都不变,只是将版本库回退到某个指定版本。
  • --hard 参数将暂存区与工作区都退回到指定版本。切记工作区有未提交的代码时不要用这个命令,因为工作区会回滚,你没有提交的代码就再也找不回了,所以使用该参数前一定要慎重。
  • HEAD 说明:
    可直接写成commitid,表示指定退回的版本
  1. HEAD 表示当前版本
  2. HEAD^ 上一个版本
  3. HEAD^^ 上上一个版本
    以此类推...
  • 可以使用 ~数字表示:
  1. HEAD~0 表示当前版本
  2. HEAD~1 上一个版本
  3. HEAD^2 上上一个版本
    以此类推...

为了便于表述,方便测试回退功能,我们先做一些准备工作:更新3个版本的ReadMe,并分别进行3次提交,如下所示:

bash 复制代码
# 第⼀次修改提交
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
qcj@139 - 159 - 150 - 152:~/ gitcode$ git add ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ git commit - m"add version1"
[master cff9d1e] add version1
1 file changed, 1 insertion(+)
# 
第⼆次修改提交
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
qcj@139 - 159 - 150 - 152:~/ gitcode$ git add ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ git commit - m"add version2"
1 file changed, 1 insertion(+)
# 第三次修改提交
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
qcj@139 - 159 - 150 - 152:~/ gitcode$ git add ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ git commit - m"add version3"
[master d95c13f] add version3
1 file changed, 1 insertion(+)
# 查看历史提交记录
qcj@139 - 159 - 150 - 152:~/ gitcode$ git log --pretty = oneline
d95c13ffc878a55a25a3d04e22abfc7d2e3e1383(HEAD->master) add version3
14c12c32464d6ead7159f5c24e786ce450c899dd add version2
cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
...

现在,如果我们在提交完version3后,发现 version3编写错误,想回退到 version2,重新基于version2开始编写。由于我们在这里希望的是将工作区的内容也回退到 version 2 版本,所以需要用到--hard 参数,示例如下:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git log --pretty = oneline
d95c13ffc878a55a25a3d04e22abfc7d2e3e1383(HEAD->master) add version3
14c12c32464d6ead7159f5c24e786ce450c899dd add version2
cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
...
qcj@139 - 159 - 150 - 152:~/ gitcode$
git reset --hard
14c12c32464d6ead7159f5c24e786ce450c899dd
HEAD is now at 14c12c3 add version2
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2

我们惊奇的发现,此时 ReadMe 文件的内容,已经回退到 version2了!,当前,我们再次用 git log 查看一下提交日志,发现 HEAD 指向了version2,如下所示:

bash 复制代码
hyb@139-159-150-152:~/gitcode$ git log --pretty=oneline
 14c12c32464d6ead7159f5c24e786ce450c899dd (HEAD -> master) add version2
 cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
 ...

到这里一般回退功能就演示完了,但现在如果我后悔了,想再回到 version3怎么办?我们可以继续使用 git reset 命令,回退到 version 3 版本,但我们必须要拿到 version 3的 commit id 去指定回退的版本。

但我们看到了 git log并不能打印出 version 3的 commit id,运气好的话我们可以从终端上去找找之前的记录,运气不好的话commitid 已经被我们搞丢了=。=

Git 还提供了⼀个git reflog 命令能补救⼀下,该命令用来记录本地的每⼀次命令。

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$
git reflog
14c12c3(HEAD->master) HEAD@{0}: reset: moving to
14c12c32464d6ead7159f5c24e786ce450c899dd
d95c13f HEAD@{1}: commit: add version3
14c12c3(HEAD->master) HEAD@{2}: commit: add version2
cff9d1e HEAD@{3}: commit: add version1
94da695 HEAD@{4}: commit: add modify ReadMe file
23807c5 HEAD@{5}: commit: add 3 files
c614289 HEAD@{6}: commit(initial) : commit my first file

这样,你就可以很方便的找到你的所有操作记录了,但 d95c13f这个是啥东西?这个是 version3 的 commit id 的部分。没错,Git 版本回退的时候,也可以使用部分 commit id 来代表目标版本。示例如下:

bash 复制代码
# 回退到v3
qcj@139 - 159 - 150 - 152:~/ gitcode$
git reset --hard d95c13f
HEAD is now at d95c13f add version3
# 查看⼯作区
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
# 查看log
qcj@139 - 159 - 150 - 152:~/ gitcode$ git log --pretty = oneline
d95c13ffc878a55a25a3d04e22abfc7d2e3e1383(HEAD->master) add version3
14c12c32464d6ead7159f5c24e786ce450c899dd add version2
cff9d1e019333318156f8c7d356a78c9e49a6e7b add version1
94da6950d27e623c0368b22f1ffc4bff761b5b00 add modify ReadMe file
23807c536969cd886c4fb624b997ca575756eed6 add 3 files
c61428926f3853d4ec6dde904415b0e6c1dabcc6 commit my first file

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

值得说的是,Git的版本回退速度非常快,因为 Git 在内部有个指向当前分支(此处是master)的HEAD指针,refs/heads/master 文件里保存当前 master 分支的最新 commit id。当我们在回退版本的时候,Git仅仅是给 refs/heads/master 中存储一个特定的version,可以简单理解成如下示意图:

1.2 撤销修改

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

  • 情况一:对于工作区的代码,还没有 add
    你当然可以直接删掉你目前在工作区新增的代码,像这样
bash 复制代码
# 向ReadMe中新增⼀⾏代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git status
On branch master
nothing to commit, working tree clean
qcj@139 - 159 - 150 - 152:~/ gitcode$ vim ReadMe
qcj@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  #
新增代码
qcj@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")
# 直接删除代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ vim ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
qcj@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]命令中的

很重要,切记不要省略,一旦省略,该命令就变为其他意思了,后面我们再说。示例如下:

bash 复制代码
# 
向ReadMe中新增⼀⾏代码
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  #新增代码 
# 恢复到上⼀次add 或commit
hyb@139-159-150-152:~/gitcode$ git checkout -- ReadMe
hyb@139-159-150-152:~/gitcode$ cat ReadMe 
hello bit
hello git
hello world
hello version1
hello version2
hello version3
  • 情况二:已经 add ,但没有commit
    add 后还是保存到了暂存区呢?怎么撤销
bash 复制代码
# 向ReadMe中新增⼀⾏代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ vim ReadMe
qcj@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  #
# add存⼊暂存区新增代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git add ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ git status
On branch master
Changes to be committed :
(use "git restore --staged <file>..." to unstage)
modified:   ReadMe

让我们来回忆一下学过的 git reset 回退命令,该命令如果使用 --mixed 参数,可以将暂存区的内容退回为指定的版本内容,但工作区文件保持不变。那我们就可以回退下暂存区的内容了

bash 复制代码
#--mixed 是默认参数,使用时可以省略
qcje139 - 159 - 150 - 152:~/ gitcode$ git reset HEAD ReadMe
Unstaged changes after reset :
M      ReadMe

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

bash 复制代码
qcj@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")

还记得如何丢弃工作区的修改吗?

bash 复制代码
hybe139-159-150-152:~/gitcode$ git checkout -- ReadMe
hyb@139-159-150-152:~/gitcode$ git status
On branch master
nothing to commit,working tree clean
hybe139-159-150-152:~/gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3

恢复了!

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

不要担心,我们可以 git reset --hardHEAD^回退到上一个版本!不过,这是有条件的,就是你还没有把自己的本地版本库推送到远程。还记得Git是分布式版本控制系统吗?我们后面会讲到远程版本库,一旦你推送到远程版本库,你就真的惨了

bash 复制代码
# 向ReadMe中新增⼀⾏代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ vim ReadMe
qcj@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  #新增代码
# 提交
qcj@139 - 159 - 150 - 152:~/ gitcode$ git add ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$ git commit - m"test quash"
[master 5f71ae1] test quash
1 file changed, 1 insertion(+)
# 回退
qcj@139 - 159 - 150 - 152:~/ gitcode$ git reset --hard HEAD ^
HEAD is now at 144a3f8 add file
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3

1.3 删除文件

在 Git 中,删除也是一个修改操作,我们实战一下,如果要删除 file5 文件,怎么搞呢?如果你这样做了

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ ls
file1  file2  file3  file4  file5  ReadMe
qcj@139 - 159 - 150 - 152:~/ gitcode$rm file5

但这样直接删除是没有用的,反而徒增烦恼,git status 命令会立刻告诉你哪些文件被删除了:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ 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:
file5
no changes added to commit(use "git add" and /or "git commit -a")

此时,工作区和版本库就不一致了,要删文件,目前除了要删工作区的文件,还要清除版本库的文件。

⼀般走到这里,有两种可能:

  • 确实要从版本库中删除该文件
  • 不小心删错了
    对第二种情况,很明显误删,需要使用 git 来进行恢复,很简单,我们刚学过(删除也是修改)
bash 复制代码
hyb@139-159-150-152:~/gitcode$ git checkout -- file5
 hyb@139-159-150-152:~/gitcode$ ls
 file1  file2  file3  file4  file5  ReadMe

对于第一种情况,很明显是没有删完,我们只删除了工作区的文件。这时就需要使用 gitrm 将文件从暂存区和工作区中删除,并且commit :

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$
git rm file5
rm 'file5'
qcj@139 - 159 - 150 - 152:~/ gitcode$ git status
On branch master
Changes to be committed :
(use "git restore --staged <file>..." to unstage)
deleted:file5
qcj@139 - 159 - 150 - 152:~/ gitcode$git rmgit commit - m"deleted file5"
[master 5476bde] deleted file5
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file5
qcj@139 - 159 - 150 - 152:~/ gitcode$ git status
On branch master
nothing to commit, working tree clean

现在,文件就从版本库中被删除了。

二. 分支管理

2.1 理解分支

本章开始介绍 Git 的杀手级功能之一(注意是之一,也就是后面还有之二,之三......):分支。分支就是科幻电影里面的平行宇宙,当你正在电脑前努力学习 C++ 的时候,另一个你正在另一个平行宇宙里努力学习 JAVA。

如果两个平行宇宙互不干扰,那对现在的你也没啥影响。不过,在某个时间点,两个平行宇宙合并了,结果,你既学会了 C++ 又学会了 JAVA!

在版本回退里,你已经知道,每次提交,Git都把它们串成一条时间线,这条时间线就可以理解为是个分支。截止到目前,只有一条时间线,在Git里,这个分支叫主分支,即master分支。

再来理解一下HEAD,HEAD 严格来说不是指向提交,而是指向master,master才是指向提交的,所以,HEAD 指向的就是当前分支。

每次提交,master分支都会向前移动一步,这样,随着你不断提交,master分支的线也越来越长,而HEAD只要一直指向master分支即可指向当前分支。

通过查看当前的版本库,我们也能清晰的理出思路:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat.git / HEAD
ref : refs / heads / master
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat.git / refs / heads / master
5476bdeb12510f7cd72ac4766db7988925ebd302

2.2 创建分支

Git 支持我们查看或创建其他分支,在这里我们来创建第一个自己的分支 dev ,对应的命令为:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git branch
* master
qcj@139 - 159 - 150 - 152:~/ gitcode$ git branch dev
qcj@139 - 159 - 150 - 152:~/ gitcode$ git branch
dev
* master

当我们创建新的分支后,Git 新建了一个指针叫 dev,*表示当前 HEAD 指向的分支是 master分支。另外,可以通过目录结构发现,新的 dev分支:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ ls.git / refs / heads /
dev  master
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat.git / refs / heads/*
5476bdeb12510f7cd72ac4766db7988925ebd302
5476bdeb12510f7cd72ac4766db7988925ebd302

发现目前 dev和 master指向同一个修改。并且也可以验证下 HEAD 目前是指向 master 的。

bash 复制代码
hyb@139-159-150-152:~/gitcode$ cat .git/HEAD
 ref: refs/heads/master

一张图总结:

2.3 切换分支

那如何切换到 dev分支下进行开发呢?使用 git checkout 命令即可完成切换,示例如下

c 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git checkout dev
Switched to branch 'dev'
qcj139 - 159 - 150 - 152 : ~/ gitcode$ git branch
* dev
master
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat.git / HEAD
ref : refs / heads / dev

我们发现 HEAD 已经指向了 dev,就表示我们已经成功的切换到了 dev 上!

接下来,在 dev 分支下修改 ReadMe文件,新增一行内容,并进行一次提交操作:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ vim ReadMe
qcj@139 - 159 - 150 - 152 : ~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello versionl
hello version2
hello version3
write aaa for new branch
qcje139 - 159 - 150 - 152:~/ gitcode$ git add .
qcj@139 - 159 - 150 - 152:~/ gitcode$ git commit - m"modify ReadMe"
[dev 3740dce] modify ReadMe
1 file changed, l insertion(+)

现在,dev分支的工作完成,我们就可以切换回 master分支:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git checkout master
Switched to branch 'master
qcj@139 - 159 - 150 - 152:~/ gitcodes cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3

切换回 master 分支后,发现ReadMe文件中新增的内容不见了!!!赶紧再切回 dev看看

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git checkout dev
Switched to branch 'dev'
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello version1
hello version2
hello version3
write aaa for new branc

在 dev分支上,内容还在。为什么会出现这个现象呢?我们来看看 dev分支和 master分支指向,发现两者指向的提交是不一样的:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat.git / refs / heads / dev
bdaf528ffbb8e05aee34d37685408f0e315e31a4
qcj@139 - 159 - 150 - 152 : ~/ gitcode$ cat.git / refs / heads / master
5476bdeb12510f7cd72ac4766db7988925ebd302

看到这里就能明白了,因为我们是在dev分支上提交的,而master分支此刻的提交点并没有变,此时的状态如图如下所示。

当切换到 master分支之时,HEAD 就指向了 master,当然看不到提交了!

2.4 合并分支

为了在 master 主分支上能看到新的提交,就需要将 dev 分支合并到 master 分支,示例如下:

bash 复制代码
qcj139 - 159 - 150 - 152:~/ gitcode$ git branch
* dev
master
qcje139 - 159 - 150 - 152 : ~/ gitcode$ git checkout master
# 切换到 master 上进行合并
Switched to branch 'master'
qcje139 - 159 - 150 - 152:~/ gitcodes git merge dev #合并 dev 分支
Updating 16623e1..3740dce
Fast - forward
ReadMe1 +
l file changed, 1 insertion(+)
qcj@139 - 159 - 150 - 152:~/ gitcode$ cat ReadMe
hello bit
hello git
hello world
hello versionl
hello version2
hello version3
write aaa for new branch

git merge 命令用于合并指定分支到当前分支。合并后,master就能看到dev分支提交的内容了。此时的状态如图如下所示。

Fast-forward 代表"快进模式"也就是直接把master指向dev的当前提交,所以合并速度非常快。当然,也不是每次合并都能 Fast-forward,我们后面会讲其他方式的合并。

2.5 删除分支

合并完成后,dev分支对于我们来说就没用了,那么dev分支就可以被删除掉,注意如果当前正处于某分支下,就不能删除当前分支,如:

bash 复制代码
qcj@139 - 159 - 150 - 152:~/ gitcode$ git branch
* dev
master
qcj@139 - 159 - 150 - 152:~/ gitcode$
git branch - d dev
error : Cannot delete branch 'dev' checked out at '/home/qcj/gitcode'

而可以在其他分支下删除当前分支,如:

bash 复制代码
qcje139 - 159 - 150 - 152:~/ gitcode$ git checkout master
Switched to branch 'master
qcje139 - 159 - 150 - 152 : ~/ gitcode$ git branch - d dev
Deleted branch dev(was bdaf528).
qcje139 - 159 - 150 - 152 : ~/ gitcode$ git branch
* master

此时的状态如图如下所示。

因为创建、合并和删除分支非常快,所以Git鼓励你使用分支完成某个任务,合并后再删掉分支,这和直接在master分支上工作效果是一样的,但过程更安全。

2.6 图文分析

上面的过程的 下面这一张图搞定!

后言

这就是Git结构原理及其分支管理模型分析。大家自己好好消化!今天就分享到这!感谢各位的耐心垂阅!咱们下期见!拜拜~

相关推荐
阿巴Jun12 分钟前
【数学】线性代数知识点总结
笔记·线性代数·矩阵
茯苓gao26 分钟前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾39 分钟前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT1 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa1 小时前
HTML和CSS学习
前端·css·学习·html
ST.J2 小时前
前端笔记2025
前端·javascript·css·vue.js·笔记
Suckerbin2 小时前
LAMPSecurity: CTF5靶场渗透
笔记·安全·web安全·网络安全
看海天一色听风起雨落2 小时前
Python学习之装饰器
开发语言·python·学习
小憩-2 小时前
【机器学习】吴恩达机器学习笔记
人工智能·笔记·机器学习
ficker133 小时前
git常用命令
git