git
git是一个分布式版本控制系统。他最初的版本是 Linus Torvalds 开发的用于管理 Linux 内核开源社区的版本控制系统。
安装 git
所有的 Linux 发行版一定回包含 git 工具,它算是软件开发的一个核心的基础工具了,我们只需要使用对应的包管理工具安装即可:
MacOS 上安装 Xcode Command Line Tools
会自动帮我们安装好 git,也可以安装 brew 来安装 git:
Windows 直接从官网下载Git for Windows来安装即可。当然通过 Chocolatey 包管理工具安装也可以,或者直接使用 WSL 的 Linux 环境。
初次使用配置
安装 git 后需要运行git config来定制 git 环境:
git config --global user.name "hncjygd"
git config --global user.email hncjygd@163.com
git config --global core.editor nvim
之后我们可以通过 git config --list
来查看当前的配置。
git 基本使用流程
获取 Git 仓库
有两种方式来获取 Git 仓库(repository):
记录每次更新到仓库
之后我们需要在仓库中工作了,说白了就是对文件进行增删改。当我们完成一个一个阶段的目标,想要记录下这个阶段的成果就需要将它们提交到仓库。
首先需要明确,工作目录中的每一个文件无外乎两种状态: 已跟踪
或 未跟踪(Untracked)
。它们的区别很简单,已跟踪的文件就是 Git 已经知道的文件,除了已跟踪的就是未跟踪的文件。
当我们修改一个 已跟踪
的文件后该文件会被标记为 已修改(Modified)
,git 的一个创新就是提供了一个 暂存区(Staging Area/index)
,所有需要提交的文件(未跟踪/已修改 -> 已跟踪)都首先提交到 暂存区(Staging Area/index)
中此时文件被打上 已暂存(Staged)
标签。之后需要正式提交到仓库中,此时文件就是 已跟踪
的,并且是 未修改(Unmodified)
的它们也被称为 已提交(committed)
。
Tips
只要进入 暂存区
中,就是 已跟踪
了,而对于 已跟踪
以及 未修改
的文件就说明他已经被正式提交到 git 仓库中了。
Tips
已跟踪
是针对于修改而言的,例如一个文件已经提交,如果此时修改,那么这个文件的当前修改是 未跟踪
的
因此整个流程实际上就是不断修改文件的状态的过程:
而文件则是在三个地方流转,他们也是 git 进行记录操作的流程:
Working Directory
: 工作目录,他们是我们文件操作的直接目录,所有的修改都是在这里完成的,如果仅仅在这里修改文件他将是已修改(modified)
但是未跟踪
的。如果确定修改完成就需要git add到暂存区,此时文件就 已跟踪
了并且是已暂存
的,如果想要放弃修改可以git restore来使用暂存区中的内容覆盖本地的修改 Staging Area
: 暂存区,他仅仅是一个快照或者是指针,因此也被成为 index。该指针指向下次提交的快照。add 到这里的文件就是已暂存
的了,如果已经敲定了没有问题,可以通过git commit来提交到 Git 仓库,如果有问题我们还可以git restore --staged来取消暂存 .git directory(Repository)
: Git 仓库,这里的文件就表示已经真正的纳入 git 的版本管理,当然在 git 的世界中对已跟踪
的文件永远是有后悔药的,如果当前提交出现了问题需要回滚此时就可以使用git reset来回滚到上一次或上几次的提交
而为了随时获取文件的状态变化需要两个命令git status和git diff
分支管理
git 的分支是一个杀手锏级的功能,这可能也是他能够在众多版本控制系统中脱颖而出的原因。Git 处理分支的方式非常轻量,对分支的创建、删除、修改操作几乎都是瞬间完成。因为Git 分支本质上就是一个只想最后一次提交对象的指针,理解这句话是理解 Git 分支的核心。
git 中的所有文件被保存为 blod 对象,他们的目录结构由 tree 对象保存,而 tree 对象已经一些提交信息共同组成了提交对象:
每一次提交都会产生一个新的提交对象,他其中会包含上一次提交对象的指针,这样就做出了提交链条:
而分支、标签等都非常简单就是指向提交对象的指针:
这其中比较特殊的就是 HEAD,他永远指向当前分支,即你想要使用什么分支就将他指向哪个分支。也就是通过 HEAD 指针来决定我们目前工作环境的基准。
因此整个分支操作实际上就是创建、移动、删除指针的过程:
- 通过git branch
来创建一个新的分支,它实际上就是创建了一个指针指向当前 HEAD 指向的提交 - 注意此时我们依然工作在当前旧分支上,如果想要在新的分支上工作需要使用git switch
来切换分支,改命令的效果就是将 HEAD 指针指向 <branchname>
即可 - 之后我们尽管我们的操作都是 HEAD 指针,但是 HEAD 指向了分支指针因此所有的操作就像 HEAD 背着分支指针一起进行的
- 删除分支也非常方便git switch -d
,实际上就是删除了一个指针
Tips
可看到创建、切换、删除等对应的就是创建、移动、删除指针的过程及其轻量化。
贮藏(stash)
有时后但你在一个分支上进行了一部分工作,此时接收到了一个新的任务需要在另一个分支上完成。我们还不想讲该分支的任务提交,为了解决这个问题就需要git stash。
所谓的 stash 会将工作目录的脏状态(包括已跟踪文件的修改以及暂存的改动)保存到一个栈上,可以在任何时候的任何分支上应用这些改动。整个操作流程如下:
git stash -u -m <msg>
来存储整个工作区修改和暂存区git switch <branch>
切换到其他分支来工作git switch main
工作完成后切换回来git stash pop
应用最新的贮藏来接着之前的工作
合并(merge)和变基(rebase)
我们以一个实际的工作流来介绍如何进行分支合并:
- 开发一个网站 -> 存在一个主分支为当前网站的主版本
- 为了实现某个新的用户需求,创建一个分支 -> 新分支用于开发新需求
- 这个分支上开展工作 -> 新需求没有完成之前不能提交到主分支上
- 存在主分支 master,