我正在参加「掘金·启航计划」
我们每天都使用git,但是对于git似乎还停留在基本命令上,这显然不够卷。
git命令分为高层命令
和底层命令
,熟练掌握高层命令满足工作需要,了解底层命令增加对git亲切感,不再可怕。
当然这个系列,我也会说明一些难点问题:
-
merge 和 rebase 区别
-
每次版本迭代,怎么做分支重建
-
项目运行几年后,每次clone都好几个G,怎么实现不影响提交记录缩小项目
git高层命令
下面会出现HEAD
,HEAD是什么呢,就是指向当前分支的指针,理解为当前工作区
我们先来复习下经常使用到的几个命令:
最基本必会
命令 | 描述 |
---|---|
git init | 初始化空git项目 |
git config --global user.name "xxxx" | 配置全局账户,也可设置 user.email 邮箱 |
git clone 项目地址 | clone项目 |
git add ./ | 提交暂存区 |
git commit -m "提交信息" | 提交到版本库 |
git push | 推送到远程服务器 |
git checkout -b 本地分支名 | 切换到分支,从当前分支建立本地新分支,并切换到新分支,注意并未关联到远程分支 |
git checkout -b 本地分支名 远程分支名(不带remotes) | 从远程分支建立新分支,并关联。如git checkout -b xxx origin/xxx |
git config --global credential.helper cache | 保存密码 |
git config core.ignorecase false | 大小写敏感,默认是不敏感 |
git config --system core.longpaths | windows解决路径过长问题 |
git merge test | 如当前在master分支,是将test分支覆盖到master分支上来合并 |
git rebase master test | 不论当前在哪个分支,是将master分支作为基础,把test分支修改内容做暂存,以master变基后,并合并到test分支上 |
查看
命令 | 描述 |
---|---|
git status | 查看当前状态,文件未跟踪、已修改、已暂存、已提交 |
git log | 查看历史记录,未折叠 |
git log --oneline | 查看历史记录,折叠简略一行 |
git reflog | 查看历史所有操作,包含撤销等,只有HEAD变化都记录 |
git branch | 查看所有本地分支 |
git branch -a | 查看所有分支,包括远程分支 |
git checkout 分支名 | 切换到本地分支,如果本地没有这个分支,而远程有这个分支,那么会自动检出远端分支,并建立跟踪 |
git stash list | 查看所有存储栈中代码 |
git diff | 查看未暂存的修改 |
git diff --cache | 查看未提交的暂存 |
git tag | 查看本地所有tag |
git ls-remote --tags remote | 查看远程所有tag |
git log --oneline --decorate --graph --all | 查看整个项目的分支图 |
git remote -v | 查看所有远程源 |
git branch -vv | 查看当前分支与远程分支的关系 |
添加
命令 | 描述 |
---|---|
git branch 分支名 | 新建本地分支 |
git merge 本地分支名 | 本地分支合并到当前分支上 |
git fetch 远程仓库名 | 拉取远程仓库数据,注意只是拉取到你本地仓库,不会合并到你工作目录,后续可手动合并 |
git pull 远程仓库名 | 拉取远程代码,相当于git fetch + git merge |
git stash | 将新代码压入存储栈存起来,一般切分支前用到 |
git stash pop | 将最新一次压栈代码弹出来,并移除栈顶 |
git stash apply stash@2 | 应用某次栈中代码,但不移除栈顶 |
git stash drop stash@2 | 丢弃某个存储 |
git tag tag名字 | 打标签 |
git tag -a tag名字 -m tag注释 | 打标签带注释 |
git push origin --tags | 推送所有本地tag到远程 |
git remote add 仓库别名 仓库地址 | 添加新远程项目地址,一个项目可以添加多个远程项目,git remote add origin xxxx |
git push 仓库别名 远程分支 | 推送到一个远程分支 |
git push -u origin --all | 推送所有分支到origin服务器 |
git push -u origin --tags | 推送所有标签到origin服务器 |
git branch -u 远程分支 | 本地分支和远程跟踪分支建立关联关系,如git branch -u origin/xxx |
修改
命令 | 描述 |
---|---|
git commit --amend | 修改上次提交对象描述信息 |
git reset --soft HEAD~ 或者 commithash | 只HEAD和分支名移动到上次提交对象,文件不动,暂存区不动 |
git reset --mixed HEAD~ 或者 commithash | HEAD和分支名移动到上次提交对象,文件不动,暂存区取消 |
git reset --hard HEAD~ 或者 commithash | HEAD和分支名移动到上次提交对象,文件取消,暂存区取消 |
删除
命令 | 描述 |
---|---|
git branch -d 分支名 | 删除分支,如果有未提交的会删除失败 |
git branch -D 分支名 | 强制删除分支 |
git tag -d tag名字 | 删除本地tag |
git push origin :tag名字 | 删除远程tag |
git push origin --delete 远程分支名 | 删除远程分支 |
git remote prune orinin --dry-run | 列出远程分支已删除,但是本地仍然在跟踪的分支 |
git remote prune origin | 删除上述列出的本地跟踪分支 |
git branch --unset-upstream | 删除本分支的跟踪分支关系 |
底层命令
要理解git就要先知道三区域和三对象:
-
git区域分为
工作区
、暂存区
、版本库
-
git对象分为
git对象
、tree对象
(树对象)、commit对象
(提交对象)
三区域
当我们用git init
创建一个git项目时,会生成.git
目录,里面内容如上图
-
objects
文件夹内就是版本库,存放实际二进制文件,可以看作是一个键值对的数据库,我们每次提交记录,每个文件修改都会完全加密拷贝进去,所有就算项目运行了N年,你依然可以时光穿梭到任意一次提交上看代码,是完整项目的快照
-
index
二进制文件就是暂存区内容,存放当前项目的每个文件指向objects
里面的文件hash值(即objects中文件名) -
工作区就是外面项目代码
三对象
刚说到objects
版本库里面是实际的二进制文件,里面存放的其实就是三对象文件
-
git对象
二进制文件就是项目每个源代码文件的二进制内容,文件名是hash值,是高层名称git add
时产生,因为git对象
只有文件内容,没有文件名等信息,所以需要tree对象
来组织git对象
-
tree对象
二进制文件记录项目目录结构,包含git对象
的hash值和源文件路径名称等信息,也是git add
时产生,因为tree对象
虽然有了文件内容和文件信息,但是没有描述信息,没有关联到上次commit,所以需要commit对象
来描述 -
commit对象
二进制文件就是执行git commit -m
时,记录这个tree对象
hash值和父commit,描述信息等
虽然说,就是由我们git add
和git commit
产生,但是实际是调用不同底层命令,做二进制文件和hash值,下面我们就来说下这几个底层命令。
新建
底层新增就四个命令:
-
hash-object
生成git对象 -
update-index
和write-tree
生成tree对象 -
commit-tree
生成commit对象
命令 | 描述 |
---|---|
git hash-object -w 文件名 | 在版本库objects中生成git对象 二进制文件和hash值 |
git hash-object 文件名 | 不生成文件,只是看hash值 |
echo "test content" | git hash-object -w --stdin | 从输入流读取生成二进制文件和hash值 |
git update-index --add 实际文件名 | 将新文件直接加入暂存区,会先到版本库生成hash,再加入暂存区 |
git update-index --add --cacheinfo 100644 git对象hash 实际文件名 | 将版本库某个文件加入暂存区跟踪,文件已在版本库跟踪的就不用--add参数,100644普通文件,100755可执行文件,12000符号链接 |
git write-tree | 将暂存区执行快照,生成tree对象文件 |
echo "提交信息" | git commit-tree 树hash值 -p 父commit对象hash值 | 生成commit对象信息 |
查看
既然,已经生成了 git对象
、tree-对象
、commit对象
,因为都是二进制文件,所以无法直接打开,提供了查看命令:
命令 | 描述 |
---|---|
git ls-files -s | 查看暂存区,即index 二进制文件内容 |
git cat-file -p 文件hash值 | 查看二进制文件内容,文件hash值在objects 文件夹内,注意完整hash是带文件夹两位字符 |
git cat-file -t 文件hash值 | 查看二进制文件类型,git对象,tree对象,commit对象 |
存储与远程跟踪分支
存储的命令是git stash
相关,上面已经说到,这里只是提出来而已。
我主要是说下远程跟踪分支,首先git branch 分支名
作用已经知道是从当前分支建立新本地分支,需要知道工作区内容是当前本地分支,而远程跟踪分支的远程分支内容,之间需要建立对应关系,不然push
和fetch
时不能知道该怎么推/拉代码,git branch -u origin/xxx
的作用是就是让本地分支和远程跟踪分支建立关联关系。
否则,像有时git push --set-upstream origin 分支名
的报错就会出现,使用git branch -u origin/xxx
即可。
也可以在新建分支时写git checkout -b 本地分支名 远程分支名(不带remotes)
, 像从远程分支建立新分支,并关联。如git checkout -b xxx origin/xxx,直接从远程分支建立本地分支名,并建立跟踪分支关联。也可以写成git checkout --track 本地分支名
同样作用。
git branch -vv
可以查看当前分支与远程分支关联关系
实际操作命令
新建文件到版本库生成git对象
上图所有命令:
新建文件test.txt
echo "hello world!" > test.txt
test.txt加入版本库
git hash-object -w test.txt
返回 => a0423896973644771497bdc03eb99d5281615b51
版本库加入暂存区记录
git update-index --add --cacheinfo 100644 a0423896973644771497bdc03eb99d5281615b51 test.txt
查看暂存区
git ls-files -s
返回 => 100644 a0423896973644771497bdc03eb99d5281615b51 0 test.txt
查看版本库二进制文件原始内容
git cat-file -p a0423896973644771497bdc03eb99d5281615b51
返回 => hello world!
查看版本库二进制文件对象类型
$ git cat-file -t a0423896973644771497bdc03eb99d5281615b51
返回 => blob
git对象到tree对象
上图所有命令:
暂存区执行快照生成tree对象
git write-tree
返回 => 5d56cf9b9843c20d7b29bf6374501f4f48841210
查看版本库中tree对象内容
git cat-file -p 5d56cf9b9843c20d7b29bf6374501f4f48841210
返回 => 100644 blob a0423896973644771497bdc03eb99d5281615b51 test.txt
查看tree对象类型
git cat-file -t 5d56cf9b9843c20d7b29bf6374501f4f48841210
返回 => tree
tree对象到commit对象
tree对象快照到commit对象
echo "提交信息" | git commit-tree 5d56cf9b9843c20d7b29bf6374501f4f48841210
说明:这里是第一次commit,所有没有父commit,没有加-p参数
返回 => d77e46bacb883271b78a3950c7d1d9f7bc900aaa
查看版本库中commit对象类型
git cat-file -p d77e46bacb883271b78a3950c7d1d9f7bc900aaa
返回 =>
tree 5d56cf9b9843c20d7b29bf6374501f4f48841210
author rootegg 1664618340 +0800
committer rootegg 1664618340 +0800
提交信息
查看版本库commit对象类型
git cat-file -t d77e46bacb883271b78a3950c7d1d9f7bc900aaa
返回 => commit
至此三区域三对象说清楚了,完毕!