背景 从git push origin HEAD:refs/for/xxxxx说起,这条命令是在使用mk ak 提交review代码发现的,对HEAD和refs/for/xxxxx 所代表的含义充满了好奇,可能有些人能理解HEAD是.git/HEAD,那refs/for/xxxxx是什么东西呢?
常规 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 # fetch > git fetch # 源端分支映射 > git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/develop remotes/origin/master # 切一个本地分支mydevelop,源端分支为 develop > git checkout -b mydevelop refs/remotes/origin/develop # 查看config文件 > cat .git/config ... [remote "origin"] 本地源 名称 url = git@github.com:JuneLeo/CardControl.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [branch "mydevelop"] remote = origin merge = refs/heads/develop
通过config文件和 refs目录,我们发现
config 为git配置文件, [remote “origin”] :对应.git/refs/remotes/origin
refs/heads 为本地分支,.git/refs/remote/origin为源端分支
fetch = +refs/heads/:refs/remotes/origin/ ,+ 号告诉 Git 即使在不能快进的情况下也要(强制)更新引用
1 2 3 4 5 6 7 8 9 10 11 12 # 查看 refs源端映射的本地引用目录 > ls .git/refs heads remotes tags > ls .git/refs/heads // heads 为本地分支 master mydevelop > ls .git/refs/remotes //源端 heads目录映射(refs/heads/*:refs/remotes/origin/* ) origin > ls .git/refs/remotes/origin // 参考后面pack-refs HEAD
上述我们查看了.git/refs 目录,
heads 为本地分支目录
remotes 为源端映射目录
1 2 3 4 5 6 7 8 9 # 查看 HEAD 本地的当前分支 > cat .git/HEAD ref: refs/heads/mydevelop //当前分支为mydevelop # 查看 packed-refs > cat .git/packed-refs # pack-refs with: peeled fully-peeled sorted 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/origin/develop 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/remotes/origin/master
其他一些目录信息
HEAD 保存着当前分支
packed-refs (后面讲解)
我们继续看 git push origin HEAD:refs/for/xxxxx
origin: 本地源端目录映射.git/refs/remote/origin
HEAD: 本地当前分支 .git/HEAD
refs/for/xxxxx 源端 for/xxxxx 目录(或者标签)
这条命令会将HEAD提交到源端的for/xxxxx目录(或者标签)下
变形 为了排除干扰 ,我们把项目删除,重新克隆,并且重新添加remote
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 > git remote add other git@github.com:JuneLeo/CardControl.git > cat .git/config ... [remote "origin"] url = git@github.com:JuneLeo/CardControl.git fetch = +refs/heads/*:refs/remotes/origin/* [remote "other"] url = git@github.com:JuneLeo/CardControl.git fetch = +refs/*:refs/remotes/other/* ... # 修改 other [remote "other"] url = git@github.com:JuneLeo/CardControl.git fetch = +refs/*:refs/remotes/other/* > git fetch other remote: Enumerating objects: 216, done. remote: Counting objects: 100% (184/184), done. remote: Compressing objects: 100% (56/56), done. remote: Total 158 (delta 57), reused 150 (delta 50), pack-reused 0 Receiving objects: 100% (158/158), 13.56 KiB | 4.52 MiB/s, done. Resolving deltas: 100% (57/57), completed with 9 local objects. From github.com:JuneLeo/CardControl * [new ref] refs/for/develop -> other/for/develop * [new branch] develop -> other/heads/develop * [new branch] master -> other/heads/master * [new ref] refs/pull/1/head -> other/pull/1/head * [new ref] refs/pull/10/head -> other/pull/10/head * [new ref] refs/pull/11/head -> other/pull/11/head * [new ref] refs/pull/11/merge -> other/pull/11/merge * [new ref] refs/pull/2/head -> other/pull/2/head * [new ref] refs/pull/3/head -> other/pull/3/head * [new ref] refs/pull/4/head -> other/pull/4/head * [new ref] refs/pull/5/head -> other/pull/5/head * [new ref] refs/pull/6/head -> other/pull/6/head * [new ref] refs/pull/7/head -> other/pull/7/head * [new ref] refs/pull/8/head -> other/pull/8/head * [new ref] refs/pull/9/head -> other/pull/9/head * [new ref] refs/song/develop -> other/song/develop > git branch -a * master remotes/origin/HEAD -> origin/master //本地存在 remotes/origin/develop // 本地仓库不存在 remotes/origin/master // 本地仓库不存在 remotes/other/for/develop // review标签 remotes/other/heads/develop remotes/other/heads/master remotes/other/pull/1/head remotes/other/pull/10/head remotes/other/pull/11/head remotes/other/pull/11/merge remotes/other/pull/2/head remotes/other/pull/3/head remotes/other/pull/4/head remotes/other/pull/5/head remotes/other/pull/6/head remotes/other/pull/7/head remotes/other/pull/8/head remotes/other/pull/9/head remotes/other/song/develop
通过上面的命令,我们发现把+refs/heads/:refs/remotes/other/ 改为+refs/*:refs/remotes/other/*,会将源端refs目录下的所有文件映射到本地refs/remote/other 目录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 > ls .git/refs/remotes origin other > ls .git/refs/remotes/other //此处为源other 映射目录 for heads pull song > ls .git/refs/remotes/other/heads //other/heads目录 develop master > ls .git/refs/remotes/origin // origin 等同 other/heads HEAD > cat .git/refs/remotes/origin/HEAD ref: refs/remotes/origin/master
通过比较发现 origin目录下只有HEAD文件,且HEAD中存储了源端映射信息;我们再次分析
+refs/:refs/remotes/other/ ,将 源端refs 映射到refs/remotes/other目录
+refs/heads/:refs/remotes/origin/ 将源端refs/heads 映射到refs/remotes/origin目录
为什么.git/refs/remotes/origin只有一个HEAD目录?而不是develop和master文件???
1 2 3 4 5 6 7 8 9 10 > git remote add juneleo git@github.com:JuneLeo/CardControl.git > cat .git/config ... [remote "juneleo"] url = git@github.com:JuneLeo/CardControl.git fetch = +refs/heads/*:refs/remotes/juneleo/* > ls .git/refs/remotes/juneleo develop master
通过添加新的源juneleo,我们发现refs/remotes/juneleo目录下有develop和master文件,那这又是为什么呢?
打包标头和标签以便高效的存储库访问 1 2 3 4 5 6 7 8 9 > cat .git/packed-refs # pack-refs with: peeled fully-peeled sorted 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/origin/develop 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/remotes/origin/master > git pack-refs --all > ls .git/refs/remotes origin
执行 git pack-refs –all,我们发现 refs/remotes目录中的other和juneleo目录消失了,这又是为什么呢??
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 > cat .git/packed-refs # pack-refs with: peeled fully-peeled sorted 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/heads/develop_origin 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/heads/master 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/heads/master_other 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/juneleo/develop 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/remotes/juneleo/master 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/origin/develop 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/remotes/origin/master 073b759c5f2b2054086010a5259be14c9c85a6bf refs/remotes/other/for/develop 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/other/heads/develop 720c57484f53f66ce310a3f303cffe6d0af954c1 refs/remotes/other/heads/master effecabb3c199b271deb2f00a7d0dc9846a9317c refs/remotes/other/pull/1/head 7bc68c59ba42beeffce0521c32eb017bf22c9e1b refs/remotes/other/pull/10/head 5aca94c89c5d873acd0169a2c98910d00986fa45 refs/remotes/other/pull/11/head f73286b0a6beca997c40ac7472ae7ce28067b3f1 refs/remotes/other/pull/11/merge 68faf293665a0431cd88dfd00df1ed013281595b refs/remotes/other/pull/2/head d34af6f4d72385d06aa32a8d8ed23f2ae8847ad6 refs/remotes/other/pull/3/head f70a3be25c18a267ec404c2325fdb4bf803e42dc refs/remotes/other/pull/4/head d34af6f4d72385d06aa32a8d8ed23f2ae8847ad6 refs/remotes/other/pull/5/head 6be27fa9215b3576c20f32a25ee740b91cc338bf refs/remotes/other/pull/6/head fa82c7d436b599b359c756be00e23181c32c7a7a refs/remotes/other/pull/7/head b394a520bd70fd042378fc2bc2ec81c75cb84622 refs/remotes/other/pull/8/head c1d0d352abb347eea4af9bfec999eba5a72305ba refs/remotes/other/pull/9/head 073b759c5f2b2054086010a5259be14c9c85a6bf refs/remotes/other/song/develop
再次打开.git/packed-refs目录,我们发现这个文件里面多了很多映射关系
传统上,分支存储在refs 目录中,尽管许多分支提示往往会经常更新,但是大多数标记和某些分支提示从未更新过。当存储库中有成百上千个标签时,这种“每个引用一个文件”的格式既浪费存储空间,又会损害性能。
git pack-refs 用于通过将引用存储在单个文件中来解决存储和性能问题 .git/packed-refs。当传统.git/refs目录层次结构中缺少ref时,将在此文件中查找该引用,并在找到该引用时使用。
分支更新总是.git/refs目录层次结构下创建新文件 。
1 2 3 4 5 6 git pack-refs --all -- pack all refs --no-all -- do not pack all refs --no-prune -- do not remove loose refs after packing them --prune -- remove loose refs after packing them