likes
comments
collection
share

Git从原理到实践的全面指南 | 概念篇

作者站长头像
站长
· 阅读数 10

Git是一个非常强大的代码管理工具,它不仅可以让你方便地提交、推送、拉取代码,还可以让你灵活地处理各种复杂的分支、合并、冲突等问题。说到使用,相信大家都会,无非就是commit、push、pull 。但是如果要说熟练掌握Git的使用,对代码管理做到得心应手却不是那么容易。现在我们就先从基本的概念开始,系统地学习Git的原理和操作。

前言

📌首先要知道Git 是如何保存数据的?

Git 保存的不是文件的变化或者差异,而是一系列不同时刻的 快照,在进行提交操作时,Git 会保存一个提交对象(commit object)。下面会说到这个object,它被保存在.git隐藏文件中。

三种状态

Git 有三种状态,后面经常会用到这些概念,所以需要理解并记住。一般来说,你的文件会处于处于三种状态其中之一: 已提交(committed)已修改(modified)已暂存(staged)

  • 已修改表示修改了文件,但还没保存到数据库中。
  • 已暂存表示对一个已修改文件的当前版本做了标记,使之包含在下次提交的快照中。
  • 已提交表示数据已经安全地保存在本地数据库中。

这会让我们的 Git 项目拥有三个阶段:工作区、暂存区以及 Git 目录

Git从原理到实践的全面指南 | 概念篇

工作区

这是对项目的某个版本独立提取出来的内容。 这些从 Git 仓库的压缩数据库中提取出来的文件,放在磁盘上供你使用或修改。

暂存区

它是一个文件,保存了下次将要提交的文件列表信息,一般在 Git 仓库目录中。 按照 Git 的术语叫做“索引”,不过一般说法还是叫“暂存区”。

Git 仓库目录

这是 Git 用来保存项目的元数据和对象数据库的地方。 这是 Git 中最重要的部分,从其它计算机克隆仓库时,复制的就是这里的数据。

基本的 Git 工作流程

✂git的工作流程一般为:

  1. 工作区中修改文件。
  2. 将你想要下次提交的更改选择性地暂存,这样只会将更改的部分添加到暂存区
  3. 提交更新,找到暂存区的文件,将快照永久性存储到 Git 目录。

如果 Git 目录中保存着特定版本的文件,就属于 已提交 状态。 如果文件已修改并放入暂存区,就属于 已暂存 状态。 如果自上次检出后,作了修改但还没有放到暂存区域,就是 已修改 状态。

commit

Git commit 是将暂存区里的改动提交到本地的版本库。每次使用 git commit 命令我们都会在本地版本库生成一个 40 位的哈希值,这个哈希值也叫 commit-id。

在Git中,commit可以看作是你对代码所做的一次保存。每一次提交都会记录你对代码所做的更改,包括添加、删除和修改的文件。这些提交被保存在Git的数据库中,构成了代码版本控制系统的历史记录。

这个历史记录📒允许你在代码中查看和恢复以前的更改,以及在代码版本之间进行比较。简单来说,commit就是记录你对代码所做的更改,并将这些更改保存在Git数据库中的一个过程。

branch分支

Git的分支是指代码版本的一种分支,允许你在不影响主代码版本的情况下进行更改和试验。

假设你在一个项目上工作,你可以使用分支来创建一个独立的代码版本,在这个版本中你可以进行试验和更改,而不会影响到主版本。

如果你的更改最终被证明是有用的,你可以将它们合并回主版本中。这就是分支的作用,它可以让你在不破坏主版本的情况下,进行试验和更改。

Git 创建新分支实际上是它为你创建了一个可以移动的新的指针。它指向当前所在的提交对象。

Git从原理到实践的全面指南 | 概念篇

📌当有多个分支时,Git 又是怎么知道当前在哪一个分支上呢?

很简单,它有一个名为 HEAD 的特殊指针。 它会指向当前所在的本地分支

HEAD

HEAD 是一个指向你正在工作中的本地分支的指针,可以将 HEAD 想象为当前分支的别名。在 Git 中,每次提交,Git 都把它们串成一条时间线,这条时间线就是一个分支。截止到目前,只有一条时间线,在 Git 里,这个分支叫主分支,即 master 分支。HEAD 严格来说不是指向提交,而是指向 master,master 才是指向提交的,所以,HEAD 指向的就是当前分支。

如果你切换到了其他分支,HEAD 就会指向那个分支。如果你提交了新的修改,master 分支也会随之移动,而 HEAD 指向的分支也会随之移动。

我们可以把git看作是一辆车🚚,而HEAD就像是车头。车头总是指向车身的前方,告诉我们它们所在的方向。同样,HEAD也指向我们当前所在的代码版本。

三者的关系

📌commit,branch和HEAD之间到底是什么关系呢?

假设你正在写一篇文章,你可以把文章的每一个版本看作是一个提交(commit)。

当你需要进行修改时,你可以创建一个新的版本,类似于在文章上打草稿。你可以在这个新的版本上进行修改,而不会影响原先的版本。这个新的版本就像是一个分支,指向你正在编辑的版本。

当你完成修改时,你可以提交新的版本,就像是把你的修改写进正式的文章中。这个提交(commit)将成为一个新的版本,你的分支将指向这个新的版本。

HEAD的作用就像是你在写文章时的光标🏷。它指向你正在编辑的版本,告诉你哪一个版本是当前正在被修改的。当你创建新的版本时,HEAD也会跟随移动到新的版本上,指向新的版本,这样你就可以在这个新的版本上进行修改了。

master和origin

推送代码的命令是git push origin master,那这里面的origin 和 master代表了什么呢?

“master ”的含义?

Git 的默认 branch(俗称主 branch / 主分支)。它和其它 branch 的区别在于:

  1. 新建的仓库中的第一个 commit 会被 master 自动指向;
  2. git clone 时,会自动 checkoutmaster

Git 的 master 分支并不是一个特殊分支。 它就跟其它分支完全没有区别。 之所以几乎每一个仓库都有 master 分支,是因为 git init 命令默认创建它,并且大多数人都懒得去改动它。

“origin”的含义?

“origin” 指远程仓库,指向的是当你运行 git clone 时默认的远程仓库名字

可以运行 git remote 命令,查看你已经配置的远程仓库服务器

git remote

# 会显示需要读写远程仓库使用的 Git 保存的简写与其对应的 URL
git remote -v

他们没有特别的含义,只是使用的比较广泛的名字。查看.git/config可以看到它们的含义

Git从原理到实践的全面指南 | 概念篇

.git隐藏文件夹

选取一个文件夹,打开后执行git init,即创建一个新的git仓库。可以在文件夹下看到一个.git文件(要打开隐藏文件才能看见)

.git文件说明

.git文件包含了几乎所有 Git 存储和操作的东西。 如若想备份或复制一个版本库,只需把这个目录拷贝至另一处即可。

新初始化的 .git 目录的典型结构如下

$ ls -F1
config description  HEAD   
hooks/  info/ objects/  refs/ 

Git从原理到实践的全面指南 | 概念篇

文件跟踪

在git仓库中,你工作目录下的每一个文件都不外乎这两种状态:已跟踪未跟踪

  • 已跟踪文件:就是 Git 已经知道的文件。

    已跟踪的文件是指那些被纳入了版本控制的文件,在上一次快照中有它们的记录,在工作一段时间后, 它们的状态可能是未修改,已修改或已放入暂存区

  • 未跟踪文件:工作目录中除已跟踪文件外的其它所有文件

    未跟踪文件,它们既不存在于上次快照的记录中,也没有被放入暂存区。

初次克隆某个仓库的时候,工作目录中的所有文件都属于已跟踪文件,并处于未修改状态,因为 Git 刚刚检出了它们, 而你尚未编辑过它们。

编辑过某些文件之后,由于自上次提交后你对它们做了修改,Git 将它们标记为已修改文件。 在工作时,你可以选择性地将这些修改过的文件放入暂存区,然后提交所有已暂存的修改,如此反复。

Git从原理到实践的全面指南 | 概念篇

使用git status可以查看文件状态

1)比较干净的工作目录

Git从原理到实践的全面指南 | 概念篇

2)存在未跟踪的文件

可以看到Untracked files文件,即存在未跟踪的文件,意味着 Git 在之前的快照(提交)中没有这些文件。根据提示可以看到使用 "git add"能让文件变为被跟踪的状态

Git从原理到实践的全面指南 | 概念篇

3)跟踪文件

现在根据提示操作git add README.md

现在README.md文件出现在 Changes to be committed 这行下面,说明是已暂存状态

Git从原理到实践的全面指南 | 概念篇

4)暂存已修改文件

工作目录中有一个已被跟踪的文件demo1.txt,修改了这个文件后,会看到下面内容

可以看到demo1.txt文件出现在了Changes not staged for commit 这行下面,说明已跟踪文件的内容发生了变化,但还没有放到暂存区。

Git从原理到实践的全面指南 | 概念篇

要暂存这次更新,需要运行 git add 命令。

这是个多功能命令:

  • 可以用它开始跟踪新文件,
  • 或者把已跟踪的文件放到暂存区,
  • 还能用于合并时把有冲突的文件标记为已解决状态等。

将这个命令理解为“精确地将内容添加到下一次提交中”而不是“将一个文件添加到项目中”要更加合适。

现在运行这个命令 git add demo1.txt可以看到现在两个文件都已暂存,下次提交时就会一并记录到仓库。

Git从原理到实践的全面指南 | 概念篇

取消暂存

可以看到在 “Changes to be committed” 文字正下方,提示使用 git restore --staged <file>… 来取消暂存。 所以,我们可以这样来取消暂存某个文件,比如 demo1.txt 文件:

 git restore --staged demo1.txt

5)暂存非暂存同时出现

现在我们准备提交了,但是突然发现漏写了东西,所以对demo1.txt文件又进行了一点改动,这个时候还可以直接提交吗?不妨在运行git status看看。

可以看到demo1.txt文件同时出现在了暂存区和非暂存区,这是为什么呢?

因为Git 只不过暂存了你运行 git add 命令时的版本。 如果你现在提交,demo1.txt 的版本是你最后一次运行 git add 命令时的那个版本,而不是你运行 git commit 时,在工作目录中的当前版本。 所以,运行了 git add 之后又作了修订的文件,需要重新运行 git add 把最新版本重新暂存起来

Git从原理到实践的全面指南 | 概念篇

如果觉得每次都要先git add比较麻烦,可以在提交的时候给 git commit 加上 -a 选项,Git 就会自动把所有已经跟踪过的文件暂存起来一并提交,从而跳过 git add 步骤

# 这很方便,但是有时这个选项会将不需要的文件添加到提交中。
git commit -a

更简单的查看

从上面git status 命令输出到的结果是比较详细的,如果想简洁点查看可以使用命令

git status -s

输出中有两栏,左栏指明了暂存区的状态,右栏指明了工作区的状态。

Git从原理到实践的全面指南 | 概念篇

  • ?? :新添加的未跟踪文件

  • A :新添加到暂存区中的文件

  • M :修改过的文件

例如,上面的状态报告显示:

  • README.md是新添加到暂存区中的文件。
  • demo1.txt文件已修改,暂存后又作了修改,因此该文件的修改中既有已暂存的部分,又有未暂存的部分。
  • demo3.txt是新添加的未跟踪文件

总结

目前为止,git中的重要概念我们都了解,下篇我们会接着说git在实战中的基础用法和高级用法以及常见问题的解决方案。

参考资料


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐