系列文章目录
手把手教你安装Git,萌新迈向专业的必备一步
GIT命令只会抄却不理解?看完原理才能事半功倍!
快速上手GIT命令,现学也能登堂入室
- 系列文章目录
- 一、GIT HELP
- 1. 命令文档
- 2. 简要说明
- 二、配置
- 1. 配置列表
- 2. 增删改查
- 3. 配置范围
- 4. 常用设置
- 三、仓库创建
- 1. 初始化(init)
- 2. 克隆(clone)
- 四、核心命令
- 1. 添加至暂存区(add)
- 2. 提交(commit)
- 3. 推送(push)
- 4. 拉取(pull)
- 5. 分支(branch)
- 6. 检出(checkout)
- 7. 合并(merge)
- 8. 记录(log)
- 五、易混命令对比
- 1. fetch 和 pull
- 2. merge 与 rebase
- 总结
经过前两期的学习,相信大家对GIT本身,以及其基本原理与模型有了一定的了解。本期就让我们开始学习GIT的命令,GIT的命令总体分为上层命令与底层命令。底层命令直接操控GIT的底层存储机制,操作风险性大还不友好,一般不使用。所以开发者对于开发者而言,只需要专注于上层命令即可,这也是我们今天要学的内容
📕作者简介:战斧,从事金融IT行业,有着多年一线开发、架构经验;爱好广泛,乐于分享,致力于创作更多高质量内容
📗本文收录于 GIT 专栏,有需要者,可直接订阅专栏实时获取更新
📘高质量专栏 云原生、RabbitMQ、Spring全家桶 等仍在更新,欢迎指导
📙Zookeeper Redis kafka docker netty等诸多框架,以及架构与分布式专题即将上线,敬请期待
一、GIT HELP
1. 命令文档
一切都有个开始,我们现在学GIT命令,最首先要学的就是git help
,该命令用来显示任何命令的 Git 自带文档。
它有三种打开方式
git help <verb>
git <verb> --help
man git-<verb>
比如我想了解 add
命令,当我输入 git add --help ,就会打开一个关于 add 命令的操作文档
git add --help
2. 简要说明
当然,如果我们不需要打开文档,只想快速了解下这个命令,只要在命令后加 -h 即可,还是拿 add 举例:
git add -h
二、配置
1. 配置列表
GIT的配置项非常的多,从功能到界面颜色都能设置,不过对于大多数同学,需要用的时候再做具体了解也不迟。一般情况下,我们可以用 git config --list 来进行配置的查看
# 查看配置列表
git config --list
2. 增删改查
当我们明确要修改某个配置的时候,我们往往会先查看该配置的当前值,其格式如 : git config <variable>
# 查看 user.name
git config user.name
zhanfu
如果我们想删除某个配置的设置,其格式如下:git config --unset <variable>
# 取消 user.name 的配置
git config --unset user.name
如果我们想修改,或是新增一个新的配置,我们可以这么使用:git config <key> <value>
# 新增一个叫user.aabb的配置
git config user.aabb ccdd
git config user.aabb
ccdd
3. 配置范围
GIT支持多种作用域范围的配置,即使同一个配置名,在不同的范围等级也是可以不一样的,目前其支持的主要作用域有
- system:系统,配置存储于$(prefix)/etc/gitconfig
- global:全局,配置存储于$XDG_CONFIG_HOME/git/config
- local:本地(也是默认作用域),配置存储于$GIT_DIR/config
- worktree:工作区,配置于$GIT_DIR/config.worktree
每个作用域都对应一个命令行选项:--system
, --global
, --local
, --worktree
读取选项时,指定范围将仅从该范围内的文件中读取选项。编写选项时,指定范围将写入该范围内的文件,可以看这样的示例:
# 分别在全局和本地设置用户名
git config --global user.name zhanfu
git config --local user.name zhanfu1
# 查询用户名,显示的本地作用域配置
git config user.name
zhanfu1
4. 常用设置
尽管GIT的配置项非常的多,但大多数人不需要全部掌握,我们在这给出一些常用的配置
- 用户信息
git config --global user.name "Your Name"
git config --global user.email you@example.com
这里使用了 --global
,代表这是一个全局设置,但是如果你想在对接不同仓库时(比如电脑上同时有公司仓库和个人项目仓库),使用不同的个人信息可能更合适,此时你需要在对接不同仓库时,使用如下配置
git config user.name "Your Name"
git config user.email you@example.com
- 编辑工具
如果在linux上使用GIT,没有视窗,我们可以设置其全局编辑工具
git config --global core.editor "vim"
- 禁用Git自动换行
git config --global core.autocrlf false
三、仓库创建
Git支持两种方式来创建仓库。 一种是从网络上或者其他地方拷贝一个现有的仓库,另一种就是在一个目录中创建一个新的仓库
1. 初始化(init)
当我们想在某个目录创建GIT仓库,只需在此目录下执行 git init
命令即可,其会自动在当前目录中创建一个新的 Git 仓库,以此开始对版本控制的跟踪。
git init
该命令可以跟带一些参数,常用的有:
# 从给定模板目录创建新的 Git 仓库,默认模版为(/usr/share/git-core/templates)
git init --template=<template-directory>
# 创建仓库时,为自动建立的分支命名。若不设置,默认分支名通常为“master”
git init --template=<template-directory>
需要注意的是,git init
命令只在仓库初始化时使用一次,创建仓库后就不需要重复执行。
2. 克隆(clone)
如果你想从远程服务器克隆下来一个仓库,那你需要使用到git clone
命令,比如如果我想克隆Gitee上的一个开源框架Sa-Token的仓库 其url为 https://gitee.com/dromara/sa-token.git。那么我们可以这样使用
git clone https://gitee.com/dromara/sa-token.git
执行完上述步骤后,Git 会克隆远程仓库到本地,并在当前目录下创建一个与远程仓库同名的文件夹
从原理上来说,git clone
实际上是一个封装了其他几个命令的命令。 它创建了一个新目录,切换到新的目录,然后 git init 来初始化一个空的 Git 仓库, 然后为你指定的 URL 添加一个(默认名称为 origin 的)远程仓库(git remote add),再针对远程仓库执行 git fetch,最后通过 git checkout 将远程仓库的最新提交检出到本地的工作目录
当然,他也有很多参数可选,一般来说常用的有以下几个
# -b 克隆后切换当前分支到 dev,如果不设置,默认当前分支为远程仓库的HEAD位置
git clone -b dev https://gitee.com/dromara/sa-token.git
# --single-branch 只克隆一个分支,此参数需要配合 -b,才能明确是要克隆哪个分支
git clone --single-branch -b dev https://gitee.com/dromara/sa-token.git
四、核心命令
如果说前面的命令用的频率较少,那么接下来我们就讲一些常用的核心命令
1. 添加至暂存区(add)
前面的文章,我们已经提到过暂存区的概念。本地仓库只接收暂存区里的东西,所以使用git add
命令把文件添加进暂存区是必需的,比如我们想添加两个文件
git add ./file1.txt ./temp/file2.txt
当然,有时候我们不想一个个指定文件,那可以用下面的命令
# 不带参数,只有目录,代表把本目录所有修改过,和新建的文件加入暂存区。但被你删除的文件不会
git add .
# 更新暂存区已有的,即包括修改过的,和被你删除的,但不包括新建的文件
git add -u
# All 代表所有文件,包括你新增的、修改的、删除的
git add -A
另一个常见的参数是交互参数 -i,当你输入下面命令时,会出现交互
git add -i
在交互状态下,你可以输入小命令前面的数字来执行,这些小命令意思分别如下:
status - 展示修改的文件位置
update - 把工作区里修改的文件加入暂存区
revert - 撤销暂存区里的修改
patch - 选择性添加
diff - 比较暂存区与本地仓库上一次内容之间的差异
add untracked - 把还没被git管理的文件添加到索引库中
quit - 退出git add -i命令系统
2. 提交(commit)
如果你的暂存区已经有了内容,接下来你就可以将暂存区的内容提交至本地仓库,这个时候我们需要用到:
git commit
当然,一般情况下,我们每次提交都应当写一写提交信息,用于描述本次提交的作用
# 提交时添加提交信息
git commit -m "这是我的第一次提交"
3. 推送(push)
在完成提交后,我们的本地仓库就包含了我们的代码了,接下来,如果你对接了远程仓库,就可以把这部分内容从本地仓库推送至远程仓库了,这个时候我们要用到 git push
命令
git push <远程主机名> <本地分支名>:<远程分支名>
如果本地分支名与远程分支名相同,则可以省略冒号,如我们要推送本地仓库的 dev 分支到远程仓库 dev 分支
git push origin dev
接下来我们列举一些参数供大家学习
# 设置远程仓库的 dev 分支为默认 push 目标,后续 push 可以省略参数
git push -u origin dev
# 强制推送,即将本地仓库的修改强制覆盖远程仓库的修改
git push -f origin dev
# 推送所有分支到远程仓库,包括新分支和删除的分支
git push --all origin
# 删除远程仓库的 dev 分支
git push origin --delete dev
4. 拉取(pull)
git pull
命令用于从远程仓库中获取最新版本的代码并合并到本地仓库中,效果相当于git fetch
+ git merge
,一般会这么使用
git pull <远程主机名> <远程分支名>:<本地分支名>
同push一样,如果本地分支名与远程分支名相同,则可以省略冒号,那么远程仓库 dev 分支拉取到本地 dev 就是如下:
git pull origin dev
需要注意的是,pull会同时更新本地工作区,但不会更新暂存区。同时,因为这里有着一个合并操作,所以其有着两种方式合并:rebase
或者 merge
(默认)
# 将远程仓库的提交合并到本地仓库时使用 rebase (变基)方式,以使合并的提交历史更清晰和整洁
git pull --rebase origin dev
5. 分支(branch)
git branch
是git命令中的一个分支管理命令,用于列出、创建、重命名、删除等分支操作,它的主要用法,我进行了一个罗列:
git branch:列出所有本地分支。
git branch -r:列出所有远程分支。
git branch -a:列出所有本地和远程分支。
git branch <branchname>:创建一个新的分支。
git branch -d <branchname>:删除一个分支。
git branch -D <branchname>:强制删除一个分支。
git branch -m <newbranchname>:重命名一个分支。
git branch -vv:显示本地分支与远程分支的对应关系。
git branch -u <upstream>:将本地分支与远程分支建立跟踪关系。
git branch --merged:列出已经合并到当前分支的分支。
git branch --no-merged:列出未合并到当前分支的分支。
git branch --contains <commit>:列出包含指定提交的分支。
git branch --set-upstream-to=<upstream>:设置当前分支跟踪另一个远程分支。
例如,使用 git branch 命令可以列出所有本地分支:
$ git branch
branch1
* master
branch2
其中带 * 号的就是当前所在分支
6. 检出(checkout)
checkout
的用法就是检出,但是它检出的内容多种多样,我们也进行一个列举:
- 切换分支
git checkout <branch_name>
- 创建新分支并切换到该分支,相当于执行以下两个命令:
git branch <new_branch_name>
和git checkout <new_branch_name>
git checkout -b <branch_name>
- 恢复某个文件的修改,即撤销对某个文件的修改,还原到最近一次提交的状态。
git checkout <file_name>
- 恢复某个历史版本,切换到指定的历史版本。可以使用git log命令查看各个历史版本的commit id
git checkout <commit_id>
- 恢复某个文件在历史版本中的状态,将指定文件回滚到指定的历史版本中的状态。
git checkout <commit_id> <file_name>
7. 合并(merge)
一般我们的仓库都会有多个分支,比如当我们每做一个任务,就从开发分支(dev)新建一个分支(iss95)用来做任务,做完以后自然要合并。所以会用到git merge
命令,注意,该命令是将其他分支的修改合并到当前分支,所以我们得先checkout 到 dev ,再进行合并
git checkout dev
git merge iss95
常用的git merge参数有不少,我们挑几个来说:
- squash
将所有合并提交压缩到一个新的提交中。这个选项通常用于将一个长期开发的功能分支合并到主分支中,比方说在iss95分支我们提交了很多次,如果我们直接git merge iss95
,在后续我们进行历史查询时,就会把 iss95 的这么多次提交全查出来。这是因为合并后,F提交点相当于以后有两个父节点了
而如果我们使用的是命令 git merge iss95
,就会把我们在c、d做的修改合并成一次,并且放在我们的暂存区中,等待我们的手动提交,如下
git merge --squash dev
git commit -m "Merged dev_branch changes"
- no-ff
--no-ff
的意思为禁用快进合并,这将创建一个新的合并提交,即使分支已经可以直接合并。这样可以保证在历史记录中保留正确的分支信息。快速合并
是GIT的一个机制,如果我们合并的两个分支,一个是另一个的祖先,那么并不会真正的“合并”,而是取了个巧,具体情况如下:
master 是 iss95 祖先分支,如果我们要把 iss95 合并进 master,GIT就只会把分支master移动到iss95的位置,这就是所谓的“快速合并”
如果使用了 --no-ff
,就是禁用快速合并。此时,就要求它必须会新建一个提交点。这样,我们就能得到更准确的记录了
8. 记录(log)
git log
经常在追溯问题时使用,可以查看提交的历史,它常配合使用的参数如下
# 显示每个提交的详细修改信息。
git log -p
# 查看指定作者的提交记录
git log --author="author name":查看指定作者的提交记录
五、易混命令对比
1. fetch 和 pull
- fetch
·fetch·只是将远程代码库的代码更新到本地代码库,不会自动合并代码。它会将远程代码库的提交记录下载下来,并更新远程分支。如果要将远程代码库的提交记录合并到本地代码库,需要手动执行·git merge·命令。
fetch的命令是:
git fetch [remote]
remote是远程代码库的名称,例如origin。如果省略remote,则默认使用origin。
- pull
pull
会首先执行fetch
命令,然后自动将远程代码库的代码合并到本地代码库。如果有冲突,需要手动解决冲突并提交更改。如果没有冲突,pull会自动提交合并的更改。
pull的命令是:
git pull [remote] [branch]
remote是远程代码库的名称,branch是要拉取的分支名称。如果省略branch,则默认拉取当前分支。
- 对比
因此,pull
和fetch
的主要差异是:pull
会自动将远程代码合并到本地代码库,而fetch
只是将远程代码库的代码更新到本地代码库。
pull
可能会导致冲突,需要手动解决冲突并提交更改,而fetch不会导致冲突。
一般来说,如果你不确定要合并代码是否会导致冲突,可以先使用fetch
命令拉取远程代码库的代码,然后手动执行git merge
命令进行合并。如果你确定合并代码不会导致冲突,可以直接使用pull命令拉取远程代码库的代码并自动合并到本地代码库。
2. merge 与 rebase
这两者都可以用于合并不同的分支,假设这是我们目前的分支情况
- merge
当我们切换至 master 分支,然后将 experiment 使用 merge
合并进来时
git checkout master
git merge experiment
最终会产生一次新的提交C5,这种提交叫“合并提交”,与一般的提交不同,它有两个父节点,也就是说以后我们在分支 master 上还能看到*experiment * 的痕迹
- rebase
而如果使用rebase
,其实就是将提交到某一分支上的所有修改都移至另一分支上,就好像“重新播放”一样。
它的原理是首先找到这两个分支(即当前分支 experiment、变基操作的目标基底分支 master) 的最近共同祖先 C2,然后对比当前分支相对于该祖先的历次提交,提取相应的修改并存为临时文件, 然后将当前分支指向目标基底 C3, 最后以此将之前另存为临时文件的修改依序应用
- 对比
这两种整合方法的最终结果没有任何区别,但是变基使得提交历史更加整洁,所以说,整合的最终结果所指向的快照始终是一样的,只不过提交历史不同罢了。 变基是将一系列提交按照原有次序依次应用到另一分支上,而合并是把最终结果合在一起。
- 变基的风险
需要注意的是,在某些复杂场景下,rebase
反而会导致提交历史混乱,具体的例子可以参考官方给出的一个示例:变基,因此,在无法防范的情况下,使用 merge
是最省心的
总结
今天我们讲了几乎都是GIT常用的核心命令,希望大家能都掌握。虽然在日常工作中,开发者的很多操作都是由可视化工具来完成的,但是也不能完全忘记命令的使用,这样即使后续出了问题,也能根据现象推断出大概解决方向,而不是越弄越糟。在
GIT专栏后面的内容中,我们还会讲解一些冲突场景的预防及解决、常用的GIT工具等等。希望大家能够喜欢