0
点赞
收藏
分享

微信扫一扫

Git汇总--对象及版本库存储


下述内容为团队内部分享整理所得,实用性较强,整体性偏差!
PS:关于完整的Git内容,请参照之前发表过一系列文章,详见:​​Git Pro深入浅出(一)​​、​​Git Pro深入浅出(二)​​、​​Git Pro深入浅出(三)​​ 推荐两个地址:​​ProGit​​、​​GotGit​​

阅读完内容,你会很快的解决下面问题,并了解其底层原理。

问题1:如何丢弃本地工作区修改的内容?

$ git checkout -- <filename>

问题2:如何丢弃本地工作区和暂存区修改的内容?

$ git checkout HEAD <filename>

问题3:误删了文件且已经提交推送到远程仓库,如何恢复?

# 查看远程前一次提交的文件树 支持管道过滤 | grep <filename>
$ git ls-files --with-tree=origin/HEAD^
# 查看前一次提交的指定文件内容 > welcome.txt
$ git cat-file -p origin/HEAD^:<filename>
# 当然,也可以采用reflog形式

问题4:如何忽略某文件?如何只让其本地生效?

​.git/info/exclude​​中配置

简介

Git作者Linus Torvalds,其是一款分布式版本控制系统。

  • CVS:集中式版本控制系统。CVS采用客户端/服务器架构设计,版本库位于服务器端,实际上就是一个RCS文件容器。每一个RCS文件以“​​.v​​”作为文件名后缀,用于保存对应文件的历次更改历史。RCS文件中只保留一个版本的完全拷贝,其他历次更改仅将差异存储其中,使得存储变得更加高效。每个文件都拥有各自独立的版本号。
  • SVN:集中式版本控制系统。拥有全局版本号,每提交一次,SVN的版本号就会自动加一。利用轻量级拷贝,SVN在不同的名字空间下创建不同的目录实现里程碑和分支的创建,轻松地解决了CVS中存在的里程碑、分支创建速度慢又不可见的问题。SVN还有一个突破,就是在工作区跟踪目录(​​.svn​​​目录)下为当前目录中的每一个文件都保存一份冗余的原始拷贝(工作区的根目录和每一个子目录下都有一个​​.svn​​目录)。这样做的好处一个是提高了网络的效率,在提交时仅传输变更差异,另外一个好处是部分操作不再需要网络连接,如本地修改的差异比较,以及本地更改的回退等。
  • Git:分布式版本控制系统。每个人都拥有一个完整的版本库。分布式版本控制系统的几乎所有操作包括查看提交日志、提交、创建里程碑和分支、合并分支、回退等都直接在本地完成而不需要网络连接。协同工作模型(版本库间推送、拉回,及补丁文件传送等)让开源项目的参与度有爆发式增长。

Git汇总--对象及版本库存储_.git

Git对象

​git init​​​ 会创建一个 ​​.git​​ 目录。这个目录包含了几乎所有 Git 存储和操作的对象。 如若想备份或复制一个版本库,只需把这个目录拷贝至另一处即可。

$ ll .git
-rw-r--r-- 1 ligang staff 6B 11 1 10:13 COMMIT_EDITMSG
-rw-r--r-- 1 ligang staff 212B 10 31 10:02 FETCH_HEAD
-rw-r--r-- 1 ligang staff 23B 8 21 15:23 HEAD
-rw-r--r-- 1 ligang staff 41B 10 31 10:02 ORIG_HEAD
drwxr-xr-x 2 ligang staff 64B 8 15 2017 branches
-rw-r--r-- 1 ligang staff 311B 8 15 2017 config
-rw-r--r-- 1 ligang staff 73B 8 15 2017 description
drwxr-xr-x 31 ligang staff 992B 5 10 14:44 hooks
-rw-r--r-- 1 ligang staff 6.9M 11 1 10:13 index
drwxr-xr-x 4 ligang staff 128B 5 9 16:11 info
drwxr-xr-x 4 ligang staff 128B 5 9 16:11 logs
drwxr-xr-x 152 ligang staff 4.8K 11 1 10:13 objects
-rw-r--r-- 1 ligang staff 166B 5 9 16:11 packed-refs
drwxr-xr-x 6 ligang staff 192B 7 3 09:53 refs

-rw-r–r--:第一位用于标识文件类型,d表示目录、l表示连结文件、-表示文件;其他表示系统用户权限rw-rw-(Owner)r–(Group)r–(Other)【r可读、w可写、x可执行】

版本库位于工作区根目录下的​​.git​​目录中,且仅此一处,在工作区的子目录下则没有任何其他跟踪文件或目录。Git的这种设计,将版本库放在工作区根目录下,所有的版本控制操作(除了和其他远程版本库之间的互操作)都在本地即可完成。

$ git log -1 --pretty=raw
# 本次提交的唯一标识
commit b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
# 本次提交所对应的目录树
tree 1e0c5cb85e1d2b4ff6875a5bbaa9183389ace668
# 本地提交的父提交(上一次提交)
parent 3365948518aad171336a52674cbdf0450679b4dc
author ligang <381510688@qq.com> 1543761152 +0800
committer ligang <381510688@qq.com> 1543761152 +0800

feat(git): git 汇总

研究Git对象ID的一个重量级武器就是​​git cat-file​​命令。

查看一下这三个ID的类型:

$ git cat-file -t b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
commit
$ git cat-file -t 1e0c5cb85e1d2b4ff6875a5bbaa9183389ace668
tree
$ git cat-file -t 3365948518aad171336a52674cbdf0450679b4dc
commit

查看对象的内容:

$ git cat-file -p <commitID>

Git 有一个底层命令​​git rev-parse​​ 可以用于显示引用对应的提交ID

$ git rev-parse master
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
$ git rev-parse refs/heads/master
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
$ git rev-parse HEAD
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259

可以看出它们都指向同一个对象!

Git汇总--对象及版本库存储_.git_02

  • 显示版本库​​.git​​ 目录所在的位置

$ git rev-parse --git-dir
/Users/ligang/Documents/github/practice/.git

  • 显示工作区根目录

$ git rev-parse --show-toplevel
/Users/ligang/Documents/github/practice

​git rev-parse​​ 是Git的一个底层命令,其功能非常丰富(或者说杂乱),很多Git脚本或工具都会用到这条命令。

  • 显示分支 ​​$ git rev-parse --symbolic --branches​
  • 显示tags ​​$ git rev-parse --symbolic --tags​
  • 显示HEAD对应的SHA1哈希值 ​​$ git rev-parse HEAD​

版本库存储

本地(工作区、暂存区、HEAD)

Git汇总--对象及版本库存储_工作区、暂存区、HEAD_03

说明

工作区

Git暂存区(stage,或称为index)

HEAD(当前分支,注意非远程

  • HEAD实际是指向master分支的一个“游标”,HEAD全部可以使用master替换
  • objects为Git的对象库,位于 ​​.git/objects​​ 目录下;
  • 工作区 <==> 暂存区

命令

说明

​git add ./<filename>​

将工作区变更提交到暂存区

​git checkout ./<filename>​

​git checkout -- <filename>​

暂存区内容覆盖工作区

​git rm --cached <file>​

直接从暂存区删除文件,工作区则不做出改变

  • 暂存区 <==> HEAD

命令

说明

​git commit -s -m ""​

将暂存区提交到master分支

(即master指向的目录树就是原暂存区的目录树)

​git reset HEAD ./<filename>​

使用master指向的目录树替换缓存区

​git checkout HEAD ./<filename>​

用HEAD指向的master分支内容替换暂存区及工作区的文件

重点来了! 如何还原本地工作区某文件

$ git reset HEAD <filename>
$ git checkout <filename>

# 替换命令
$ git checkout HEAD <filename>

本地(stash)

​git stash​​ 保存当前工作进度,会分别对暂存区和工作区的状态进行保存。

$ git stash [save [–patch] [-k|–[no-]keep-index] [-q|–quiet] [<message>]]

  • ​save "message..."​​ 保存工作进度时使用指定说明
  • ​--patch​​ 会显示工作区和HEAD的差异,通过对差异文件的编辑决定在进度中最终要保存的工作区的内容
  • ​-k​​​或者​​--keep-index​​参数,在保存进度后不会将暂存区重置。缺省会将暂存区和工作区强制重置!

注意: 本地没有被版本控制系统跟踪的文件并不能保存进度,即新创建文件需要 ​​git add​​。

恢复工作进度,可以通过下述命令:

$ git stash apply [–index] [<stash>]
$ git stash drop [<stash>]
# 等价于上述两条命令
$ git stash pop [–index] [<stash>]

远程(remote)

$ cd .git/refs/remotes
$ ll
drwxr-xr-x 5 ligang staff 160B 11 28 10:42 origin
drwxr-xr-x 11 ligang staff 352B 11 27 00:11 upstream
$ ll origin
-rw-r--r-- 1 ligang staff 32B 11 8 09:43 HEAD
-rw-r--r-- 1 ligang staff 41B 11 28 10:42 feature-v2.1
-rw-r--r-- 1 ligang staff 41B 11 28 10:42 master
$ ll upstream
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 develop
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 master
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 themes
$ cat origin/develop
eeaa2013d901bda74eaa9fe102abe1e474b7a5d6
$ git ls-tree eeaa2013d901bda74eaa9fe102abe1e474b7a5d6

Git 这样的设计是非常巧妙的,在向远程版本库执行获取操作时,不是把远程版本库的分支原封不动地复制到本地版本库的分支中,而是复制到其命名空间中。如在克隆一个版本库时,会将远程分支都复制到目录 ​​.git/refs/remotes/origin/​​ 下。这样向不同的远程版本库执行获取操作,因为远程分支相互隔离,所以就避免了相互的覆盖。

  • 添加新远程版本库

$ git remote add remote-name git@x.x.x.x:project-namespace/project-name.git
$ git remote -v

未完,请继续阅读 ​​Git汇总–版本库操作​​


举报

相关推荐

0 条评论