如果非得了解下git系统... - 实践篇
git的定义是一个内容寻址文件系统。内容、寻址、文件、系统,该来的总会来的…
本文旨在通过实践来介绍.git文件夹中的目录及文件功能,属git基础知识。但在此基础上可解决各git使用过程中可能遇到的问题,如“.git文件夹占用空间大”,“git如何找回丢失的对象(提交)”,”git diff 对比依据是什么”等,
话不多说,撸起袖子就是干,来看看 .git 是个啥样,这些个货色都是干嘛的。
# 初始化git,查看内容
git init 产生一个.git隐藏文件夹
cd .git
ls -F1
# 初始化时的.git长这样
# HEAD
# config
# description
# hooks/
# info/
# objects/
# refs/
# 日常工作中的.git大概长这样
# COMMIT_EDITMSG
# config
# description
# hooks/
# index
# info/
# logs/
# objects/
# refs/
随着之后的多种 git操作 ,还会存在如 MERGE_HEAD 、 MERGE_MODE等和 COMMIT_EDITMSG 类似功能的文件,branches(分支信息)、lost-found(存储被悬挂起/丢失的提交对象)、packed-refs(压缩后的refs记录)等和logs、objects类似功能的文件夹。
以上面的.git为例做个简单的介绍:
COMMIT_EDITMSG 最近一次的 commit edit message ;
# 编写提交信息的两种姿势
git commit
# 自动打开文件编辑,在文件中输入信息即可
git commit -m msg
# 信息都会被保存到 COMMIT_EDITMSG
# 如需修改提交信息,不可直接编辑COMMIT_EDITMSG,可执行以下命令
git commit --amend
# 自动打开文件编辑,在文件中修改信息即可
description 描述文件,打开后里面提醒该为git仓库创建个描述(Unnamed repository; edit this file 'description' to name the repository.)。
config 文件包含项目特有的配置选项,如一些常用项:
[core] ignorecase 是否忽略文件大小写;
[remote "origin"] url 配置远程仓库地址;
[remote "origin"] fetch 远程分支映射关系;
[user] name 用户名
[user] email 邮箱
[alias] 命令别名配置 : cmt = commit
抑或更多其他config参数…
全局配置文件在 ~/.gitconfig ,Windows应该是在Users/Administrator/.gitconfig。
info/ 文件夹用以存储一些有关git仓库的信息,如exclude
# 包含一个全局性排除(global exclude)文件,用以放置那些不希望被记录在 .gitignore 文件中的忽略模式(ignored patterns);
echo for git ignore > git-ignore
echo for git exclude > git-exclude
echo git-ignore > .gitignore
git status # On branch test
# Untracked files:
# (use "git add <file>..." to include in what will be committed) # .gitignore
# git-exclude # git-ignore已被忽略,还有2个untracked的文件 cd .git
cd info/
vi exclude # 最后一行新增 git-exclude cd ../..
git status
# On branch test
# Untracked files:
# (use "git add <file>..." to include in what will be committed) # .gitignore # git-exclude 已被忽略,只有.gitignore还是untracked
除exclude文件外,还可能会有refs、grafts,attributes等文件
hooks/ 文件夹包含客户端或服务端的钩子脚本(hook scripts),如pre-commit,post-receive等:
vi .git/hooks/pre-commit
# 保存以下信息 第一行指定用什么执行
#!/bin/sh
echo "Message for pre commit";
exit ;
# 开执行权限
chmod +x .git/hooks/pre-commit # user+group+other 执行x(1)权限 ,备注 r(4,read),w(2,write),x(1,execute),-(0,no permission),s(special) touch commit-hook-test
git add .
git commit -m “pre-commit test“
# 你会看到以下信息
# Message for pre commit # 如果不exit,则继续执行,详情可参考.git/hooks/下的*.sample文件
# Message for pre commit
# [test 038e6ec] pre-commit test
# 1 file changed, 1 insertion(+), 1 deletion(-)
logs/ 放置git仓库操作记录的文件夹,包含HEAD文件 和 refs文件夹。
HAED 文件包含对 git分支 的操作记录,如
vi HEAD
# 99a10c283c33beed7f31c210a6c8b411d2a31085 5daf6094ea2cc60d17e947c0435096a4bdafe82d yeshou <yeshou@xxx.com> 1535082919 +0800 commit: rm files
# 5daf6094ea2cc60d17e947c0435096a4bdafe82d b8e02a5f9c2bf44342d15f5ea1e60ffd9434765a yeshou <yeshou@xxx.com> 1535087285 +0800 checkout: moving from test to master
# 先是删除文件后提交了次,再是由test检出到master
refs 文件夹包含 heads 文件夹,remote文件夹。heads 记录本地相关的各 git分支 操作记录,remote 记录远程仓库相关的各 git分支 操作记录
cd heads
ls
# master master分支操作记录
# test test分支操作记录 cd remote/origin
ls
# master 远程master分支操作记录
# test 远程test分支操作记录
HEAD 文件指示当前被检出(所在)的分支,如当前在test分支,文件内容则为ref: refs/heads/test。
index 文件是当前版本的文件索引,包含生成当前树(唯一确定的)对象的所虚信息,可用于快速比对工作树和其他提交树对象的差异(各commit和HEAD之间的diff),可用于存储单文件的多个版本以有效的解决合并冲突。可使用git ls-files 查看index文件内容。如:
git commit 的一次提交从index中的信息生成tree对象,将其存储在对象数据库中,并与本次新的commit做关联,产生本次commit的tree信息(下面的objects介绍中会提到commit和tree)。
refs/ (references) 文件夹存储指向数据(分支)的提交对象指针;其中 heads 文件夹记录内部文件对应名称的分支的提交对象;tags记录内部文件对应名称的标签的提交对象;remotes记录内部文件对应名称的远程仓库分支的提交对象;
举个例子:
cat .git/refs/heads/master
# ce1fed3fdbaf12e816e3028055f9feee57b33b45 当前master的提交记录
git checkout -b test # 检出一个新分支
find .git
# 多了个 .git/refs/heads/test 文件
git log # commit 63a85dcbc6978f2d43996f5bebc38993c2afadaa (HEAD -> test)
# Author: yeshou <yeshou@xxx.com>
# Date: Sat Aug 25 13:57:26 2018 +0800
#
# branch test : edit test : add line : write d # commit ce1fed3fdbaf12e816e3028055f9feee57b33b45 (master)
# Author: yeshou <yeshou@xxx.com>
# Date: Sat Aug 25 12:40:35 2018 +0800
#
# edit test : add line : write c cat .git/refs/heads/test
# 63a85dcbc6978f2d43996f5bebc38993c2afadaa 当前test的最近提交记录
cat .git/refs/heads/master
# ce1fed3fdbaf12e816e3028055f9feee57b33b45 依然是当前master的最近提交记录
另两者亦然。
objects/ 文件夹用以存储git仓库中的所有数据内容。
一步步来...
先看看这个文件夹里是怎么存数据内容的,再理解这些数据内容又是什么。
# 为了清晰的看明白objects文件夹中文件的生成,初始化.git
rm -rf .git
git init
cd .git
find .git # 这时候objects文件夹下只有pack和info 两个空文件夹
touch test
vi test
# 输入 a ,保存,退出
git add test
find .git
# objects 下多了个文件夹,且里面有文件
# .git/objects/44
# .git/objects/44/2406aa9341668f9c43c2d5378a777ad69324a0
验证下这个文件内容是什么,注意,这是个二进制球,呸…是文件,文明观球,呸…是观看。这里我们用传说中git中的手术刀( git cat-file )来解剖git文件。
git cat-file -p 442406aa9341668f9c43c2d5378a777ad69324a0
# 输出 a
9de29bb2d1d6434b8b29ae775ad8c2e48c5391 是个二进制文件,是git对象中的blob对象,它记录了当前版本的该文件的数据内容,并以SHA-1计算产生一个40个字符的校验和。 根据官方描述:这是一个 SHA-1 哈希值——一个将待存储的数据外加一个头部信息(header)一起做 SHA-1 校验运算而得的校验和。
继续操作,修改test
vi test
# 第二行输入 b ,保存,退出
git add test
find .git
# objects 下又多了个文件夹,且里面也有文件
# .git/objects/bf
# .git/objects/bf/daa0f1c3415c09d3080063911d155fd7259d18
这次的二进制文件的数据内容是 a (手动换行) b 。
继续走下去:
git commit -m “add test”
# wtf,怎么突然生出2个文件夹,来来来,看看内容
# .git/objects/3e
# .git/objects/3e/5f95cd5c4f0ff429522b0fdfeda9369f92d89c
# .git/objects/fd
# .git/objects/fd/1332e4e95f8a64682c1516e175abb66b6f6325
git cat-file -t fd1332e4e95f8a64682c1516e175abb66b6f6325
# commit
git cat-file -p fd1332e4e95f8a64682c1516e175abb66b6f6325
# tree对象、作者、提交者、提交日期、提交信息、父对象(有的话带一个或多个父对象)
# tree 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c
# author yeshou <yeshou@xxx.com> 1535168447 +0800
# committer yeshou <yeshou@xxx.com> 1535168447 +0800
# add dir-test
git cat-file -t 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c
# tree
git cat-file -p 3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c
# 100644 blob bfdaa0f1c3415c09d3080063911d155fd7259d18 test
git cat-file -p bfdaa0f1c3415c09d3080063911d155fd7259d18
# a (换行) b
3e5f95cd5c4f0ff429522b0fdfeda9369f92d89c 也是个二进制文件,是git对象中的tree对象,记录着blob标识符、路径名和在一个tree下的所有文件的元数据。
fd1332e4e95f8a64682c1516e175abb66b6f6325 又是个二进制文件,是git对象中的commit对象,它记录了当前版本的一次提交数据内容,包含tree对象、作者、提交者、提交日期、提交信息、父对象(有的话带一个或多个父对象)。
然后,pack文件夹是干嘛的?
随着objects文件夹下的文件夹和文件不断生成(也就是N多次的commit之后),objects文件夹明显会”长大”,这时开发者可以用 git gc 来对之前的操作的对象做整理压缩。
pack 文件夹内有2个文件 pack-(SHA-1).pack 和 pack-(SHA-1).idx 前者是以压缩形式存储之前记录对象的文件,后者用以存储访问索引的文件。
举个例子:
git gc
# Counting objects: 12, done.
# Delta compression using up to 4 threads.
# Compressing objects: 100% (4/4), done.
# Writing objects: 100% (12/12), done.
# Total 12 (delta 0), reused 0 (delta 0)
find .git
# 发现少了很多objects里的文件夹和文件,多了以下2个文件
# .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.pack
# .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx
git verify-pack -v .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx
# 列出之前存在objects里的所有操作数据内容
# 655a12c9b83a029bb46fa852ea15e6affd1587d8 commit 167 117 510
# ...
# 616dfdb2643c725fa1027ecef76d49d482d9e26d tree 32 43 670
# ...
# bfdaa0f1c3415c09d3080063911d155fd7259d18 blob 5 14 853
# 也可以通过后面加 | grep keyword 来搜索所需的内容,如下列出所有commit记录
git verify-pack -v .git/objects/pack/pack-2021ec3cb18c796fdfca8ef616fb6a20b1449ab1.idx | grep commit
git gc ( garbage collect )命令将会收集所有松散对象并将它们存入 pack,合并这些 pack 进一个大的 pack,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除,除此之外还会将所有引用 (references) 并入一个单独文件(上面有提到随着各种操作,.git下还会产生更多文件夹,.git中的packed-refs文件夹就是这时候产生的)。该命令可能通过修改配置中的 gc.auto 和 gc.autopacklimit 来调整操作阈值。注意:git gc 调用的也是 git prune ,如有需求也可关注这个命令。
至于"info文件夹是干嘛的?"这个问题还未知... 官网的描述也没看懂,也没查到或者在项目中实际出现这个文件夹有存在什么文件,要么等遇到再说?
至此git对象中的三个对象已经知道是咋回事了,还剩个tags对象,简单介绍下。
tags对象通常也是一个commit对象,指的是一个指定了开发者可读名称的一个特殊对象,如有需要也可通过 git cat-file 来解析探索。
其间关系大致如下:
|- commit aaaaa…
|- tree abbbb…
|- blob acccc… (可能是这次修改的)
|- blob adddd…(也可能是上次修改的)
|- tree aeeee…
|- blob affff… |- commit bbbbb…
关系图的话,这个是git官网的… 和上面的结构是一样的。
基于objects的介绍再回过头来看看”内容、寻址、文件、系统”便比较清晰了:以git对象作为内容,通过唯一的校验和寻址,文件形式存储的一个版本控制系统。
了解完这些,主要还是希望能够运用到实际生产中来解决问题。如 “项目中.git文件为什么这么大?怎么处理?"
可能的处理方案:
1. 执行 git gc ,如果压缩后能达到预期效果,则不做过多处理
2.针对历史记录中对某些大文件的引用,则删除对应引用的对象,操作如下
git gc
git count-objects -v
git verify-pack -v .git/objects/pack/pack-(SHA-).idx | sort -k -n | tail -
# 前面用过了git verify-pack,可知第三列信息表示的文件大小,这里用tail取前5个较大文件的记录
git rev-list --objects --all | grep (SHA-)
# 使用 git rev-list --objects -all 来查看指定 (SHA-1) 对象信息
# ce1fed3fdbaf12e816e3028055f9feee57b33b45 xxx.mp4 比如是个视频文件
git log --pretty=oneline --branches -- xxx.mp4
# 找出哪些 commit 修改/操作了这个文件
# 94cbe08e... add xxx.mp4
git filter-branch --index-filter 'git rm --cached --ignore-unmatch xxx.mp4' -- 94cbe08e^..
# 删除文件引用,rewrite 信息...
rm -rf .git/refs/original
rm -rf .git/logs/
git gc
# 删除 .git/refs/original 和 .git/logs/ ,处理其中对xxx.mp4文件仍存在的引用,之后repack仓库
git count-objects -v
# 检查下操作后文件大小,或者直接在.git目录下执行 du -h -d 1 查看1级目录/文件的大小
3.若还是难处理,或者不好处理,或者不想删除大文件的引用,则备份一份.git,然后初始化git仓库,操作如下
# 除去备份操作,备份操作使用者自定义
rm -rf .git
git init
git remote add origin xxx.git
# 重新指向新的远程仓库地址,也可根据上文所说修改config文件来指定
关于git hooks,参考Customizing-Git-Git-Hooks
关于更详细的.git文件夹,参考 Gitrepository-layout-objectsinfo
如果非得了解下git系统... - 实践篇的更多相关文章
- Git_Windows 系统下Git安装图解
Windows 系统下Git安装图解 心得 :很成功~ 简单来说Git是一个免费的.开源的版本控制软件,从功能上讲,跟我们比较熟悉的Subversion(SVN)这类版本控制软件没什么两样.由于工 ...
- 转:Git_Windows 系统下Git安装图解
原文地址:http://blog.csdn.net/jiguanghoverli/article/details/7902791 Windows 系统下Git安装图解 简单来说Git是一个免费的.开源 ...
- windows 系统下git 的使用
前言: 最新版本的git for windows也是有界面的,不再是以前的纯命令行操作,但是我习惯了乌龟,所以感觉还是直接用乌龟比较方便点~~ 前提,已安装以下: git for windows,未安 ...
- windows 系统下git 的安装
在linux系统下,可以直接在命令窗口安装和使用git.但是,在windows系统下,想要达到同样的效果,可以安装git,使用git bash到达效果.具体安装步骤如下: 第一步:官网上下载git 网 ...
- 安全防范:nginx下git引发的隐私泄露问题
安全防范:nginx下git引发的隐私泄露问题 1 安全事件 最近阿里云服务器后台管理系统中收到一条安全提示消息,系统配置信息泄露: http://my.domain.com/.git/confi ...
- Ubuntu下git的安装与使用
Ubuntu下git的安装与使用 Ubuntu下git的安装与使用与Windows下的大致相同,只不过个人感觉在Ubuntu下使用git更方便. 首先,确认你的系统是否已安装git,可以通过git指令 ...
- 聊下git pull --rebase
有一种场景是经常发生的. 大家都基于develop拉出分支进行并行开发,这里的分支可能是多到数十个.然后彼此在进行自己的逻辑编写,时间可能需要几天或者几周.在这期间你可能需要时不时的需要pull下远程 ...
- linux下git的简单运用
linux下git的简单运用 windows下也有git,是git公司出的bash,基本上模拟了linux下命令行.许多常用的命令和linux下操作一样.也就是说,windows下的git命令操作和l ...
- linux下git的安装和使用(转)
转自:http://www.cnblogs.com/sunada2005/archive/2013/06/06/3121098.html 最近在使用github,感觉不错.在windows下,可使用g ...
随机推荐
- JSTL安装与使用
第一步:下载支持JSTL的文件.jakarta-taglibs-standard-1.1.2.zip 第二步:下载解压后的两个jar文件:standard.jar和jstl.jar文件拷贝到工程的\W ...
- DC画线
CClientDC hdc(this);//获取DC CPen pen(PS_SOLID,4,RGB(255,0,0));//创建一支红笔 CPen * pOldPen=hdc.SelectObjec ...
- Ng第二课:单变量线性回归(Linear Regression with One Variable)
二.单变量线性回归(Linear Regression with One Variable) 2.1 模型表示 2.2 代价函数 2.3 代价函数的直观理解 2.4 梯度下降 2.5 梯度下 ...
- css设置自适应屏幕高度
<style type="text/css"> body,html{ margin:0; height:100%; /*这里将高度设置为100%是这个布局实现自适应高度 ...
- 【repost】JavaScript运动框架之速度时间版本
一.JavaScript运动框架之速度版 1.1 运动框架的实现思路 运动,其实就是在一段时间内改变 left . right . width . height . opactiy 的值,到达目的地之 ...
- android TextView 设置部分文字背景色和文字颜色
通过SpannableStringBuilder来实现,它就像html里边的元素改变指定文字的文字颜色或背景色 public class MainActivity extends Activity { ...
- android:theme
附件:常用的系统提供的 android:theme 样式一览表 01 android:theme="@android:style/Theme.Dialog" 将一个Activity ...
- ubuntu 修改mysql 5.7数据库密码
1.vi /ect/mysql/debian 查看debain-sys-maint用户的密码 2.登录mysql 4.切换到mysql数据库,更新 user 表: update user set au ...
- [C# 面试总结]9个点如何画10条线
问题描述 9个点画10条直线,要求每条直线上至少3个点,相信这道理题目很多朋友在面试的时候都遇到过的(同时自己在面试的时候也遇到过),所以这里记录下来以备复习. 解决方法1:
- Windows8.1 安装SQL Server2012——部分组件安装不成功!(提示安装.NET 3.5时出错,无Internet情况下利用win8.1安装镜像安装.NET 3.5)
虽然从事着与开发毫无关系的工作,但却也断断续续维持了近6年的WEB开发,有时因为其它工作原因,可能每做一个项目的时间间隔比较大,有时甚至在做的一个项目因为其他事情而停滞几个月之久(有些项目是自己兴趣或 ...