Skip to content

git

git是一个分布式版本控制系统。他最初的版本是 Linus Torvalds 开发的用于管理 Linux 内核开源社区的版本控制系统。

安装 git

所有的 Linux 发行版一定回包含 git 工具,它算是软件开发的一个核心的基础工具了,我们只需要使用对应的包管理工具安装即可:

Bash
sudo dnf install git
sudo apt install git

MacOS 上安装 Xcode Command Line Tools 会自动帮我们安装好 git,也可以安装 brew 来安装 git:

Bash
brew install git

Windows 直接从官网下载Git for Windows来安装即可。当然通过 Chocolatey 包管理工具安装也可以,或者直接使用 WSL 的 Linux 环境。

初次使用配置

安装 git 后需要运行git config来定制 git 环境:

Bash
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):

  1. 使用git init来初始化一个 git 仓库
  2. 从其他服务器git clone一个已经存在的 git 仓库

记录每次更新到仓库

之后我们需要在仓库中工作了,说白了就是对文件进行增删改。当我们完成一个一个阶段的目标,想要记录下这个阶段的成果就需要将它们提交到仓库。

首先需要明确,工作目录中的每一个文件无外乎两种状态: 已跟踪未跟踪(Untracked)。它们的区别很简单,已跟踪的文件就是 Git 已经知道的文件,除了已跟踪的就是未跟踪的文件。

当我们修改一个 已跟踪 的文件后该文件会被标记为 已修改(Modified),git 的一个创新就是提供了一个 暂存区(Staging Area/index),所有需要提交的文件(未跟踪/已修改 -> 已跟踪)都首先提交到 暂存区(Staging Area/index) 中此时文件被打上 已暂存(Staged) 标签。之后需要正式提交到仓库中,此时文件就是 已跟踪 的,并且是 未修改(Unmodified) 的它们也被称为 已提交(committed)

Tips

只要进入 暂存区 中,就是 已跟踪 了,而对于 已跟踪 以及 未修改 的文件就说明他已经被正式提交到 git 仓库中了。

Tips

已跟踪 是针对于修改而言的,例如一个文件已经提交,如果此时修改,那么这个文件的当前修改是 未跟踪

因此整个流程实际上就是不断修改文件的状态的过程:

lifecycle

而文件则是在三个地方流转,他们也是 git 进行记录操作的流程:

areas

  1. Working Directory: 工作目录,他们是我们文件操作的直接目录,所有的修改都是在这里完成的,如果仅仅在这里修改文件他将是 已修改(modified) 但是 未跟踪 的。如果确定修改完成就需要git add 到暂存区,此时文件就 已跟踪 了并且是 已暂存 的,如果想要放弃修改可以git restore 来使用暂存区中的内容覆盖本地的修改
  2. Staging Area: 暂存区,他仅仅是一个快照或者是指针,因此也被成为 index。该指针指向下次提交的快照。add 到这里的文件就是 已暂存 的了,如果已经敲定了没有问题,可以通过git commit来提交到 Git 仓库,如果有问题我们还可以git restore --staged 来取消暂存
  3. .git directory(Repository): Git 仓库,这里的文件就表示已经真正的纳入 git 的版本管理,当然在 git 的世界中对 已跟踪 的文件永远是有后悔药的,如果当前提交出现了问题需要回滚此时就可以使用git reset来回滚到上一次或上几次的提交

而为了随时获取文件的状态变化需要两个命令git statusgit diff

分支管理

git 的分支是一个杀手锏级的功能,这可能也是他能够在众多版本控制系统中脱颖而出的原因。Git 处理分支的方式非常轻量,对分支的创建、删除、修改操作几乎都是瞬间完成。因为Git 分支本质上就是一个只想最后一次提交对象的指针,理解这句话是理解 Git 分支的核心。

git 中的所有文件被保存为 blod 对象,他们的目录结构由 tree 对象保存,而 tree 对象已经一些提交信息共同组成了提交对象:

commit and tree

每一次提交都会产生一个新的提交对象,他其中会包含上一次提交对象的指针,这样就做出了提交链条:

commit and parents

而分支、标签等都非常简单就是指向提交对象的指针:

branch and history

这其中比较特殊的就是 HEAD,他永远指向当前分支,即你想要使用什么分支就将他指向哪个分支。也就是通过 HEAD 指针来决定我们目前工作环境的基准。

因此整个分支操作实际上就是创建、移动、删除指针的过程:

  1. 通过git branch 来创建一个新的分支,它实际上就是创建了一个指针指向当前 HEAD 指向的提交
  2. 注意此时我们依然工作在当前旧分支上,如果想要在新的分支上工作需要使用git switch 来切换分支,改命令的效果就是将 HEAD 指针指向 <branchname> 即可
  3. 之后我们尽管我们的操作都是 HEAD 指针,但是 HEAD 指向了分支指针因此所有的操作就像 HEAD 背着分支指针一起进行的
  4. 删除分支也非常方便git switch -d ,实际上就是删除了一个指针

Tips

可看到创建、切换、删除等对应的就是创建、移动、删除指针的过程及其轻量化。

贮藏(stash)

有时后但你在一个分支上进行了一部分工作,此时接收到了一个新的任务需要在另一个分支上完成。我们还不想讲该分支的任务提交,为了解决这个问题就需要git stash

所谓的 stash 会将工作目录的脏状态(包括已跟踪文件的修改以及暂存的改动)保存到一个栈上,可以在任何时候的任何分支上应用这些改动。整个操作流程如下:

  1. git stash -u -m <msg> 来存储整个工作区修改和暂存区
  2. git switch <branch> 切换到其他分支来工作
  3. git switch main 工作完成后切换回来
  4. git stash pop 应用最新的贮藏来接着之前的工作

合并(merge)和变基(rebase)

我们以一个实际的工作流来介绍如何进行分支合并:

  1. 开发一个网站 -> 存在一个主分支为当前网站的主版本
  2. 为了实现某个新的用户需求,创建一个分支 -> 新分支用于开发新需求
  3. 这个分支上开展工作 -> 新需求没有完成之前不能提交到主分支上

basic branching

  1. 存在主分支 master,