1. git基本介绍
认识 .git 文件
- 创建一个新的git仓库(git-demo),观察 .git 文件的基本组成
- HEAD
向当前正在工作的分支,是通过ref指向的一个引用
cat .git/HEAD
ref: refs/heads/master
表示当前分支为master
-
config
保存了本地仓库的配置信息,输入cat .git/config查看config里面的内容 -
description
仓库的描述信息 -
hooks
执行的一些钩子脚本,.sample默认不生效,去掉.sample以后才会生效。
exit 1: 表明没有通过校验
exit 0: 通过校验
-
info/exclude
exclude可以与.gitignore实现相同的功能。区别是.gitignore是团队共享,.git/info/exclude是共个人专用 -
objects
包含一系列重要的对象:tree、blob、commit、tag。
objects/pack:压缩文件,通过git gc进行压缩 或者 通过git push推送到远程仓库都会形成压缩文件。 -
refs
表示一系列的引用,包含heads、remote、tags等目录;在刚初始化的项目里面只包含heads、tags。如果是一个全新的空仓库,这两个目录都将是空的
heads:表示一系列的本地分支
remote:远程仓库分支
tags:tag标签
git的三个区
- 工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。
- 索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次commit被提交到Git仓库。(
git add以后) - Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。(
git commit以后)
配置相关
git config -l 查看当前配置
git config -l --global 查看全局配置
当不想使用global里面的user信息时,就可以添加项目用户
git config user.name "demo"
git config user.email "demo@demo.com"
通过cat .git/config查看新的config信息
2. git add
blob对象
首先在命令行输入echo aaa > 1.txt 产生一个文件
通过 git add 1.txt 将 1.txt 添加到索引区。可以通过git ls-files查看当前索引区的内容
查看
.git/objects里面的内容
我们会发现
.git/objects 多了一个文件,我们可以通过下面的命令查看该文件的一些信息
git cat-file -p 72943a # 查看文件的具体内容
git cat-file -t 72943a # 查看文件的类型
git cat-file -s 72943a # 查看文件在磁盘上的大小
可以看出这个文件的类型时一个
blob,里面的内容是aaa,在磁盘上的大小是4kb。其实这个blob对象就是 1.txt 内容对应的二进制压缩文件。这个文件的文件名就是一个sha1值
sha1 值
通过git hash-object查看一个内容的对应的sha1值
echo aaa | git hash-object -w --stdin
生成hash值以后,写入到标准输入
这个sha1其实是将内容按照格式
blob 字符长度\0内容 最终转换而成的
echo -e "blob 4\0aaa" | shasum
3. git commit
执行 git commit -m "first commit"产生一次提交。然后查看.git/objects
会发现里面多了2个文件。分别查看这两个文件的类型和内容
de73fa6a
类型:commit
详情:设置的提交者信息以及提交时的备注信息
dff4011
类型:tree
详情:包含文件名称与blob对象的映射
此时形成的关系为
接下来添加几个特殊的文件
- 一个空文件夹
- 一个文件夹包含一个文件
- 一个文件夹包含多个文件
依次执行下面的命令
mkdir file1 file2 file3
echo bbb > file2/2-1.txt
echo ccc > file3/3-1.txt
echo ddd > file3/3-2.txt
此时的目录结构是
此时完成完成git add,git commit
空文件夹并不会形成记录,查看 452cd1a 的内容
可以发现有一个
parent属性指向上一次提交的commitId。此时形成的关系是
commit通过parent就能形成一条链表。文件夹对应的就是一个tree对象。通过树结构,就能还原每次commit对应的所有的文件。
此时,查看HEAD相关的内容
可以发现
HEAD指向master的452cd1
4. 分支和tag
执行下面的命令创建一个dev分支和tag
git checkout -b dev
git tag -a v1.0.0 -m "test tag"
可以发现 refs里面添加了tag和branch信息,查看tag号 v1.0.0 的相关信息
tag的类型就是tag
tag对应的是一个固定的commitId,branch对应的是变化的commitId。tag和branch都可以理解为一个指针。
当删除
tag和branch时,并不会删除该指针特有的blob对象。
5. 文件解压缩、垃圾文件
文件压缩
当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会进行压缩操作。
- 查看压缩文件情况
git verify-pack -v .git/objects/pack/pack-xxx.idx
文件解压
- 解压文件
当执行解压操作的时候要把pack文件移动到其他地方
mv .git/objects/pack/pack-xxx.pack .git/
解压命令(注意:这儿是<)
git unpack-objects < .git/pack-xxx.pack
解压的文件会被放到 objects 里面
git add 产生的垃圾文件
大多数情况下,执行git gc通常会去执行git prune
git prune 删除没有被引用的对象
git prune -n查看执行git prune将被删除的对象
git fsck --unreachable 查看没有被引用的对象
在master上面进行如下操作
echo bbb > 2.txt
git add -A
rm -rf 2.txt
echo ccc 3.txt
git add -A
rm -rf 3.txt
这样就会产生2条blob类型的垃圾对象
可以发现通过执行git gc并没有帮我们移除垃圾对象。此时就需要手动执行git prune
删除分支产生的垃圾文件
当我们在新分支创建了新内容,并产生了很多该分支单独拥有的对象。然后发现该分支没有用时,删了了该分支,此时就会产生很多垃圾对象。
我们进行如下操作
git checkout -b temp
echo "temp">temp.txt
git add temp.txt
git commit -m "添加temp.txt"
git checkout master
git branch -D temp
此时我们如果需要删除temp分支所产生的一些提交信息,就可以执行下面的命令
git prune无效,使用git gc时,会将这些文件正常进行压缩(这些文件并不会被识别成unreachable)
git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 \
-c gc.rerereresolved=0 -c gc.rerereunresolved=0 \
-c gc.pruneExpire=now gc "$@"
6. fast-forward、git merge、git rebase
fast-forward
当分支master是分支dev的祖先节点时,切换到分支master,执行 git merge dev,此时就会发生fast-forward,分支master会直接指向dev所在的位置
fast forward 以后会产生一个OARIG_HEAD文件,里面的内容是原分支以前指向的commit。(可以通过git reset OARIG_HEAD 回滚到合并前的状态 )
git rebase
在dev上运行 git rebase master ,其实就是把dev的操作在master上面执行一次,最终 dev 分出来的第一次commit的parent会指向master的最终的指向。注意master的commit不会改变,但是dev上面新的commitId都会相应发生改变。
此时就满足了fast forward 的条件,切换到master,执行 git merge dev ,此时就是 fast forward merge 了。此时如果还想找到F对应的 commitId,可以使用git reflog查看操作日志.
git rebase会隐藏掉合并信息,所以在多人协作的时候尽量不要使用,在单人开发时为了分支的干净可以进行使用。
7. 远程仓库
远程仓库就是一个.git文件
创建一个远程仓库
git init --bare .
至此,我们生成了一个远程仓库地址,它的 SSH 地址是:
// 前面的git表示用户是git
git@x.xxx.xxx.xxx:/home/www/website/myBlog.git
8. git fetch、git pull
git fetch
通过git fetch 同步远程仓库信息以后,远程信息会保存到 refs/remotes/origin 下面。注意如果是通过git clone的项目,默认的远程分支会以packed-refs的形式存在,通过删除该文件,然后再执行 git fetch,这样远程分支信息就会同步进refs/remotes/origin
- 执行完
git fetch以后会增加.git/FETCH_HEAD文件,同时当前分支对应的远程分支的commit对象对应的sha1值会排在FETCH_HEAD文件的第一行
cat .git/FETCH_HEAD
fd2a2d7dae0176f08507623dbae2e661d1e39d9d branch 'master' of gitee.com:feiying-tf/git-test
fd2a2d7dae0176f08507623dbae2e661d1e39d9d not-for-merge branch 'dev' of gitee.com:feiying-tf/git-test
当使用git pull 的时候,首先会执行 git fetch,然后使用 git merge 合并第一行对应的分支。
git pull 会产生 .git/ORIG_HEAD,通过 ORIG_HEAD 可以回滚到合并前的状态
- 注意只有
master默认与远程的master进行过关联,其他分支都必须与远程仓库进行关联,比如:
- 在推送的时候使用
git push origin test -u - 使用
git branch --set-upstream-to=origin/dev dev
然后就可以在test分支上面直接运行git pull或者git push,。
- 我们可以在
.git/config中查看与远程产生关联的分支。
9. git worktree
- 目的:在本地进行多个分支工作
git worktree list查看工作树列表- 使用:
git worktree add ../wrapper master在上一级目录下创建wapper目录,检出master - 处理完毕以后删除多余的工作树
git worktree remove wrapper # 删除wrapper这个工作树
10. git 切换分支,将当前分支的修改带到另一个分支的情况
如果有被重写的内容会被提示
提示产生的条件:
dev修改一个master也有的文件,并且dev与master必须没有处于同一条提交链上。