简介
引用官方介绍,如下,
Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency.
git 在本地保存了完整的版本库,既可以在本地独立管理版本,也可以和远程版本库进行同步。
本文以本地为例,介绍了 git 的基本使用。
安装
以 ubuntu-22.04 LTS 为例,安装命令如下,
1 | sudo apt install git-all |
安装完后,可通过git --version
查看 git 版本,
其他操作系统安装 git 的命令可以参考官方文档:https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
必要配置
使用 git 前,必须设置user.name
和user.email
。
这两个属性用来标识用户身份,会出现在每一次的提交信息中。
设置配置
设置user.name
和user.email
命令如下,
1 | git config --global user.name "<your-name>" |
其中,--global
表示属性的作用范围。git config
中一共有三个作用范围,
--local
,只对当前项目生效;--global
,对当前用户的所有项目生效;--system
,对所有用户的所有项目生效。
注意,
- 如果不指定作用范围,默认是
--local
; - 属性覆盖优先级:
--local
>--global
>--system
。
查看配置
- 查看所有级别的属性(包括
--local
、--global
和--system
),
1 | git config --list |
- 查看指定级别的属性,
1 | git config --list --local |
1 | git config --list --global |
1 | git config --list --system |
取消配置
1 | git config --global --unset <property-name> |
此外,
--global
还可以换成--local
或者--system
,表示撤销某个级别的属性设置;- 默认是
--local
。
初始化项目
- 从零开始创建项目,
1 | git init <project-root-directory-name> |
此时,名为<project-root-directory-name>
的目录会被自动创建,并且在该目录下会自动创建.git
目录用来存储元数据。
- 将已有项目添加 git 管理,
1 | cd <project-root-directory> |
即,在项目根目录下执行git init
。
此时,会在当前目录(即,项目根目录)下创建.git
目录用来存储元数据。
文件管理
文件状态
在 git 管理的项目中,一个文件的某个版本(或某次修改),存在于如下几个位置,
- 工作目录
项目目录下,.git
之外的目录即为工作目录。
之所以称之为“工作目录”,是因为用户可以在这里新建、修改、删除文件或目录,之后通过命令将变化提交给 git。
工作目录中的文件有如下状态,
1. untracked:新创建的文件会是 untracked 状态,此时,需要通过命令将新文件提交给 git 管理;
2. modified:被 git 管理的文件,在工作目录中内容被修改了,就会处于 modified 状态,此时,需要通过命令将变化更新给 git;
3. deleted:被 git 管理的文件,在工作目录中被删除了,就会处于 deleted 状态,此时,需要通过命令将删除更新给 git。
- 暂存区
工作目录中的文件如果有变化(新建、修改、删除),需要通过命令将这种变化更新给 git。通常,并不是修改完一个文件就立即提交到版本库;而是将修改完的文件放入暂存区,待本次所有相关的文件都修改好后一次性提交到版本库。
当文件被提交到暂存区后,git 就会为之创建一个 blob 对象存储当前版本的文件内容。
git 对象(包括 blob 对象)位于 git 元数据目录.git/objects/
下。
- 版本库
当文件变化(新建、修改、删除)需要作为历史版本被持久化保存时,此时,变化是通过命令提交到版本库。之后,可以通过回退版本找回当前文件内容。
可以从暂存区提交到版本库(这是比较合理的方式),也可以直接从工作目录提交到版本库(新建的文件不能直接提交到版本库,需要先添加到暂存区)。
当文件被提交到版本库后,git 会为此次提交创建一个 tree 对象,该 tree 对象保存了以本次提交的视角看到的项目目录下的目录结构和文件内容。
git 对象(包括 tree 对象)位于 git 元数据目录.git/objects/
下。
状态转换
工作目录 –> 暂存区
1 | git add <file-name>... |
或
1 | git add --all |
前者是将指定文件添加到暂存区(即,交给 git 管理);后者是将所有新文件添加到暂存区。
可以通过git status
查看文件状态。
暂存区 –> 版本库
1 | git commit <file-name>... -m "some message for describing this commit" |
或
1 | git commit -m "some message for describing this commit" |
前者是将指定文件从暂存区提交到版本库;后者是将暂存区所有文件提交到版本库。
可以通过git log --all --graph
查看所有历史提交。
此后,被提交到版本库的文件就多了一个历史版本,之后可以随时回到任意一个历史版本。
版本库 –> 暂存区
版本库的最新版本 –> 暂存区
1 | git reset --mixed |
或
1 | git reset -- <file-name>... |
前者是用版本库中的最新版本恢复暂存区中的所有文件;后者是恢复指定文件。
此时,
- 暂存区中的相关文件会与版本库中的最新版本保持一致;
- 暂存区中没被提交到版本库的修改退回到了工作目录中。
版本库的指定版本 –> 暂存区
1 | git reset --mixed <commit-id> |
或
1 | git reset <commit-id> -- <file-name>... |
前者是使用版本库中指定 commit(某个历史版本)恢复暂存区中所有文件;后者是恢复指定文件。
注意,
恢复所有文件时,版本库中指定<commit id>
后面的所有 commit 都会被丢弃,这会导致后面的历史版本丢失,相当于重置了最新的历史版本;而恢复部分文件时,版本库中的所有 commit 保持不变,版本库中之前的最新版本仍是现在的最新版本,从而不会导致历史版本丢失。
版本库 –> both 暂存区 and 工作目录
版本库的最新版本 –> both 暂存区 and 工作目录
1 | git reset --hard |
用版本库中的最新版本恢复暂存区和工作目录中的所有文件。
此时,
- 暂存区和工作目录中的文件与版本库保持一致;
- 暂存区和工作目录中未被提交到版本库的修改将被丢弃。
注意,
使用--hard
时,只能恢复所有文件,不能只恢复指定文件。
版本库的指定版本 –> both 暂存区 and 工作目录
1 | git reset --hard <commit-id> |
使用版本库中指定 commit(某个历史版本)恢复暂存区中的所有文件。
注意,
- 使用
--hard
时,只能恢复所有文件,不能只恢复指定文件; - 使用
--hard
时,版本库中的最新版本会重置为指定版本,这会导致指定版本之后的所有版本都丢失。
暂存区 –> 工作目录
方式一,使用版本库-->暂存区
的命令,从而暂存区中未提交到版本库中的修改会被放回工作目录。
方式二,撤回暂存区中的修改到工作目录,
1 | git restore --staged <file-name>... |
此时,会将从工作目录提交到暂存区的修改撤回到工作目录。
撤销工作目录中的修改
1 | git restore <file-name>... |
工作目录 –> 版本库
1 | git commit -a -m "some message for describing this commit" |
这里的-a
是指将工作目录中的修改直接提交到版本库,从而省去了添加到暂存区的步骤。
分支
分支的应用场景
包括但不限于如下场景,
- 一个分支是一个版本
例如,应用程序 v1.0 和 v2.0 都在持续更新版本,那么,v1.0 和 v2.0 可以分别作为两个分支。
- 一个分支是一个开发阶段
例如,对于同一个版本的应用程序,可能分为测试版和稳定版,那么,
1. 测试版和稳定版可以分别作为两个分支;
2. 测试版经过一系列迭代之后并入稳定版。
- 一个分支是一个特性开发
例如,应用程序在主线开发之外需要引入一个新的特性、或者修复一个紧急 bug,此时,
1. 在主线之外创建一个分支;
2. 在特性开发完成、或者 bug 修复之后,将该分支并入主线。
- 一个分支是一个开发模块
例如,应用程序分为前端开发和后端开发,那么,
1. 前端开发和后端开发可以分别作为两个并行推进;
2. 当前端开发和后端开发都完成后,将两个分支合并到一起。
查看分支
列出所有分支名称,
1 | git branch |
其中,*
表示当前分支。
创建分支
- 创建新分支,但不切换到新分支,
1 | git branch <new-branch-name> <commit-id> |
如果不指定<commit-id>
,默认从当前分支的最新 commit 创建分支。
- 创建分支,并且切换到新的分支,
1 | git checkout -b <new-branch-name> <commit-id> |
如果不指定<commit-id>
,默认从当前分支的最新 commit 创建分支。
删除分支
1 | git branch -d <branch-name> |
注意,
- 使用
-d
时,要删除的分支必须已经并入了当前分支,否则删除失败; - 如果确定不再需要待删除的分支、并且不想将其并入当前分支,可以使用
git branch -D <branch-name>
; - 待删除的分支不能是当前分支,需要离开这个分支、然后才能删除它。
切换分支
1 | git checkout <branch-name> |
合并分支
1 | git merge <branch-name> |
将<branch-name>
指定的分支并入到当前分支。
比较不同
比较工作目录和暂存区的不同
- 比较所有文件
1 | git diff |
- 比较指定文件
1 | git diff -- <file-name>... |
比较工作目录和指定 commit 的不同
- 比较所有文件
1 | git diff <commit-id> |
- 比较指定文件
1 | git diff <commit-id> -- <file-name>... |
比较暂存区和指定 commit 的不同
- 比较所有文件
1 | git diff --cached <commit-id> |
- 比较指定文件
1 | git diff --cached <commit-id> -- <file-name>... |
比较两个 commit 的不同
- 比较所有文件
1 | git diff <commit-id> <commit-id> |
- 比较指定文件
1 | git diff <commit-id> <commit-id> -- <file-name>... |
–end–